メインコンテンツまでスキップ

マルチベクトルハイブリッド検索

多くのアプリケーションでは、タイトルや説明のような豊富な情報セット、またはテキスト、画像、音声のような複数のモダリティによってオブジェクトを検索できます。たとえば、テキストと画像を含むツイートは、テキストまたは画像のいずれかが検索クエリの意味に一致すれば検索されるべきです。ハイブリッド検索は、これらの多様なフィールドにまたがる検索を組み合わせることで検索体験を向上させます。Zilliz Cloud は、複数のベクトルフィールドでの検索を可能にし、複数の近似最近傍(Approximate Nearest Neighbor、ANN)検索を同時に実行することでこれをサポートします。マルチベクトルハイブリッド検索は、テキストと画像の両方を検索したい場合、同じオブジェクトを説明する複数のテキストフィールドを検索したい場合、または密ベクトルと疎ベクトルを使って検索品質を向上させたい場合に特に有用です。

Qx7UwgI6jhrku8bAxZqcYxZMnSe

マルチベクトルハイブリッド検索は、異なる検索手法を統合したり、さまざまなモダリティにまたがる埋め込みを扱ったりします。

  • 疎密ベクトル検索: Dense Vector は意味的関係の把握に優れており、一方で Sparse Vector は正確なキーワードマッチングに非常に効果的です。ハイブリッド検索はこれらのアプローチを組み合わせることで、広い概念的理解と正確な用語の関連性の両方を提供し、検索結果を改善します。各手法の強みを活用することで、ハイブリッド検索は個別アプローチの限界を克服し、複雑なクエリに対してより優れた性能を提供します。セマンティック検索と全文検索を組み合わせたハイブリッド検索の詳細なガイドはこちらです。

  • マルチモーダルベクトル検索: マルチモーダルベクトル検索は、テキスト、画像、音声などのさまざまなデータ型をまたいで検索できる強力な手法です。このアプローチの主な利点は、異なるモダリティを統合し、シームレスで一貫性のある検索体験を実現できることです。たとえば商品検索では、ユーザーがテキストと画像の両方で記述された商品を見つけるためにテキストクエリを入力することがあります。これらのモダリティをハイブリッド検索手法で組み合わせることで、検索精度を高めたり、検索結果をより豊かにしたりできます。

各商品がテキスト説明と画像を含む実際のユースケースを考えてみましょう。利用可能なデータに基づいて、次の 3 種類の検索を実行できます。

  • セマンティックテキスト検索: これは密ベクトルを使用して商品のテキスト説明をクエリする方法です。テキスト埋め込みは、BERTTransformers のようなモデル、または OpenAI のようなサービスを使って生成できます。

  • 全文検索: ここでは疎ベクトルによるキーワードマッチを使って商品のテキスト説明をクエリします。この目的には、BM25 のようなアルゴリズムや、BGE-M3SPLADE のような疎埋め込みモデルを利用できます。

  • マルチモーダル画像検索: この方法では、密ベクトルを使用してテキストクエリで画像に対してクエリを行います。画像埋め込みは CLIP のようなモデルで生成できます。

このガイドでは、商品の生のテキスト説明と画像埋め込みが与えられているとして、上記の検索手法を組み合わせたマルチモーダルハイブリッド検索の例を説明します。マルチベクトルデータを保存し、再ランキング戦略を用いてハイブリッド検索を実行する方法を示します。

複数のベクトルフィールドを持つコレクションを作成する

コレクションを作成するプロセスは、コレクションスキーマの定義、インデックスパラメータの設定、コレクションの作成という 3 つの重要なステップで構成されます。

スキーマを定義する

マルチベクトルハイブリッド検索では、コレクションスキーマ内に複数のベクトルフィールドを定義する必要があります。コレクションで許可されるベクトルフィールド数の制限については、Zilliz Cloud Limits を参照してください。

この例では、スキーマに以下のフィールドを含めます。

  • id: テキスト ID を格納するための主キーとして機能します。このフィールドのデータ型は INT64 です。

  • text: テキストコンテンツの格納に使用します。このフィールドのデータ型は VARCHAR で、最大長は 1000 バイトです。全文検索を容易にするため、enable_analyzer オプションは True に設定されています。

  • text_dense: テキストの密ベクトルを格納するために使用します。このフィールドのデータ型は FLOAT_VECTOR で、ベクトル次元は 768 です。

  • text_sparse: テキストの疎ベクトルを格納するために使用します。このフィールドのデータ型は SPARSE_FLOAT_VECTOR です。

  • image_dense: 商品画像の密ベクトルを格納するために使用します。このフィールドのデータ型は FLOAT_VETOR で、ベクトル次元は 512 です。

組み込みの BM25 アルゴリズムを使用して text フィールドに対する全文検索を実行するため、スキーマに Milvus Function を追加する必要があります。詳細については、Full Text Search を参照してください。

python
from pymilvus import (
MilvusClient, DataType, Function, FunctionType
)

client = MilvusClient(
uri="YOUR_CLUSTER_ENDPOINT",
token="YOUR_CLUSTER_TOKEN"
)

# Init schema with auto_id disabled
schema = client.create_schema(auto_id=False)

# Add fields to schema
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, description="product id")
schema.add_field(field_name="text", datatype=DataType.VARCHAR, max_length=1000, enable_analyzer=True, description="raw text of product description")
schema.add_field(field_name="text_dense", datatype=DataType.FLOAT_VECTOR, dim=768, description="text dense embedding")
schema.add_field(field_name="text_sparse", datatype=DataType.SPARSE_FLOAT_VECTOR, description="text sparse embedding auto-generated by the built-in BM25 function")
schema.add_field(field_name="image_dense", datatype=DataType.FLOAT_VECTOR, dim=512, description="image dense embedding")

# Add function to schema
bm25_function = Function(
name="text_bm25_emb",
input_field_names=["text"],
output_field_names=["text_sparse"],
function_type=FunctionType.BM25,
)
schema.add_function(bm25_function)

インデックスを作成する

コレクションスキーマを定義した後の次のステップは、ベクトルインデックスを設定し、類似度メトリックを指定することです。与えられた例では次のようになります。

  • text_dense_index: テキスト密ベクトルフィールドに対して、IP メトリックタイプを持つ AUTOINDEX 型のインデックスを作成します。

  • text_sparse_index: テキスト疎ベクトルフィールドに対して、BM25 メトリックタイプを持つ SPARSE_INVERTED_INDEX 型のインデックスを使用します。

  • image_dense_index: 画像密ベクトルフィールドに対して、IP メトリックタイプを持つ AUTOINDEX 型のインデックスを作成します。

python
# Prepare index parameters
index_params = client.prepare_index_params()

# Add indexes
index_params.add_index(
field_name="text_dense",
index_name="text_dense_index",
index_type="AUTOINDEX",
metric_type="IP"
)

index_params.add_index(
field_name="text_sparse",
index_name="text_sparse_index",
index_type="AUTOINDEX",
metric_type="BM25"
)

index_params.add_index(
field_name="image_dense",
index_name="image_dense_index",
index_type="AUTOINDEX",
metric_type="IP"
)

collection の作成

前の 2 つのステップで設定した collection schema と index を使用して、demo という名前の collection を作成します。

python
client.create_collection(
collection_name="my_collection",
schema=schema,
index_params=index_params
)

データの挿入

このセクションでは、先ほど定義した schema に基づいて my_collection collection にデータを挿入します。挿入時には、自動生成される値を持つフィールドを除き、すべてのフィールドに対して正しい形式のデータを指定してください。この例では以下のとおりです。

  • id: 製品 ID を表す整数

  • text: 製品説明を含む文字列

  • text_dense: テキスト説明の dense embedding を表す 768 個の浮動小数点値のリスト

  • image_dense: 製品画像の dense embedding を表す 512 個の浮動小数点値のリスト

各フィールドの dense embedding の生成には、同じモデルを使用しても異なるモデルを使用してもかまいません。この例では、2 つの dense embedding は次元数が異なっており、異なるモデルで生成されたことを示しています。後で各検索を定義する際には、対応するモデルを使用して適切なクエリ embedding を生成するようにしてください。

この例では、テキストフィールドから sparse embedding を生成するために組み込みの BM25 関数を使用しているため、sparse vector を手動で指定する必要はありません。ただし、BM25 を使用しない場合は、自分で sparse embedding を事前計算して指定する必要があります。

python
import random

# Generate example vectors
def generate_dense_vector(dim):
return [random.random() for _ in range(dim)]

data=[
{
"id": 0,
"text": "Red cotton t-shirt with round neck",
"text_dense": generate_dense_vector(768),
"image_dense": generate_dense_vector(512)
},
{
"id": 1,
"text": "Wireless noise-cancelling over-ear headphones",
"text_dense": generate_dense_vector(768),
"image_dense": generate_dense_vector(512)
},
{
"id": 2,
"text": "Stainless steel water bottle, 500ml",
"text_dense": generate_dense_vector(768),
"image_dense": generate_dense_vector(512)
}
]

res = client.insert(
collection_name="my_collection",
data=data
)

ステップ 1: 複数の AnnSearchRequest インスタンスを作成する

ハイブリッド検索は、hybrid_search() 関数内で複数の AnnSearchRequest を作成することで実装されます。各 AnnSearchRequest は、特定のベクトルフィールドに対する基本的な ANN 検索リクエストを表します。そのため、ハイブリッド検索を実行する前に、各ベクトルフィールドに対して AnnSearchRequest を作成する必要があります。

さらに、AnnSearchRequestexpr パラメータを設定することで、ハイブリッド検索のフィルタリング条件を指定できます。詳細については、Filtered Search および Filtering Explained を参照してください。

📘注意

ハイブリッド検索では、各 AnnSearchRequest は 1 つのクエリデータのみをサポートします。

さまざまな検索ベクトルフィールドの機能を示すために、サンプルクエリを使用して 3 つの AnnSearchRequest 検索リクエストを作成します。また、このプロセスでは事前計算済みの dense vector も使用します。検索リクエストの対象となるベクトルフィールドは次のとおりです。

  • text_dense: 意味に基づいて文脈を理解し、直接的なキーワード一致ではなく意味ベースで検索・取得を行うセマンティックテキスト検索用

  • text_sparse: テキスト内の単語やフレーズの正確な一致に焦点を当てる全文検索またはキーワード一致用

  • image_dense: クエリの意味内容に基づいて関連する製品画像を取得する、マルチモーダルな text-to-image 検索用

python
from pymilvus import AnnSearchRequest

query_text = "white headphones, quiet and comfortable"
query_dense_vector = generate_dense_vector(768)
query_multimodal_vector = generate_dense_vector(512)

# text semantic search (dense)
search_param_1 = {
"data": [query_dense_vector],
"anns_field": "text_dense",
"limit": 2
}
request_1 = AnnSearchRequest(**search_param_1)

# full-text search (sparse)
search_param_2 = {
"data": [query_text],
"anns_field": "text_sparse",
"limit": 2
}
request_2 = AnnSearchRequest(**search_param_2)

# text-to-image search (multimodal)
search_param_3 = {
"data": [query_multimodal_vector],
"anns_field": "image_dense",
"limit": 2
}
request_3 = AnnSearchRequest(**search_param_3)

reqs = [request_1, request_2, request_3]

limit パラメータが 2 に設定されているため、各 AnnSearchRequest は 2 件の検索結果を返します。この例では 3 つの AnnSearchRequest インスタンスが作成されるため、合計 6 件の検索結果になります。

ステップ 2: reranking 戦略を設定する

ANN 検索結果のセットをマージして rerank するには、適切な reranking 戦略を選択することが重要です。Zilliz Cloud は複数種類の reranking 戦略を提供しています。これらの reranking メカニズムの詳細については、Weighted Ranker または RRF Ranker を参照してください。

この例では、特定の検索クエリを特に重視しないため、RRFRanker 戦略を使用します。

python
ranker = Function(
name="rrf",
input_field_names=[], # Must be an empty list
function_type=FunctionType.RERANK,
params={
"reranker": "rrf",
"k": 100 # Optional
}
)

Hybrid Search を開始する前に、collection がロードされていることを確認してください。collection 内のいずれかの vector field に index がない場合、またはメモリにロードされていない場合は、Hybrid Search メソッドの実行時にエラーが発生します。

python
res = client.hybrid_search(
collection_name="my_collection",
reqs=reqs,
ranker=ranker,
limit=2
)
for hits in res:
print("TopK results:")
for hit in hits:
print(hit)

以下は出力例です。

python
["['id: 1, distance: 0.006047376897186041, entity: {}', 'id: 2, distance: 0.006422005593776703, entity: {}']"]

Hybrid Search で limit=2 パラメータを指定すると、Zilliz Cloud は 3 回の検索で得られた 6 件の結果を rerank します。最終的に、最も類似度の高い上位 2 件の結果のみが返されます。

Ctrl I