Search Aggregation
当购物者搜索“用于日常训练的黑色跑鞋”时,ANN Search 会根据向量相似度对商品进行排序,并返回一个扁平的 Top-K list。结果可能相关,但也可能重复:在下面的示例中,前六个结果中有四个是 Brand A 商品,而 Brand B 和 Brand C 各只出现一次。
扁平列表无法直接提供面向 bucket 的摘要。应用可能需要按保留的候选数量或平均价格比较不同品牌,查看每个品牌少量有代表性的商品,或者将结果组织为多级 bucket。
Search Aggregation 会根据选定的标量字段,将保留下来的 ANN 候选结果组织到 bucket 中。在此示例中,每个品牌都会成为一个单独的 bucket。Milvus 可以为每个 bucket 计算统计信息、对 bucket 排序,并附加有代表性的商品。应用通过 result.agg_buckets 消费这种以 bucket 优先的响应。

Search Aggregation 不会对整个 Collection 执行精确聚合。bucket 是否存在、计数、指标、排序以及代表性命中,取决于 ANN 和 grouping 阶段保留下来的候选结果。
How it works

-
检索候选项。 Milvus 运行 ANN search,查找与查询向量最接近的 Entity。随后,分组阶段会为每个完整复合键保留有上限数量的候选项。这个按 key 计算的候选项预算,取聚合树中任意位置最大的
TopHits.size;如果没有任何层级配置top_hits,则为1。 -
构建 bucket。
SearchAggregation.fields定义 bucket key。字段值的每一种唯一组合都会创建一个独立的 key。在图中,fields=["brand"]会创建(Brand A)、(Brand B)和(Brand C)bucket key。具有相同 key 的保留候选项属于同一个 bucket,并计入其count。SearchAggregation.size限制 Milvus 返回的 bucket 数量。 -
计算并返回结果。 每个返回的 bucket 都包含其 key 和保留候选项计数。Milvus 还可以计算已配置的指标、对 bucket 排序、返回代表性 Entity,以及构建子 bucket。
result.agg_buckets中的每个AggregationBucket都会暴露key、count、metrics、hits和sub_groups。启用 Search Aggregation 后,普通 search hit 列表为空。
在图中,TopHits.size=4 提供了每个 key 四个候选项的预算,因此保留的四个 Brand A 候选项会产生 count: 4。为保持图示简洁,完成后的 Brand A 卡片只展示四个返回的代表性 hits 中的两个。
使用 sub_aggregation 时,Milvus 会在每个父 bucket 内重复步骤 2 和步骤 3。ANN 召回结果或按 key 计算的候选项预算发生变化时,可能会改变 bucket 计数、指标、排序、hits 和嵌套结果。
Limits
使用 Search Aggregation 前,请注意以下限制:
-
嵌套聚合: 一个请求可以包含一个根
SearchAggregation,并且最多包含三层嵌套的sub_aggregation,总共最多四层。在所有层级中,最多可以使用 10 个字段创建 bucket key。 -
用于创建 bucket key 的字段:
SearchAggregation.fields支持布尔、整数、VARCHAR和TIMESTAMPTZ字段。不支持FLOAT、DOUBLE、ARRAY、JSON、GEOMETRY、TEXT、vector field 或动态字段。 -
Metric 字段:
count接受"*"或任何非JSON、非动态字段;指定字段时会跳过NULL值。sum和avg接受整数和浮点字段。min和max还接受字符串和TIMESTAMPTZ字段。 -
Top Hits 排序字段:
TopHits.sort接受可比较的布尔、整数、浮点、字符串和TIMESTAMPTZ字段,以及_score。不支持ARRAY、JSON、GEOMETRY、vector field 或动态字段。 -
候选项预算: 聚合树中最大的
TopHits.size也是每个完整复合键保留的候选项数量。如果所有层都未配置top_hits,Milvus 会为每个键保留一个候选项。Bucketcount和 metric 都基于这些保留的候选项计算,因此更改TopHits.size可能会改变它们。 -
可为 NULL 的 bucket 字段:
NULL值会形成自己的 bucket key。要排除 NULL bucket,请在搜索请求中添加类似brand is not null的过滤条件。 -
重复字段: 同一字段不能出现在多个
SearchAggregation.fields列表中。例如,如果根聚合使用fields=["category"],嵌套的sub_aggregation不能再使用fields=["category"]。 -
不支持的组合: Search Aggregation 不能与非零
offset、Search Iterators、Hybrid Search、Highlighter 或 Grouping Search 组合使用。顶层offset的值为0时,等同于省略该参数。在 REST v2 搜索请求中,不能同时指定searchAggregation和ids。 -
返回条目: 默认情况下,当请求计算出的最大结果条目数超过 10,000 时,Milvus 会拒绝该 Search Aggregation 请求。此阈值由
proxy.maxSearchAggregationResultEntries控制。将该配置值设置为0或负数可禁用此检查。
Milvus 按以下方式计算该最大值:
number of query vectors × product of the effective search_size at every aggregation level × largest TopHits.size at any level
对于该服务端计算,某一层级的有效 search_size 是显式配置的 search_size;如果省略 search_size,则使用该层级的 size。本指南中使用的 PyMilvus API 目前不暴露 search_size,因此 PyMilvus 请求在此计算中使用各层级的 size。如果所有层级都未配置 TopHits,最后一个因子使用 1。例如,一个查询向量、10 个根 bucket、每个根 bucket 下 5 个子 bucket,以及每个子 bucket 2 个 hit,会得到以下计算最大值:
1 × 10 × 5 × 2 = 100
使用 Search Aggregation
根据你的目标选择示例:
| 跳转到 | 说明 | 关键设置 |
|---|---|---|
| 比较并排序 bucket | 计算每个 bucket 的统计信息以比较 bucket,然后按指标、数量或键对返回的 bucket 排序。 | fields, size, metrics, order |
| 显示每个 bucket 的代表性结果 | 从每个 bucket 返回有限数量的 entity,并按标量字段或向量分数独立排序这些 entity。 | top_hits, TopHits.size, TopHits.sort |
| 按多级分组结果 | 将结果组织为父级和子级 bucket 层级,以便按顺序分析多个维度。 | sub_aggregation |
以下示例使用一个包含品牌、类别、颜色、价格和评分字段的商品 collection。所有品牌名称、商品名称、价格、评分和搜索结果都是合成示例数据。展开以下部分以创建 collection 并定义共享搜索变量。
设置示例 collection
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"} 将更高的 cosine similarity 排在前面。对于 L2 等距离度量,请使用 {"_score": "asc"}。
Compare and sort buckets
当你需要使用计算出的统计信息比较检索到的 Entity 分组,并控制 bucket 返回顺序时,可以使用此模式。在此示例中,Milvus 按 brand 对检索到的商品分组,为每个 brand bucket 计算价格指标,并按平均价格对 bucket 排序。
如果你的目标只是通过为每个字段值返回一个或多个 Entity 来提升结果多样性,请改用 Grouping Search。
以下配置最多创建三个 brand bucket,为每个 bucket 计算指标,并按平均价格对 bucket 排序:
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] 中返回普通 Entity hits。请改为从 result.agg_buckets[0] 读取 bucket 响应。output_fields 参数控制每个返回的 AggregationHit.fields 映射中包含哪些标量字段;即使某些 metric-source 字段和排序字段未列在 output_fields 中,Milvus 仍可使用它们。
查看示例 bucket 输出
以下输出来自上面的请求,并序列化为 JSON 以便阅读。PyMilvus 返回的是 AggregationBucket 对象,而不是 JSON。即使 fields 只包含一个字段,key 值也始终是按顺序排列的 key 组件列表。这可以保留复合 key 的字段顺序。
[
{
"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] 读取返回的顶层 bucket。每个 bucket 都会暴露其有序 key 组件、保留候选的 count、计算出的 metrics、代表性 hits,以及 sub_groups 中的嵌套 bucket。
按如下方式理解该配置:
| 设置 | 控制内容 | 在此示例中 |
|---|---|---|
fields | Milvus 如何创建 bucket key | 为每个不同的 brand 值创建一个 bucket。 |
size | 返回 bucket 的最大数量 | 最多返回三个 brand bucket。 |
metrics | 为每个 bucket 计算的统计信息 | 计算商品数量、平均价格和最低价格。 |
order | Milvus 如何对返回的 bucket 排序 | 按平均价格排序,然后使用 bucket key 打破并列。 |
设置 search_aggregation 后,Milvus 会忽略 limit。请使用根级 SearchAggregation.size 值控制顶层 bucket 的数量。
使用这些设置时,Milvus 会按 avg_price 降序返回 Brand B、Brand A 和 Brand C bucket。_key 条件仅在 bucket 具有相同平均价格时适用。由于此配置未定义 top_hits,每个 bucket 的 hits 列表为空,并且每个 key 的候选预算为 1。因此,显示的计数和指标描述的是每个 brand 的一个保留候选。当 aggregation 需要更宽的每 key 指标窗口时,请配置 top_hits 并使用更大的 TopHits.size。
指标和排序规则
每个 SearchAggregation.metrics 条目都会将用户定义的别名映射到 {operation: source}:
| Source | 支持的操作 | 行为 |
|---|---|---|
任何非 JSON、非动态字段 | count | 统计 source 字段不是 NULL 的保留候选数量。 |
| 整数或浮点字段 | sum, avg, min, max | 基于非 NULL 保留值计算。 |
字符串或 TIMESTAMPTZ 字段 | min, max | 选择非 NULL 保留值中的最小值或最大值。 |
"*" | count | 统计 bucket 中的每个保留候选。结果与 bucket.count 一致。 |
_score | sum, avg, min, max | 聚合保留候选的 ANN 相似度或距离值。 |
SearchAggregation.order 接受以下 key:
| Order key | 含义 |
|---|---|
| metric 别名 | 按同一 aggregation 层级的 metrics 中计算出的值排序,例如 avg_price。 |
_count | 按每个 bucket 中的保留候选数量排序。 |
_key | 按 bucket key 排序,而不是按名为 _key 的 Collection 字段排序。 |
每个 order 条目都会将一个 key 映射到 "asc" 或 "desc"。Milvus 按从前到后的顺序评估多个条目。如果省略 order,Milvus 会保留来自保留候选集的 bucket 发现顺序。
要按向量匹配质量对 bucket 排序,请先基于 _score 计算 bucket 级指标,然后在 order 中使用该指标别名。不能直接将 _score 用作 bucket 排序 key,因为每个 bucket 可包含多个 Entity score。例如,对于 COSINE 或 IP:
aggregation = SearchAggregation(
fields=["brand"],
size=3,
metrics={"max_score": {"max": "_score"}},
order=[{"max_score": "desc"}],
)
对于 L2,请计算最小 _score 值,并按升序对该指标别名排序,使距离最低的 bucket 排在最前。
创建复合 bucket key
要创建复合 bucket key,请在同一个列表中传入多个字段名:
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) 等 key。只有当两个值都匹配时,两个 Entity 才会共享一个 bucket。Milvus 会保留列表顺序,因此 brand 是第一个 key 组件,color 是第二个 key 组件。当在 order 中使用 _key 时,Milvus 会按相同顺序比较复合 key 组件。请在一个扁平列表中传入多个字符串;不支持嵌套列表。
size=6 是此 aggregation 层级返回的复合 bucket 最大数量。示例数据包含五种不同的 brand-color 组合,因此可以全部返回。在 返回条目限制 中,此请求贡献 1 query vector × 6 buckets × 1 = 6 个配置结果条目。
同一个 SearchAggregation.fields 列表中的多个字段会在该 aggregation 层级创建复合 bucket key。要创建父子 bucket 层级结构,请使用 嵌套 aggregation。
后续示例会重新定义 aggregation。请将更新后的对象传递给同一个 search_aggregation 参数,并重新运行 search 调用。
显示每个 bucket 中的代表性结果
当应用需要展示每个 bucket 中的实际商品时,可以包含代表性 Entity。在此示例中,Milvus 会从每个品牌 bucket 返回最多两个商品,并先按 rating 排序,再按 vector score 排序。
按如下方式配置 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"},
],
),
)
查看包含代表性命中的 bucket
以下 Brand A bucket 来自上述请求,并已序列化为 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 | 可选。为该聚合层级配置代表性 Entity。如果省略,bucket.hits 为空,且每个 key 的候选预算默认为 1。 |
TopHits.size | 从每个选中的 bucket 返回最多两个代表性 Entity,并将整个聚合树中每个 key 的候选预算设置为 2。 |
TopHits.sort | 使用列出的条件对每个 bucket 内的 Entity 排序。 |
当应用需要代表性 Entity,或计数和指标需要更宽的每 key 候选窗口时,请配置 top_hits。较大的 TopHits.size 会同时增加候选预算和 Limits 中的最大返回条目计算值。
SearchAggregation.order 对 bucket 排序,而 TopHits.sort 对每个 bucket 内保留的 Entity 排序。排序顺序不会改变为 count 和指标保留的候选项。TopHits.sort 接受受支持的可比较标量字段名以及内置 _score 字段,后者表示 ANN 相似度或距离。Milvus 会按从前到后的顺序评估 sort 条目。在此示例中,它先按 rating 从高到低对商品排序,并且只有当两个 rating 相等时才使用 _score。由于配置使用 COSINE,_score 降序会将相似度更高的商品排在前面。
metrics 或 TopHits.sort 使用的字段不必出现在 output_fields 中。Milvus 会在内部获取这些字段,但只有在 output_fields 中显式列出的字段才会包含在每个返回命中的 fields 映射中。Primary key 和 vector score 仍可通过 AggregationHit.pk 和 AggregationHit.score 获取。
每个返回的 AggregationHit 都会在 pk 中公开其 primary key,在 score 中公开 vector score,并在 fields 中公开请求的输出字段。
Group results at multiple levels
当你需要在一个 bucket 内再创建一层 bucket 时,可以使用嵌套聚合。在本示例中,Milvus 会先创建 category bucket,然后在每个 category 内创建 brand bucket。
子聚合只会接收分配给其父 bucket 的 Entity。fields 控制每一层聚合的 bucket key,而 sub_aggregation 用于创建父子层级关系。
下面的配置会创建 key 为 (running_shoes) 的 category bucket。在该父 bucket 内,子聚合会创建独立的 brand bucket,其 key 例如 (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) 的复合子 key。
以下配置实现了这一层级结构:
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"}],
),
),
)
查看嵌套 bucket 结果
以下序列化片段展示了 running_shoes 父 bucket 及其 Brand B 子 bucket。为简洁起见,省略了 Brand A 和 Brand C 子 bucket。
{
"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": []
}
]
}
展示的结果表示 bucket path (running_shoes) → (Brand B),而不是单个复合 bucket key (running_shoes, Brand B)。
Milvus 首先按 product_count 排序,最多选择两个 category bucket。然后,它会在每个选中的 category 内独立运行 sub_aggregation,并按 avg_rating 排序返回最多三个 brand bucket。
在上面的输出中:
- 根
running_shoesbucket 在其子复合 key 中包含四个保留候选项。其metrics包含根级别的avg_price和product_count值。 - 根 bucket 的
sub_groups列表包含子 brand bucket。展示的 Brand B bucket 包含一个保留候选项,以及它自己的avg_rating和brand_count值。 - 根 bucket 的
hits列表为空,因为根聚合未配置top_hits。Brand B 子 bucket 包含一个代表性 hit,因为top_hits是在sub_aggregation中配置的。
FAQ
bucket count 和 metric 的准确性如何?
Search Aggregation 汇总保留下来的 ANN 候选结果。它不会对整个 Collection 执行 aggregation。
候选保留有两个近似阶段。ANN search 可能遗漏 Collection 中相关的 Entity,grouping 阶段会为每个完整 composite key 最多保留 TopHits.size 个排名最高的候选结果。如果没有任何层级配置 top_hits,这个按 key 的限制为 1。
例如,假设某个 Collection 包含 5,000 个 Brand A 产品,其中许多与 vector query 相关。如果 aggregation 使用 TopHits(size=4),Brand A bucket 对于一个完整 composite key 最多只能保留 4 个候选结果。其 count 和指标描述的是这些保留下来的候选结果,而不是所有相关的 Brand A 产品,也不是 Collection 中全部 5,000 个 Entity。
当 order 使用 metric alias 时,近似带来的影响最明显。search recall 的变化可能改变 metric 值,进而改变哪些 bucket 能进入 SearchAggregation.size 范围。Nested aggregation 会放大这种影响,因为每个子层级都基于其父 bucket 中可用的 Entity 运行。
如果你需要对每个匹配 Entity 获取精确统计信息,请使用 exact query aggregation workflow,而不是 Search Aggregation。
How does Search Aggregation differ from Grouping Search?
根据应用所需的主要结果形态进行选择:
| 主要需求 | 推荐使用 | 需要消费的响应 |
|---|---|---|
| 返回标准的按排名排序的 Entity 列表,并减少 grouping 字段中的重复值 | Grouping Search | 每个查询向量对应的扁平 search hits |
| 以 bucket 形式检查或比较分组,并包含 key、count、metric、排序、代表性 hits 或子 bucket | Search Aggregation | result.agg_buckets 中的 AggregationBucket 对象 |
即使 Search Aggregation 配置了 top_hits,其主要响应仍然是 bucket tree。当应用已经处理普通 search hits,并且主要希望提升结果多样性时,Grouping Search 仍然适用。
这些 API 互斥。如果在同一个请求中将 search_aggregation 与 group_by_field 或 group_by_fields 组合使用,PyMilvus 会抛出 ParamError。