検索の集約Compatible with Milvus 3.0.x

買い物客が「日常のトレーニング用ブラックランニングシューズ」と検索した場合、近似最近傍法(ANN)検索はベクトルの類似度に基づいて商品をランク付けし、フラットなトップKリストを返します。結果は関連性が高いものの、繰り返しが多くなりがちです。以下の例では、上位6件の結果のうち4件がブランドAの商品であり、ブランドBとブランドCはそれぞれ1件ずつしか表示されていません。

フラットなリストでは、バケット指向の要約を直接提供することはできません。アプリケーションでは、候補の保持数や平均価格によってブランドを比較したり、各ブランドから少数の代表的な商品を精査したり、結果を複数のバケットレベルに整理したりする必要がある場合があります。

検索集計機能は、選択されたスカラーフィールドに基づいて、保持されたANN候補をバケットに整理します。この例では、各ブランドが個別のバケットとなります。Milvusは、各バケットの統計値を計算し、バケットを順序付け、代表的な製品を関連付けることができます。アプリケーションは、result.agg_buckets を通じて、この「バケット優先」のレスポンスを利用します。

A flat running-shoe search result becomes a set of comparable brand buckets 平坦なランニングシューズの検索結果は、比較可能なブランド・バケットのセットになります

検索集計は、コレクション全体に対する厳密な集計を実行するものではありません。バケットの存在、件数、メトリクス、順序、および代表的なヒットは、ANNおよびグループ化ステージによって保持された候補に依存します。

仕組み

ANN candidates grouped by bucket keys and returned with counts, metrics, and representative hits バケットキーごとにグループ化され、カウント、メトリクス、および代表的なヒットとともに返されるANN候補

  1. 候補の取得。MilvusはANN検索を実行し、クエリベクトルに最も近いエンティティを検索します。その後、グループ化ステージでは、各完全複合キーに対して上限数の候補を保持します。このキーごとの候補予算は、集計ツリー内の任意の場所におけるTopHits.size の最大値、またはtop_hits が設定されていないレベルでは1 となります。

  2. バケットの構築。 SearchAggregation.fields がバケットキーを定義します。フィールド値の各一意の組み合わせが、個別のキーを生成します。図では、fields=["brand"] により、(Brand A)(Brand B) 、および(Brand C) というバケットキーが生成されます。同じキーを持つ保持候補は同じバケットに属し、そのcount に寄与します。SearchAggregation.size は、Milvusが返すバケットの数を制限します。

  3. 結果を計算して返します。返される各バケットには、そのキーと保持された候補の数が含まれます。Milvusは、設定されたメトリクスの計算、バケットの並べ替え、代表的なエンティティの返却、および子バケットの構築も行うことができます。result.agg_buckets 内の各AggregationBucket は、keycountmetricshits 、およびsub_groups を公開します。検索集計が有効になっている場合、通常の検索ヒットリストは空になります。

図中では、TopHits.size=4 がキーごとの候補予算として4を割り当てているため、保持されたブランドAの候補4つからcount: 4 が生成されます。図を簡潔にするため、完成したブランドAのカードには、返された代表的なヒット4件のうち2件のみが表示されています。

sub_aggregation を使用すると、Milvusは各親バケット内で手順2と3を繰り返します。ANNのリコール率やキーごとの候補予算の変更により、バケット数、メトリクス、順序、ヒット、およびネストされた結果が変化する可能性があります。

制限事項

検索集計を使用する前に、以下の制限事項に注意してください:

  • ネストされた集計:1 つのリクエストには、1 つのルートSearchAggregation と、最大 3 レベルのネストされたsub_aggregation を含めることができ、合計で最大 4 レベルまで可能です。

  • バケットキーの作成に使用されるフィールド: SearchAggregation.fields は、Boolean、integer、VARCHAR 、およびTIMESTAMPTZ フィールドをサポートしています。FLOATDOUBLEARRAYJSONGEOMETRYTEXT 、vector、およびdynamicフィールドはサポートしていません。

  • メトリックフィールド: count は、"*" 、またはJSON 以外の非動的フィールドを受け付け、フィールドが指定されている場合はNULL の値をスキップします。sum およびavg は、整数および浮動小数点フィールドを受け付けます。min およびmax は、さらに文字列およびTIMESTAMPTZ フィールドも受け付けます。

  • トップヒットのソートフィールド: TopHits.sort は、比較可能なブール値、整数、浮動小数点数、文字列、およびTIMESTAMPTZ フィールドに加え、_score を受け付けます。ARRAYJSONGEOMETRY 、ベクトル、または動的フィールドはサポートしていません。

  • 候補数(Candidate budget):集計ツリー内のどこかで最大のTopHits.size は、完全複合キーごとに保持される候補数でもあります。どのレベルでもtop_hits が設定されていない場合、Milvusはキーごとに1つの候補を保持します。バケットcount およびメトリクスは、これらの保持された候補から計算されるため、TopHits.size を変更すると、これらも変更される可能性があります。

  • Null許容バケットフィールド: NULL の値は、それ自体がバケットキーを形成します。Nullバケットを除外するには、検索リクエストにbrand is not null などのフィルターを追加してください。

  • 重複するフィールド:同一のフィールドを複数の「SearchAggregation.fields 」リストに含めることはできません。たとえば、ルート集計でfields=["category"] を使用している場合、ネストされたsub_aggregationfields=["category"] を使用することはできません。

  • サポートされていない組み合わせ:Search Aggregationは、offset 、Search Iterators、Hybrid Search、Highlighter、またはGrouping Searchと組み合わせることはできません。

  • 返されるエントリ数:設定された結果エントリの最大数を10,000以下に抑えてください。この最大数は次のように計算します:

    number of query vectors × size at every aggregation level × largest TopHits.size at any level

    TopHits が設定されていないレベルがある場合、最後の要素として1 を使用してください。たとえば、クエリベクトルが1つ、ルートバケットが10個、ルートバケットごとに子バケットが5個、子バケットごとにヒットが2件ある場合、設定された最大値は次のようになります:

    1 × 10 × 5 × 2 = 100

検索集計の使用

達成したい内容に基づいて例を選択してください:

[検索] に移動して説明主な設定
バケットの比較と並べ替えバケットごとの統計情報を計算してバケットを比較し、返されたバケットをメトリクス、カウント、またはキーで並べ替えます。fields,size,metrics,order
各バケットから代表的な結果を表示各バケットから限定された数のエンティティを取得し、それらのエンティティをスカラーフィールドまたはベクトルスコアごとに個別に並べ替えます。top_hits,TopHits.size,TopHits.sort
結果を複数のレベルでグループ化する結果を親バケットと子バケットのレベルに整理し、複数の次元を順次分析します。sub_aggregation

以下の例では、ブランド、カテゴリ、色、価格、評価のフィールドを持つ商品コレクションを使用しています。すべてのブランド名、商品名、価格、評価、および検索結果は、合成されたサンプルデータです。以下のセクションを展開して、コレクションを作成し、共有検索変数を定義してください。

サンプルコレクションの設定

from pymilvus import DataType, MilvusClient, SearchAggregation, TopHits

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

collection_name = "product_search_aggregation"

if client.has_collection(collection_name):
    client.drop_collection(collection_name)

schema = client.create_schema(auto_id=False, enable_dynamic_field=False)
schema.add_field("id", DataType.INT64, is_primary=True)
schema.add_field("embedding", DataType.FLOAT_VECTOR, dim=5)
schema.add_field("name", DataType.VARCHAR, max_length=200)
schema.add_field("brand", DataType.VARCHAR, max_length=100)
schema.add_field("category", DataType.VARCHAR, max_length=100)
schema.add_field("color", DataType.VARCHAR, max_length=50)
schema.add_field("price", DataType.DOUBLE)
schema.add_field("rating", DataType.DOUBLE)
schema.add_field("in_stock", DataType.BOOL)

index_params = client.prepare_index_params()
index_params.add_index(
    field_name="embedding",
    index_type="AUTOINDEX",
    metric_type="COSINE",
)

client.create_collection(
    collection_name=collection_name,
    schema=schema,
    index_params=index_params,
    # Make preceding writes visible to searches from this client.
    consistency_level="Session",
)

client.insert(
    collection_name=collection_name,
    data=[
        {
            "id": 1,
            "embedding": [0.12, 0.42, 0.18, 0.66, 0.31],
            "name": "Runner A1",
            "brand": "Brand A",
            "category": "running_shoes",
            "color": "black",
            "price": 129.99,
            "rating": 4.7,
            "in_stock": True,
        },
        {
            "id": 2,
            "embedding": [0.10, 0.39, 0.20, 0.61, 0.29],
            "name": "Trail A2",
            "brand": "Brand A",
            "category": "running_shoes",
            "color": "blue",
            "price": 139.99,
            "rating": 4.6,
            "in_stock": True,
        },
        {
            "id": 3,
            "embedding": [0.14, 0.44, 0.19, 0.68, 0.33],
            "name": "Runner B1",
            "brand": "Brand B",
            "category": "running_shoes",
            "color": "white",
            "price": 159.99,
            "rating": 4.8,
            "in_stock": True,
        },
        {
            "id": 4,
            "embedding": [0.16, 0.41, 0.22, 0.62, 0.30],
            "name": "Runner C1",
            "brand": "Brand C",
            "category": "running_shoes",
            "color": "red",
            "price": 119.99,
            "rating": 4.4,
            "in_stock": False,
        },
        {
            "id": 5,
            "embedding": [0.48, 0.20, 0.59, 0.15, 0.71],
            "name": "Jacket A1",
            "brand": "Brand A",
            "category": "jackets",
            "color": "black",
            "price": 99.99,
            "rating": 4.5,
            "in_stock": True,
        },
        {
            "id": 6,
            "embedding": [0.45, 0.18, 0.55, 0.17, 0.69],
            "name": "Jacket B1",
            "brand": "Brand B",
            "category": "jackets",
            "color": "blue",
            "price": 89.99,
            "rating": 4.3,
            "in_stock": True,
        },
        {
            "id": 7,
            "embedding": [0.09, 0.38, 0.17, 0.60, 0.27],
            "name": "Runner A3",
            "brand": "Brand A",
            "category": "running_shoes",
            "color": "black",
            "price": 159.99,
            "rating": 4.8,
            "in_stock": True,
        },
        {
            "id": 8,
            "embedding": [0.13, 0.43, 0.21, 0.65, 0.32],
            "name": "Runner A4",
            "brand": "Brand A",
            "category": "running_shoes",
            "color": "black",
            "price": 149.99,
            "rating": 4.9,
            "in_stock": True,
        },
    ],
)

client.load_collection(collection_name)

query_vector = [0.11, 0.40, 0.19, 0.64, 0.30]
search_params = {
    "metric_type": "COSINE",
    "params": {},
}

上記の設定では、ベクトルインデックスと検索パラメータの両方について、COSINE が構成されています。そのため、以降の例では、{"_score": "desc"} を使用して、コサイン類似度の高いものを優先的に表示します。L2 などの距離メトリックを使用する場合は、{"_score": "asc"} を使用してください。

バケットの比較とソート

このパターンは、計算された統計値を使用して検索されたエンティティのグループを比較し、バケットが返される順序を制御する必要がある場合に使用します。この例では、Milvusは検索された商品をbrand でグループ化し、各ブランドバケットの価格メトリクスを計算し、平均価格に基づいてバケットを並べ替えます。

フィールド値ごとに1つ以上のエンティティを返すことで、結果の多様性を高めることのみを目的とする場合は、代わりに「グループ化検索」を使用してください。

以下の設定では、最大3つのブランド・バケットを作成し、各バケットのメトリクスを計算した上で、平均価格順にバケットを並べ替えます:

aggregation = SearchAggregation(
    # Form one bucket for each distinct brand value.
    fields=["brand"],
    # Return up to three buckets at this aggregation level.
    size=3,
    # Calculate named metrics for every selected bucket.
    metrics={
        "product_count": {"count": "*"},
        "avg_price": {"avg": "price"},
        "min_price": {"min": "price"},
    },
    # Sort buckets by average price, highest first.
    order=[
        {"avg_price": "desc"},
        # If average prices are equal, sort by bucket key in ascending order.
        {"_key": "asc"},
    ],
)

MilvusClient.search()search_aggregation パラメータにオブジェクトを渡します:

result = client.search(
    collection_name=collection_name,
    data=[query_vector],
    anns_field="embedding",
    search_params=search_params,
    output_fields=[
        "name",
        "brand",
        "category",
        "color",
        "price",
        "rating",
        "in_stock",
    ],
    search_aggregation=aggregation,
)

search_aggregation が設定されている場合、PyMilvusはresult[0] に通常のエンティティヒットを返しません。代わりに、result.agg_buckets[0] からバケットのレスポンスを読み取ってください。output_fields パラメータは、返される各AggregationHit.fields マッピングにどのスカラーフィールドが表示されるかを制御します。Milvusは、output_fields にリストされていないメトリックソースフィールドやソートフィールドも引き続き使用できます。

バケット出力の例を表示

以下の出力は、上記のリクエストから取得され、可読性を高めるためにJSONとしてシリアライズされたものです。PyMilvusはJSONではなく、AggregationBucket オブジェクトを返します。key の値は、fields にフィールドが1つしか含まれていない場合でも、常にキーコンポーネントの順序付きリストとなります。これにより、複合キーのフィールド順序が保持されます。

[
  {
    "key": [
      {
        "field_id": 103,
        "field_name": "brand",
        "value": "Brand B"
      }
    ],
    "count": 1,
    "metrics": {
      "product_count": 1,
      "avg_price": 159.99,
      "min_price": 159.99
    },
    "hits": [],
    "sub_groups": []
  },
  {
    "key": [
      {
        "field_id": 103,
        "field_name": "brand",
        "value": "Brand A"
      }
    ],
    "count": 1,
    "metrics": {
      "product_count": 1,
      "avg_price": 129.99,
      "min_price": 129.99
    },
    "hits": [],
    "sub_groups": []
  },
  {
    "key": [
      {
        "field_id": 103,
        "field_name": "brand",
        "value": "Brand C"
      }
    ],
    "count": 1,
    "metrics": {
      "product_count": 1,
      "avg_price": 119.99,
      "min_price": 119.99
    },
    "hits": [],
    "sub_groups": []
  }
]

このガイドの単一のクエリベクトルについては、result.agg_buckets[0] から返された最上位のバケットを読み取ります。各バケットは、順序付きキーコンポーネント、保持された候補count 、計算されたmetrics 、代表値hits 、およびsub_groups 内のネストされたバケットを公開しています。

設定は次のように読み取ります:

設定項目制御対象この例では
fieldsMilvusによるバケットキーの生成方法brand の値がそれぞれ異なるごとに、1つのバケットを作成します。
size返されるバケットの最大数最大3つのブランド・バケットを返します。
metrics各バケットについて計算される統計情報商品数、平均価格、最低価格を算出します。
orderMilvus による返されるバケットのソート方法平均価格でソートし、同値の場合はバケットキーを使用して順位を決定します。

search_aggregation が設定されている場合、Milvusはlimit を無視します。トップレベルのバケット数を制御するには、ルートSearchAggregation.size の値を使用してください。

これらの設定により、Milvusはavg_price の降順で、ブランドB、ブランドA、ブランドCのバケットを返します。_key という基準は、バケットの平均価格が同じ場合にのみ適用されます。この構成ではtop_hits が定義されていないため、各バケットのhits リストは空であり、キーごとの候補予算は1 となります。したがって、表示されるカウントとメトリクスは、ブランドごとに1つの候補が保持されていることを表しています。集計にキーごとのより広いメトリクスウィンドウが必要な場合は、top_hitsTopHits.size の値を大きくして設定してください。

メトリクスと順序付けのルール

SearchAggregation.metrics エントリは、ユーザー定義のエイリアスを{operation: source} にマッピングします:

ソースサポートされる操作動作
JSON 以外かつ動的フィールドではないフィールドcountソースフィールドがNULL ではない、保持された候補をカウントします。
整数型または浮動小数点型のフィールドsumavgminmaxNULL ではない保持済み値に対して計算を行います。
文字列またはTIMESTAMPTZ フィールドminmaxNULLでない保持値のうち、最小値または最大値を選択します。
"*"countバケット内のすべての保持候補をカウントします。結果はbucket.count と一致します。
_scoresumavgminmax保持された候補について、ANNの類似度または距離の値を集計します。

SearchAggregation.order 以下のキーを受け付けます:

順序キー意味
メトリックの別名metrics で同じ集計レベルで計算された値(例:avg_price )に基づいてソートします。
_count各バケットに保持されている候補の数に基づいてソートします。
_key_key という名前のコレクションフィールドではなく、バケットキーに基づいてソートします。

order エントリは、キーを"asc" または"desc" にマッピングします。Milvusは、最初のエントリから最後のエントリまで複数のエントリを評価します。order を省略した場合、Milvusは保持された候補セットからのバケット検出順序を維持します。

バケットをベクトル一致品質でソートするには、まず `_score` からバケットレベルのメトリックを計算し、そのメトリックエイリアスを `order` で使用します。各バケットには複数のエンティティスコアが含まれる可能性があるため、`_score ` をバケット順序のキーとして直接使用することはできません。たとえば、`COSINE ` または `IP` を使用する場合:

aggregation = SearchAggregation(
    fields=["brand"],
    size=3,
    metrics={"max_score": {"max": "_score"}},
    order=[{"max_score": "desc"}],
)

L2 を使用し、_score の最小値を算出し、メトリックエイリアスを昇順でソートすることで、距離が最も小さいバケットが先頭にくるようにします。

複合バケットキーの作成

複合バケットキーを作成するには、同じリストに複数のフィールド名を指定します:

aggregation = SearchAggregation(
    # Combine brand and color to form a composite bucket key.
    fields=["brand", "color"],
    size=6,
)

この設定により、(Brand A, black)(Brand A, blue)(Brand B, white) などのキーが生成されます。2つのエンティティが同じバケットを共有するのは、両方の値が一致する場合のみです。Milvusはリストの順序を保持するため、brand が最初のキー構成要素となり、color が2番目となります。order_key が使用される場合、Milvusは複合キーの構成要素を同じ順序で比較します。複数の文字列は1つのフラットなリストで渡してください。ネストされたリストはサポートされていません。

size=6 は、この集計レベルで返される複合バケットの最大数です。サンプルデータには5つの異なるブランドと色の組み合わせが含まれているため、これら5つすべてが返される可能性があります。返されるエントリの制限において、このリクエストは1 query vector × 6 buckets × 1 = 6 で設定された結果エントリを生成します。

1つのSearchAggregation.fields リスト内の複数のフィールドは、その集計レベルで複合バケットキーを作成します。親子バケット階層を作成するには、ネストされた集計を使用してください。

以下の例では、aggregation を再定義しています。更新されたオブジェクトを同じsearch_aggregation パラメータに渡して、検索呼び出しを再実行してください。

各バケットから代表的な結果を表示する

アプリケーションが各バケットから実際の製品を表示する必要がある場合は、代表的なエンティティを含めます。この例では、Milvus は各ブランドバケットから最大 2 つの製品を、評価順、次にベクトルスコア順で返します。

TopHits を次のように設定します:

aggregation = SearchAggregation(
    fields=["brand"],
    size=3,
    # Return and sort representative entities for each selected bucket.
    top_hits=TopHits(
        # Return up to two entities per bucket.
        size=2,
        # Apply sort criteria in list order.
        sort=[
            {"rating": "desc"},
            {"_score": "desc"},
        ],
    ),
)

代表的なヒットを含むバケットを表示する

以下のブランドAのバケットは、上記のリクエストから取得され、可読性を高めるためにJSONとしてシリアライズされています。

{
  "key": [
    {
      "field_id": 103,
      "field_name": "brand",
      "value": "Brand A"
    }
  ],
  "count": 2,
  "metrics": {},
  "hits": [
    {
      "pk": 1,
      "score": 0.99976646900177,
      "fields": {
        "brand": "Brand A",
        "category": "running_shoes",
        "color": "black",
        "in_stock": true,
        "name": "Runner A1",
        "price": 129.99,
        "rating": 4.7
      }
    },
    {
      "pk": 2,
      "score": 0.9997048377990723,
      "fields": {
        "brand": "Brand A",
        "category": "running_shoes",
        "color": "blue",
        "in_stock": true,
        "name": "Trail A2",
        "price": 139.99,
        "rating": 4.6
      }
    }
  ],
  "sub_groups": []
}

パラメータ目的
top_hitsオプション。この集計レベルにおける代表的なエンティティを設定します。省略された場合、bucket.hits は空となり、キーごとの候補予算はデフォルトで 1 になります。
TopHits.size選択された各バケットから最大2つの代表的なエンティティを返し、集計ツリー全体についてキーごとの候補予算を2に設定します。
TopHits.sort各バケット内のエンティティを、指定された基準に従って並べ替えます。

アプリケーションで代表エンティティが必要な場合や、カウントおよびメトリクスでキーごとの候補ウィンドウを広くする必要がある場合は、top_hits を設定してください。TopHits.size を大きくすると、候補予算とLimits での最大返却エントリ数の計算値の両方が増加します。

SearchAggregation.order はバケットをソートし、TopHits.sort は各バケット内の保持されたエンティティをソートします。このソート順によって、count やメトリクスのために保持された候補が変更されることはありません。TopHits.sort は、サポートされている比較可能なスカラーフィールド名と、ANNの類似度または距離を表す組み込みの_score フィールドを受け入れます。Milvusは、sort のエントリを先頭から末尾へと評価します。 この例では、rating の値が高い順から低い順に商品を並べ替え、_score は2つの評価が等しい場合にのみ使用されます。設定でCOSINE が使用されているため、降順の_score により、類似度の高い商品が最初に配置されます。

metricsTopHits.sort で使用されるフィールドは、output_fields に含まれている必要はありません。Milvus は内部的にそれらのフィールドを取得しますが、output_fields に明示的にリストされているフィールドのみが、返される各ヒットのfields マッピングに含まれます。主キーとベクトルスコアは、AggregationHit.pk およびAggregationHit.score を通じて引き続き利用可能です。

返される各AggregationHit は、pk でプライマリキーを、score でベクトルスコアを、fields で要求された出力フィールドを公開します。

複数のレベルで結果をグループ化する

あるレベル内のバケットを別のレベル内に配置する必要がある場合は、ネストされた集計を使用します。この例では、Milvusはまずカテゴリバケットを作成し、その後、各カテゴリ内にブランドバケットを作成します。

子集計には、その親バケットに割り当てられたエンティティのみが渡されます。fields は各集計レベルでのバケットキーを制御し、sub_aggregation は親子階層を作成します。

以下の設定では、キーが(running_shoes) であるカテゴリ・バケットが作成されます。その親バケット内で、子集計により、(Brand A)(Brand B)(Brand C) などのキーを持つ個別のブランド・バケットが作成されます。

Parent bucket key:
(running_shoes)

Child bucket keys:
├── (Brand A)
├── (Brand B)
└── (Brand C)

各レベルでは、複数のフィールドを独立して使用できます。たとえば、子アグリゲーションで `fields=["brand", "color"] ` を使用すると、`(Brand A, black)` のような複合子キーが生成されます。

以下の設定により、この階層構造が実装されます:

aggregation = SearchAggregation(
    fields=["category"],
    size=2,
    metrics={
        "product_count": {"count": "*"},
        "avg_price": {"avg": "price"},
    },
    order=[{"product_count": "desc"}],
    # For each category bucket, group only its entities by brand.
    sub_aggregation=SearchAggregation(
        fields=["brand"],
        size=3,
        metrics={
            "brand_count": {"count": "*"},
            "avg_rating": {"avg": "rating"},
        },
        order=[{"avg_rating": "desc"}],
        top_hits=TopHits(
            size=2,
            sort=[{"rating": "desc"}],
        ),
    ),
)

ネストされたバケットの結果を表示する

以下のシリアライズされた抜粋は、親バケット「running_shoes 」とその子バケット「Brand B」を示しています。簡潔にするため、「Brand A」および「Brand C」の子バケットは省略されています。

{
  "key": [
    {
      "field_id": 104,
      "field_name": "category",
      "value": "running_shoes"
    }
  ],
  "count": 4,
  "metrics": {
    "avg_price": 137.49,
    "product_count": 4
  },
  "hits": [],
  "sub_groups": [
    {
      "key": [
        {
          "field_id": 103,
          "field_name": "brand",
          "value": "Brand B"
        }
      ],
      "count": 1,
      "metrics": {
        "avg_rating": 4.8,
        "brand_count": 1
      },
      "hits": [
        {
          "pk": 3,
          "score": 0.9994542598724365,
          "fields": {
            "brand": "Brand B",
            "category": "running_shoes",
            "color": "white",
            "in_stock": true,
            "name": "Runner B1",
            "price": 159.99,
            "rating": 4.8
          }
        }
      ],
      "sub_groups": []
    }
  ]
}

表示された結果は、単一の複合バケットキー(running_shoes, Brand B) ではなく、バケットパス(running_shoes) → (Brand B) を表しています。

Milvusはまず、product_count の順に最大2つのカテゴリバケットを選択します。次に、選択された各カテゴリ内でsub_aggregation を個別に実行し、avg_rating の順に最大3つのブランドバケットを返します。

上記の出力では:

  • ルートrunning_shoes バケットには、その子コンポジットキー全体にわたって4つの保持候補が含まれています。そのmetrics には、ルートレベルのavg_price およびproduct_count の値が含まれています。
  • ルートバケットのsub_groups リストには、子ブランドバケットが含まれています。表示されているブランドBバケットには、1つの保持候補と、それ自体のavg_rating およびbrand_count 値が含まれています。
  • ルートバケットのhits リストが空なのは、ルート集計でtop_hits が設定されていないためです。ブランドBの子バケットには代表的なヒットが含まれていますが、これはsub_aggregationtop_hits が設定されているためです。

よくある質問

バケットのカウント数やメトリクスの精度はどの程度ですか?

検索集計は、保持された ANN 候補を要約するものです。コレクション全体の集計は実行されません。

候補の保持には 2 つの近似段階があります。ANN 検索では関連するコレクションエンティティが除外される可能性があり、グループ化段階では、各完全複合キーに対して最大でTopHits.size の候補が保持されます。top_hits が設定されているレベルがない場合、このキーごとの上限は 1 となります。

たとえば、あるコレクションにブランドAの製品が5,000件含まれており、その多くがベクトルクエリに関連していると仮定します。集計でTopHits(size=4) が使用されている場合、ブランドAのバケットは、完全な複合キーに対して最大4つの候補のみを保持できます。そのcount およびメトリクスは、保持されたそれらの候補を表しており、関連するすべてのブランドA製品や、コレクション内の5,000件のエンティティすべてを表しているわけではありません。

近似値が最も重要になるのは、order がメトリックエイリアスを使用する場合です。検索のリコール率の変化によりメトリック値が変化し、その結果、SearchAggregation.size に収まるバケットが変わる可能性があります。ネストされた集計では、各子レベルが親バケット内で利用可能なエンティティに対して操作を行うため、この影響がさらに増幅される可能性があります。

一致するすべてのエンティティについて正確な統計情報を必要とする場合は、検索集計の代わりに「正確なクエリ集計」ワークフローを使用してください。

アプリケーションの主な結果の形状に基づいて選択してください:

主な要件推奨利用すべき結果
グループ化フィールド内の重複値が少なく、標準的な順位付けされたエンティティリストを返すグループ化検索各クエリベクトルに対するフラットな検索ヒット
グループをバケットとして、キー、カウント、メトリクス、順序、代表的なヒット、または子バケットを用いて検査または比較する検索集計AggregationBucket オブジェクトresult.agg_buckets

検索集計でtop_hits が設定されている場合でも、その主なレスポンスはバケットツリーのままです。アプリケーションがすでに通常の検索ヒットを処理しており、主に結果の多様性を求めている場合には、グループ化検索が有用です。

これらのAPIは相互に排他的です。同じリクエスト内でsearch_aggregationgroup_by_field またはgroup_by_fields を組み合わせて使用すると、PyMilvusはParamError を発生させます。