スキーマ設計ハンズオン
検索としても知られる情報検索(IR)システムは、検索支援生成(RAG)、画像検索、商品推薦など、さまざまなAIアプリケーションに不可欠です。IRシステム開発の最初のステップはデータモデルの設計であり、これにはビジネス要件の分析、情報の整理方法の決定、データを意味的に検索可能にするためのインデックス作成が含まれます。
Milvusはコレクションスキーマを通してデータモデルの定義をサポートします。コレクションは、テキストや画像のような非構造化データを、セマンティック検索に使用される様々な精度の密なベクトルや疎なベクトルを含むベクトル表現とともに整理します。さらに、Milvusは "スカラー "と呼ばれる非ベクトルデータ型の保存とフィルタリングをサポートしています。スカラー型にはBOOL、INT8/16/32/64、FLOAT/DOUBLE、VARCHAR、JSON、Arrayが含まれます。
ニュース記事を検索するために設計されたデータ・スキーマの例
検索システムのデータモデル設計には、ビジネスニーズを分析し、情報をスキーマで表現されたデータモデルに抽象化することが含まれる。例えば、テキストを検索するためには、リテラル文字列を「埋め込み」によってベクトルに変換し、ベクトル検索を可能にすることで「インデックス化」しなければならない。この基本要件以外にも、出版タイムスタンプや著者などのプロパティを格納する必要があるかもしれない。このメタデータによって、フィルタリングによってセマンティック検索を絞り込み、特定の日付以降に出版されたテキストや特定の著者によるテキストだけを返すことができる。また、アプリケーションで検索結果をレンダリングするために、メインテキストと一緒に検索する必要がある場合もある。これらのテキスト片を整理するために、それぞれに整数または文字列で表される一意の識別子を割り当てる必要がある。これらの要素は洗練された検索ロジックを実現するために不可欠です。
よく設計されたスキーマはデータモデルを抽象化し、検索によってビジネス目標を達成できるかどうかを決定するため重要です。さらに、コレクションに挿入されるすべてのデータ行はスキーマに従う必要があるため、データの一貫性と長期的な品質の維持に大いに役立ちます。技術的な観点からは、よく定義されたスキーマは、よく整理されたカラム・データ・ストレージとすっきりとしたインデックス構造につながり、検索パフォーマンスを高めることができる。
例ニュース検索
例えば、あるニュースサイトの検索を構築し、テキスト、サムネイル画像、その他のメタデータを含むニュースのコーパスがあるとしよう。まず、検索というビジネス要件をサポートするために、データをどのように活用したいかを分析する必要がある。例えば、サムネイル画像と内容の要約に基づいてニュースを検索し、著者情報や公開時間などのメタデータを条件として検索結果をフィルタリングする、というような要件があるとします。これらの要件は、さらに次のように分解できる。
テキストから画像を検索するために、テキストと画像データを同じ潜在空間にマッピングできるマルチモーダル埋め込みモデルによって、画像をベクトルに埋め込むことができる。
記事の要約テキストは、テキスト埋め込みモデルによってベクトルに埋め込まれる。
公開時間に基づいてフィルタリングするために、日付はスカラーフィールドとして格納され、効率的なフィルタリングのためにスカラーフィールドのインデックスが必要である。JSONのような、より複雑なデータ構造をスカラーに格納し、その内容からフィルタリング検索を実行することもできる(JSONのインデックス化は今後の機能)。
画像のサムネイルバイトを取得して検索結果ページにレンダリングするために、画像のURLも格納される。同様に、要約テキストとタイトルについても同様です。(必要に応じて、生のテキストと画像ファイルのデータをスカラーフィールドとして格納することもできます)。
要約テキストでの検索結果を改善するために、ハイブリッド検索アプローチを設計する。一つの検索パスに対して、OpenAIの
text-embedding-3-large
やオープンソースのbge-large-en-v1.5
のような、テキストから密なベクトルを生成する通常の埋め込みモデルを使用する。これらのモデルはテキストの全体的な意味を表現するのに適している。もう1つの方法は、BM25やSPLADEのようなスパース埋め込みモデルを使用してスパースベクトルを生成することである。Milvusは、マルチベクトル機能により、同じデータコレクションで両方を使用することをサポートしています。複数のベクトルに対する検索は、単一のhybrid_search()
操作で行うことができる。最後に、Milvusの用語では正式には「エンティティ」と呼ばれる、個々のニュースページを識別するためのIDフィールドも必要である。このフィールドは主キー(略して "pk")として使用される。
フィールド名 | article_id (主キー) | タイトル | 著者情報 | パブリッシュ | 画像URL | 画像ベクトル | 要約 | 要約_デンスベクトル | 要約_疎ベクトル |
---|---|---|---|---|---|---|---|---|---|
型 | INT64 | VARCHAR | JSON | INT32 | VARCHAR | FLOAT_VECTOR | VARCHAR | FLOAT_VECTOR | スパース・フロート・ベクトル |
インデックスが必要 | N | N | N (近日サポート開始) | Y | N | Y | N | Y | Y |
スキーマ例の実装方法
スキーマの作成
まず、Milvusサーバに接続し、コレクションとデータを管理するためのMilvusクライアントインスタンスを作成します。
スキーマをセットアップするために create_schema()
を使用してスキーマオブジェクトを作成し add_field()
を使用してスキーマにフィールドを追加します。
from pymilvus import MilvusClient, DataType
collection_name = "my_collection"
# client = MilvusClient(uri="http://localhost:19530")
client = MilvusClient(uri="./milvus_demo.db")
schema = MilvusClient.create_schema(
auto_id=False,
)
schema.add_field(field_name="article_id", datatype=DataType.INT64, is_primary=True, description="article id")
schema.add_field(field_name="title", datatype=DataType.VARCHAR, max_length=200, description="article title")
schema.add_field(field_name="author_info", datatype=DataType.JSON, description="author information")
schema.add_field(field_name="publish_ts", datatype=DataType.INT32, description="publish timestamp")
schema.add_field(field_name="image_url", datatype=DataType.VARCHAR, max_length=500, description="image URL")
schema.add_field(field_name="image_vector", datatype=DataType.FLOAT_VECTOR, dim=768, description="image vector")
schema.add_field(field_name="summary", datatype=DataType.VARCHAR, max_length=1000, description="article summary")
schema.add_field(field_name="summary_dense_vector", datatype=DataType.FLOAT_VECTOR, dim=768, description="summary dense vector")
schema.add_field(field_name="summary_sparse_vector", datatype=DataType.SPARSE_FLOAT_VECTOR, description="summary sparse vector")
Milvus サーバに接続するためにMilvusClient
の引数uri
にお気づきでしょうか。引数は以下のように設定できます。
小規模なデータやプロトタイプを作成するためにローカルのベクターデータベースが必要なだけであれば、uri をローカルファイル、例えば
./milvus.db
に設定するのが最も便利な方法です。もし、100万ベクトルを超えるような大規模なデータがある場合は、DockerやKubernetes上に、よりパフォーマンスの高いMilvusサーバを構築することができます。このセットアップでは、サーバのアドレスとポートをURIとして使用してください(例:
http://localhost:19530
)。Milvusで認証機能を有効にしている場合、トークンには"<your_username>:<your_password>"を使用します。MilvusのフルマネージドクラウドサービスであるZilliz Cloudをご利用の場合は、Zilliz CloudのPublic EndpointとAPI keyに対応する
uri
とtoken
を調整してください。
MilvusClient.create_schema
のauto_id
については、AutoID はプライマリフィールドの属性で、プライマリフィールドのオートインクリメントを有効にするかどうかを決定します。 フィールドarticle_id
を主キーとして設定し、記事 ID を手動で追加したいので、この機能を無効にするためにauto_id
を False に設定します。
スキーマオブジェクトにすべてのフィールドを追加した後、スキーマオブジェクトは上の表のエントリと一致します。
インデックスの定義
メタデータや画像や要約データのためのベクター・フィールドを含む様々なフィールドでスキーマを定義した後、次のステップではインデックス・パラメーターを準備します。インデックスの作成は、ベクターの検索と取得を最適化し、効率的なクエリ・パフォーマンスを確保するために非常に重要です。次のセクションでは、コレクション内の指定されたベクトルフィールドとスカラーフィールドのインデックスパラ メータを定義します。
index_params = client.prepare_index_params()
index_params.add_index(
field_name="image_vector",
index_type="AUTOINDEX",
metric_type="IP",
)
index_params.add_index(
field_name="summary_dense_vector",
index_type="AUTOINDEX",
metric_type="IP",
)
index_params.add_index(
field_name="summary_sparse_vector",
index_type="SPARSE_INVERTED_INDEX",
metric_type="IP",
)
index_params.add_index(
field_name="publish_ts",
index_type="INVERTED",
)
インデックスパラメータが設定され適用されると、Milvusはベクトルおよびスカラーデータに対する複雑なクエリを処理するために最適化されます。このインデックス作成により、コレクション内の類似検索の性能と精度が向上し、画像ベクトルや要約ベクトルに基づく記事の効率的な検索が可能になる。密なベクトルに対する AUTOINDEX
を活用することで SPARSE_INVERTED_INDEX
疎ベクトルには INVERTED_INDEX
forスカラーを活用することで、Milvusは最も関連性の高い結果を素早く識別して返すことができ、全体的なユーザーエクスペリエンスとデータ検索プロセスの有効性を大幅に向上させることができる。
インデックスとメトリックには多くの種類があります。これらの詳細については、MilvusインデックスタイプとMilvusメトリックタイプを参照してください。
コレクションの作成
スキーマとインデックスが定義されたので、これらのパラメータで "コレクション "を作成します。MilvusにとってのコレクションはリレーショナルDBにとってのテーブルのようなものです。
client.create_collection(
collection_name=collection_name,
schema=schema,
index_params=index_params,
)
コレクションを記述することで、コレクションが正常に作成されたことを確認できます。
collection_desc = client.describe_collection(
collection_name=collection_name
)
print(collection_desc)
その他の検討事項
インデックスの読み込み
Milvusでコレクションを作成する際、インデックスのロードを即座に行うか、いくつかのデータを一括インジェストした後まで延期するかを選択することができます。上記の例では、コレクション作成直後に取り込まれたデータに対してインデックスが自動的に構築されるため、通常、明示的に選択する必要はありません。これにより、取り込まれたデータをすぐに検索できるようになります。しかし、コレクション作成後に大量の一括挿入があり、ある時点までデータを検索する必要がない場合は、コレクション作成でindex_paramsを省略することでインデックス構築を延期し、すべてのデータを取り込んだ後に明示的にloadを呼び出すことでインデックスを構築できます。この方法は、大きなコレクションにインデックスを構築する場合に効率的ですが、load() を呼び出すまで検索はできません。
マルチテナントのデータモデルの定義方法
複数のテナントという概念は、1つのソフトウェア・アプリケーションやサービスが、それぞれ独立した環境を持つ複数のユーザーや組織にサービスを提供する必要がある場合によく使われる。これは、クラウドコンピューティング、SaaS(Software as a Service)アプリケーション、データベースシステムで頻繁に見られます。例えば、クラウドストレージサービスでは、マルチテナントを利用することで、同じインフラを共有しながら、異なる企業が別々にデータを保存・管理できるようにすることができる。このアプローチは、各テナントのデータ・セキュリティとプライバシーを確保しながら、リソースの利用と効率を最大化する。
テナントを区別する最も簡単な方法は、データとリソースを互いに分離することです。各テナントは特定のリソースに排他的にアクセスするか、他のテナントとリソースを共有してデータベース、コレクション、パーティションなどのMilvusエンティティを管理します。Milvusのマルチテナントを実装するには、これらのエンティティに沿った特定の方法があります。詳細はMilvusマルチテナンシーページをご参照ください。