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

StructArray を使用したハイブリッド検索

このページでは、StructArray のベクトル検索と他のベクトル検索を 1 つのハイブリッド検索リクエストで組み合わせる方法について説明します。StructArray ハイブリッド検索では、組み合わせる AnnSearchRequest オブジェクトに応じて、エンティティレベルの結果またはエレメントレベルの結果を返すことができます。

このページでは、StructArray フィールドの作成 で作成した tech_articles コレクションを使用します。このコレクションには、title_vector というトップレベルのベクトルフィールドと、chunks という StructArray フィールドがあります。chunks[emb_list_vector] サブフィールドは EmbeddingList 検索用に、chunks[emb] はエレメントレベル検索用にインデックスが作成されています。

これらの例を実行する前に、コレクションを作成し、サンプルデータを挿入し、必要なベクトルインデックスを作成して、コレクションをロードしてください。ここに示すフィールドには、4 次元のベクトルを使用します。各コードブロックは、そのコードブロック内で改めて定義されていない限り、同じ言語の前の例で定義された接続と変数を使用することを前提としています。

StructArray におけるハイブリッド検索の適用方法​

AnnSearchRequest の組み合わせ最終候補スコープ結果の動作element_scope
コレクションレベルのベクトルフィールド + StructArray の EmbeddingList サブフィールドエンティティレベル最終候補はプライマリキーをキーとして管理されます。使用しません。
コレクションレベルのベクトルフィールド + StructArray のエレメントレベルサブフィールドエンティティレベルハイブリッドリランキングの前に、エレメントレベルのヒットがエンティティレベルの候補に折りたたまれます。StructArray のエレメントレベル AnnSearchRequest に対するオプションの折りたたみ設定。
同じ StructArray フィールド配下の複数のエレメントレベルサブフィールドエレメントレベル最終候補は、プライマリキーと Struct エレメントのオフセットをキーとして管理されます。使用しません。
異なる StructArray フィールド配下のエレメントレベルサブフィールドエンティティレベルエレメントオフセットは同一の識別情報を共有しないため、各 StructArray エレメントレベルの AnnSearchRequest はリランキングの前に折りたたまれます。各 StructArray エレメントレベル AnnSearchRequest に対するオプションの折りたたみ設定。
📘Notes

警告

element_scope は、同一 Struct でないエレメントレベルのハイブリッド検索において、StructArray エレメントレベルの AnnSearchRequest オブジェクトの折りたたみを構成する場合にのみ使用してください。EmbeddingList リクエスト、コレクションレベルのベクトルリクエスト、または同一 StructArray のエレメントレベルハイブリッド検索には使用しないでください。

事前準備​

ハイブリッド検索を実行する前に、コレクション、データ、インデックスを準備します。

要件詳細
StructArray フィールドコレクションに chunks などの StructArray フィールドが含まれています。
ベクトルサブフィールドEmbeddingList 検索とエレメントレベル検索には、別々のベクトルサブフィールドを使用します。
インデックスchunks[emb_list_vector] は MAX_SIM* メトリクスを使用します。chunks[emb] は COSINE、IP、L2 などの通常のベクトルメトリクスを使用します。
リランカーRRFRanker などのハイブリッドリランカー、またはアプリケーションでサポートされている別のリランカーを選択します。

インデックスの設定については、StructArray フィールドのインデックス作成 を参照してください。

EmbeddingList リクエストを使用したハイブリッド検索の実行​

StructArray のベクトルサブフィールドに対する EmbeddingList 検索は、ハイブリッド検索ではエンティティレベルです。これはエンティティレベルのベクトル検索リクエストと同様に動作し、一致した Struct エレメントのオフセットを 1 つ返すことはありません。

python
from pymilvus import AnnSearchRequest, MilvusClient, RRFRanker
from pymilvus.client.embedding_list import EmbeddingList

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

query_vector = [0.19, 0.24, 0.30, 0.37]

query_list = EmbeddingList()
query_list.add([0.12, 0.21, 0.32, 0.44])
query_list.add([0.18, 0.23, 0.29, 0.36])

title_req = AnnSearchRequest(
data=[query_vector],
anns_field="title_vector",
param={},
limit=10,
)

chunk_list_req = AnnSearchRequest(
data=[query_list],
anns_field="chunks[emb_list_vector]",
param={},
limit=10,
)

results = client.hybrid_search(
collection_name="tech_articles",
reqs=[title_req, chunk_list_req],
ranker=RRFRanker(),
limit=5,
output_fields=[
"doc_id",
"title",
"category",
"chunks[text]",
"chunks[section]",
],
)

この例では、両方の AnnSearchRequest オブジェクトがエンティティレベルの候補を生成します。最終結果は、親エンティティのプライマリキーをキーとして管理されます。EmbeddingList リクエストには element_scope を追加しないでください。

すべての AnnSearchRequest オブジェクトが同じ StructArray フィールド配下のエレメントレベルベクトルサブフィールドを対象とする場合、ハイブリッド検索はリランキングを通じてエレメントレベルの候補を維持できます。最終結果がエレメントレベルのまま保持されるのは、この StructArray ハイブリッドモードのみです。

次の例では、chunks StructArray フィールドに chunks[emb] と chunks[code_emb] という 2 つのエレメントレベルのベクトルサブフィールドがあり、どちらも COSINE を使用することを前提としています。コレクションの作成時に、追加の 4 次元 code_emb サブフィールドを定義してデータを格納してください。これは、上記でリンクされている基本スキーマには含まれていません。

python
query_vector = [0.19, 0.24, 0.30, 0.37]
code_query_vector = [0.20, 0.25, 0.31, 0.38]

index_chunk_req = AnnSearchRequest(
data=[query_vector],
anns_field="chunks[emb]",
limit=10,
param={},
expr='element_filter(chunks, $[section] == "index")',
)

code_chunk_req = AnnSearchRequest(
data=[code_query_vector],
anns_field="chunks[code_emb]",
limit=10,
param={},
expr='element_filter(chunks, $[has_code] == true)',
)

results = client.hybrid_search(
collection_name="tech_articles",
reqs=[index_chunk_req, code_chunk_req],
ranker=RRFRanker(),
limit=5,
output_fields=[
"doc_id",
"title",
"chunks[text]",
"chunks[section]",
"chunks[quality_score]",
],
)

for hits in results:
for hit in hits:
print(
"doc_id:", hit["doc_id"],
"distance:", hit["distance"],
"offset:", hit.get("offset"),
"entity:", hit["entity"],
)

両方の AnnSearchRequest オブジェクトは、chunks 配下のベクトルサブフィールドを検索します。同じ 0 始まりのオフセットは同じ Struct エレメントを指すため、ハイブリッドリランカーはエレメント候補を直接ランク付けできます。このモードではエンティティレベルの折りたたみが行われないため、element_scope を設定しないでください。

ハイブリッド検索で StructArray エレメントレベルの AnnSearchRequest と、コレクションレベルのベクトルリクエスト、EmbeddingList リクエスト、または異なる StructArray フィールド配下のエレメントレベルリクエストを組み合わせる場合、最終候補スコープはエンティティレベルになります。この場合、各 StructArray エレメントレベルの AnnSearchRequest は、ハイブリッドリランキングの前にエンティティレベルの候補に折りたたまれます。

同じエンティティから一致した複数のエレメントをどのように折りたたむかを制御する必要がある場合は、StructArray エレメントレベル AnnSearchRequest の params 内で element_scope を使用します。

python
query_vector = [0.19, 0.24, 0.30, 0.37]

title_req = AnnSearchRequest(
data=[query_vector],
anns_field="title_vector",
param={},
limit=10,
)

chunk_req = AnnSearchRequest(
data=[query_vector],
anns_field="chunks[emb]",
param={
"params": {
"element_scope": {
"collapse": {
"strategy": "topk_sum",
"topk": 3,
},
},
},
},
limit=30,
expr='element_filter(chunks, $[quality_score] > 0.8)',
)

results = client.hybrid_search(
collection_name="tech_articles",
reqs=[title_req, chunk_req],
ranker=RRFRanker(),
limit=5,
output_fields=[
"doc_id",
"title",
"category",
"chunks[text]",
"chunks[section]",
"chunks[quality_score]",
],
)

C++ および Rust 3.0.2 SDK のビルダーと C# 3.0.0 SDK は、文字列値の追加パラメーターインターフェイスを通じて、この例で使用するネストされた element_scope オブジェクトをエンコードしません。この折りたたみ戦略を構成するには、上記のいずれかの SDK または REST API を使用してください。

この例では、title_req はエンティティレベルであるため、最終的なハイブリッド検索結果もエンティティレベルになります。chunk_req リクエストは最初に chunks[emb] からエレメントのヒットを返し、次に同じエンティティから返されたエレメントのうち、上位 3 つのエレメントスコアを合計することで折りたたみます。エンティティレベルの折りたたみが必要なときに element_scope を省略すると、折りたたみ戦略はデフォルトで max になります。

折りたたみ戦略の選択​

戦略動作topkメトリクスの要件
maxエンティティについて返された最も良いエレメントスコアを保持します。指定できません。サポートされている任意の通常ベクトルメトリクス。
sumエンティティについて返されたすべてのエレメントスコアを合計します。指定できません。IP や COSINE など、正の相関を持つメトリクスのみ。
avgエンティティについて返されたすべてのエレメントスコアを平均します。指定できません。サポートされている任意の通常ベクトルメトリクス。
topk_sumエンティティについて返された上位 K 個のエレメントスコアを合計します。必須で、正の値である必要があります。IP や COSINE など、正の相関を持つメトリクスのみ。
topk_avgエンティティについて返された上位 K 個のエレメントスコアを平均します。必須で、正の値である必要があります。サポートされている任意の通常ベクトルメトリクス。

折りたたみでは、その StructArray エレメントレベル AnnSearchRequest によって返されたエレメントのヒットのみを使用します。ANN 検索後にエンティティ内のすべての Struct エレメントをスキャンするわけではありません。折りたたみに使用するエレメントを十分に取得できるよう、リクエストの limit を高めに設定してください。

フィルター、範囲検索、グループ化の追加​

スカラー条件を、ベクトル検索に参加する同じ Struct エレメントに適用する必要がある場合は、StructArray のエレメントレベル AnnSearchRequest に element_filter を付加できます。その条件を満たす必要がある各サブリクエストに親エンティティの条件を適用してください。トップレベルの filter 引数によってこの条件がすべてのリクエストに伝播されることを前提にしないでください。

StructArray のエレメントレベルベクトルフィールドは、ハイブリッド検索での範囲検索をサポートしています。エレメントレベル AnnSearchRequest に radius と、必要に応じて range_filter を追加します。EmbeddingList レベルの StructArray リクエストは範囲検索をサポートしていません。

エレメントレベルのハイブリッドグループ化は、すべての AnnSearchRequest オブジェクトが同じ StructArray フィールド配下のエレメントレベルベクトルフィールドを対象とし、group_by_field がプライマリキーである場合にのみサポートされます。リクエストにコレクションレベルのベクトルフィールド、異なる StructArray フィールド、または EmbeddingList レベルのリクエストが混在している場合、ハイブリッドグループ化はサポートされません。範囲検索とグループ化を組み合わせないでください。

ハイブリッド検索結果の解釈​

最終候補スコープ結果のキーオフセットの動作発生条件
エンティティレベルプライマリキー。最終結果にエレメントオフセットは含まれません。ハイブリッドリクエストに、コレクションレベルのベクトルフィールド、EmbeddingList リクエスト、または異なる StructArray フィールド配下のエレメントレベルリクエストが含まれている場合。
エレメントレベルプライマリキー、親 StructArray フィールド、およびエレメントオフセット。API または SDK で公開されている場合、選択されたエレメントオフセットを返すことができます。すべての AnnSearchRequest オブジェクトがエレメントレベルで、同じ StructArray フィールド配下にある場合。

制限事項​

  • ハイブリッド検索でエンティティレベルの候補に折りたたむ必要がある StructArray エレメントレベルの AnnSearchRequest オブジェクトにのみ、element_scope を使用してください。

  • EmbeddingList リクエスト、コレクションレベルのベクトルリクエスト、または同一 StructArray のエレメントレベルハイブリッド検索には、element_scope を使用しないでください。

  • sum および topk_sum の折りたたみ戦略では、IP や COSINE など、正の相関を持つメトリクスが必要です。L2 と組み合わせて使用しないでください。

  • topk_sum および topk_avg には正の topk 値が必要です。他の折りたたみ戦略には topk を含めないでください。

  • EmbeddingList レベルの StructArray リクエストは、範囲検索およびグループ化をサポートしていません。

  • ハイブリッドグループ化は、同一 StructArray のエレメントレベルハイブリッド検索でのみ、かつプライマリキーによる場合にのみサポートされます。

  • 範囲検索とグループ化を組み合わせないでください。

よくある間違い​

  • 同一 StructArray のエレメントレベルハイブリッドリクエストに element_scope を追加する。このリクエストはエレメントレベルのままであり、エンティティレベルの折りたたみは行われません。

  • chunks[emb_list_vector] に element_scope を追加する。EmbeddingList 検索はすでにエンティティレベルです。

  • 2 つの StructArray フィールドがエレメントオフセットを共有していると想定する。chunks のオフセット 3 と別の StructArray フィールドのオフセット 3 は異なるエレメントであるため、ハイブリッドリクエストはエンティティレベルになります。

  • topk_sum を L2 とともに使用する。負の距離メトリクスには、max、avg、または topk_avg を使用してください。

  • 折りたたみ後に、エンティティレベルのハイブリッド検索結果に選択された Struct エレメントのオフセットが含まれると期待する。

次のステップ​

  1. StructArray の 2 つの基本的なベクトル検索モードについては、StructArray を使用した基本的なベクトル検索 を参照してください。

  2. ハイブリッド検索にスカラーフィルターを追加する方法については、StructArray を使用したフィルター検索 を参照してください。

  3. ハイブリッド検索でスコアまたは距離の境界を使用する方法については、StructArray を使用した範囲検索 を参照してください。

  4. エレメントレベルのハイブリッド検索結果を親エンティティでグループ化する方法については、StructArray を使用したグループ化検索 を参照してください。

  5. StructArray 検索の制限を確認するには、StructArray の制限 を参照してください。