StructArray を使用した検索結果のグループ化

このページでは、StructArrayの要素レベルの検索結果を親エンティティごとにグループ化します。要素レベルの検索では、複数のStruct要素がクエリに一致する場合、同じエンティティから複数のヒットが返されることがあります。グループ化を行うと、これらの要素ヒットがまとめられ、各親エンティティが最大1回だけ表示されるようになります。

このページでは、「StructArrayフィールドの作成」のtech_articles コレクションを使用しています。このコレクションには、chunks という名前のStructArrayフィールドがあります。chunks[emb] ベクトルサブフィールドは、通常のベクトルメトリックを使用して要素レベルの検索がインデックス化されています。

StructArray に対するグループ化の適用方法

検索モードグループ化の挙動結果の挙動
EmbeddingList検索サポートされていません。該当なし。
要素レベルの検索主キーによるグループ化によりサポートされます。親エンティティごとに最大 1 件の結果が返されます。要素レベルのメタデータは保持されるため、API または SDK によって公開される場合、選択された要素のインデックスまたはオフセットが返されます。
ハイブリッド検索すべてのサブ検索が、同じ StructArray フィールドの下にある要素レベルのベクトルフィールドを対象としている場合にのみサポートされます。要素レベルのサブ検索は、最終的な結果処理の前に主キーによってグループ化されます。

グループ化されていない要素レベルの検索で重複する親エンティティが多数返される場合は、グループ化を使用してください。一致するすべての Struct 要素を個別のヒットとして取得したい場合は、group_by_field を使用せずに、StructArray を使用した基本ベクトル検索を使用してください。

開始する前に

グループ化検索を実行する前に、コレクション、データ、およびインデックスを準備してください。

要件詳細
要素レベルのベクトルサブフィールドchunks[emb] などの StructArray ベクトルサブフィールドを使用し、通常のベクトルメトリックでインデックス付けしてください。
通常のベクトルクエリEmbeddingList ではなく、通常のクエリベクトルを使用してください。
主キーによるグループ化コレクションの主キーを `group_by_field` として使用します(例: `doc_id`)。
範囲パラメータは使用しないグループ化検索を、radiusrange_filter などの範囲検索パラメータと組み合わせて使用しないでください。

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

次の例では、まず個々のチャンクを検索し、その後、親エンティティの主キーに基づいてヒットした要素をグループ化します。

from pymilvus import MilvusClient

client = MilvusClient(
    uri="http://localhost:19530",
    token="root:Milvus",
)

query_vector = [0.19, 0.24, 0.30, 0.37]

results = client.search(
    collection_name="tech_articles",
    data=[query_vector],
    anns_field="chunks[emb]",
    limit=5,
    group_by_field="doc_id",
    output_fields=[
        "doc_id",
        "title",
        "chunks[text]",
        "chunks[section]",
        "chunks[page]",
        "chunks[quality_score]",
    ],
)

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

グループ化を行わない場合、複数のチャンクがクエリに一致すると、同じ `doc_id ` が複数回表示される可能性があります。`group_by_field="doc_id"` を使用すると、各親エンティティは最大 1 回だけ表示されます。グループ化によって要素レベルのメタデータが保持されるため、API または SDK が公開している場合、グループ化された結果には、選択された Struct 要素のインデックスまたはオフセットが引き続き含まれることがあります。

スカラーフィルターの追加

グループ化検索と StructArray のスカラーフィルタリングを組み合わせることができます。スカラー条件によって、要素レベルのベクトル検索に参加する Struct 要素を制限する必要がある場合は、element_filter を使用します。

filter_expr = (
    'category == "search" && '
    'element_filter(chunks, '
    '$[section] == "index" && '
    '$[quality_score] > 0.9)'
)

results = client.search(
    collection_name="tech_articles",
    data=[query_vector],
    anns_field="chunks[emb]",
    filter=filter_expr,
    limit=5,
    group_by_field="doc_id",
    output_fields=[
        "doc_id",
        "title",
        "category",
        "chunks[text]",
        "chunks[section]",
        "chunks[quality_score]",
    ],
)

最上位の述語は候補エンティティを選択します。element_filter 述語は、要素レベルのベクトル検索を一致するStruct要素に限定します。その後、グループ化によって、一致した要素のヒットが主キーごとに集約されます。

StructArray を使用したハイブリッドグループ化は、要素レベルの機能です。これは、すべてのサブ検索が、同じ StructArray フィールドの下にある要素レベルのベクトルフィールドを対象としている場合にのみサポートされます。グループ化された StructArray ハイブリッド検索では、EmbeddingList レベルのリクエストを使用しないでください。

次の例では、chunks というStructArrayフィールドに、chunks[emb]chunks[code_emb] という2つの要素レベルのベクトルサブフィールドがあり、両方が通常のベクトルメトリックでインデックス化されていることを前提としています。

from pymilvus import AnnSearchRequest, RRFRanker

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

code_chunk_req = AnnSearchRequest(
    data=[code_query_vector],
    anns_field="chunks[code_emb]",
    limit=10,
    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,
    group_by_field="doc_id",
    output_fields=[
        "doc_id",
        "title",
        "chunks[text]",
        "chunks[section]",
    ],
)

この例では、両方のサブリクエストが、同じ StructArray フィールド(chunks )の下にある要素レベルのベクトルフィールドを対象としています。ハイブリッド検索では、通常のベクトルフィールド、異なる StructArray フィールド、または EmbeddingList レベルのリクエストが混在している場合、要素レベルのグループ化はサポートされません。

グループ化された結果の解釈

結果項目意味
idグループ化された親エンティティのプライマリキー。
distance またはスコアその親エンティティに対して選択されたStruct要素のスコアまたは距離。
offset返される際の、選択されたStruct要素の0を基点とする位置。
重複する主キー主キーによるグループ化では発生しない。
limitグループ化された親エンティティの結果に適用されます。

制限事項

  • グループ化検索は、要素レベルの StructArray ベクトル検索にのみ適用されます。EmbeddingList 検索および EmbeddingList レベルのハイブリッド検索では、グループ化はサポートされていません。

  • 主キーを `group_by_field` として使用してください。StructArray の要素レベルのグループ化は、任意のスカラーフィールドに対する汎用的なグループ化ではありません。

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

  • グループ化検索には、EmbeddingList クエリやMAX_SIM* メトリックを使用しないでください。

  • ハイブリッドグループ化は、すべてのサブ検索が同じ StructArray フィールドの下にある要素レベルのベクトルフィールドを対象としている場合にのみサポートされます。

  • ハイブリッド検索で、通常のベクトルフィールド、別の StructArray フィールド、または EmbeddingList レベルのリクエストが混在している場合、ハイブリッドグループ化はサポートされません。

よくある間違い

  • chunks[emb_list_vector] でのグループ化の使用。これは EmbeddingList 検索を目的としています。

  • 主キー以外のスカラーフィールドによるグループ化。

  • 複数のフィールドによるグループ化。要素レベルの StructArray グループ化では、主キーによるグループ化のみがサポートされています。

  • グループ化された結果が、一致したすべての Struct 要素を表すものと期待すること。グループ化では、親エンティティごとに最大 1 つの結果が返されます。

  • グループ化された要素レベルの検索によって、EmbeddingList形式のMAX_SIM* スコアが再計算されると想定すること。グループ化は要素レベルのヒットを統合するものであり、スコアリングモデルを変更するものではありません。

  • group_by_fieldradius またはrange_filter の組み合わせ。

次のステップ

  1. まず、グループ化されていない要素レベルの検索について学ぶには、「StructArray を使用した基本的なベクトル検索」を参照してください。

  2. グループ化された検索にスカラーフィルタを追加するには、「StructArray を使用したフィルタ付き検索」を参照してください。

  3. グループ化の代わりにスコアまたは距離の境界を使用するには、「StructArray を使用した範囲検索」を参照してください。

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