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

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

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

Qx7UwgI6jhrku8bAxZqcYxZMnSe

マルチベクトルハイブリッド検索は、異なる検索方法を統合するか、さまざまなモダリティからの埋め込みを横断します:

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

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

例​

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

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

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

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

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

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

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

スキーマを定義する​

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

この例では、次のフィールドをスキーマに組み込みます:

  • 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 アルゴリズムを使用するため、Milvus の Function をスキーマに追加する必要があります。詳細については、全文検索 を参照してください。

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: テキストの密ベクトルフィールドに対して、AUTOINDEX タイプの IP メトリックタイプのインデックスが作成されます。

  • text_sparse_index: テキストの疎ベクトルフィールドには、SPARSE_INVERTED_INDEX タイプの BM25 メトリックタイプのインデックスが使用されます。

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

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"
)

コレクションを作成する​

前の 2 つのステップで構成したコレクションスキーマとインデックスを使用して、demo という名前のコレクションを作成します。

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

データを挿入する​

このセクションでは、先に定義したスキーマに基づいて、my_collection コレクションにデータを挿入します。挿入時には、自動生成される値を除くすべてのフィールドに、正しい形式でデータが指定されていることを確認してください。この例では:

  • id: 商品 ID を表す整数

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

  • text_dense: テキスト説明の密埋め込みを表す、768 個の浮動小数点値のリスト

  • image_dense: 商品画像の密埋め込みを表す、512 個の浮動小数点値のリスト

各フィールドの密埋め込みを生成するには、同じモデルまたは異なるモデルを使用できます。この例では、2つの密埋め込みの次元が異なるため、異なるモデルによって生成されたことを示唆しています。後で各検索を定義するときは、対応するモデルを使用して適切なクエリ埋め込みを生成してください。

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

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 インスタンスを作成する​

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

さらに、expr パラメーターを AnnSearchRequest に構成することで、ハイブリッド検索のフィルタリング条件を設定できます。フィルタリング検索 および フィルタリングの説明 を参照してください。

Notes

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

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

  • text_dense: セマンティックテキスト検索用。直接的なキーワードマッチングではなく、意味に基づく文脈理解と取得を可能にします。

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

  • image_dense: マルチモーダルなテキストから画像への検索用。クエリのセマンティックコンテンツに基づいて関連する商品画像を取得します。

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",
"param": {},
"limit": 2
}
request_1 = AnnSearchRequest(**search_param_1)

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

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

reqs = [request_1, request_2, request_3]

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

ステップ 2:リランキング戦略を構成する​

ANN 検索結果のセットをマージしてリランキングするには、適切なリランキング戦略を選択することが不可欠です。Zilliz Cloud は、いくつかのタイプのリランキング戦略を提供しています。これらのリランキングメカニズムの詳細については、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
}
)

ハイブリッド検索を開始する前に、コレクションがロードされていることを確認してください。コレクション内のベクトルフィールドにインデックスがない場合、またはメモリにロードされていない場合、ハイブリッド検索メソッドの実行時にエラーが発生します。

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)

出力は次のとおりです:

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

ハイブリッド検索に limit=2 パラメーターを指定すると、Zilliz Cloud は 3つの検索から得られた 6つの結果をリランキングします。最終的に、最も類似した上位 2つの結果のみが返されます。