使用 StructArray 进行分组搜索
使用本页面可按父实体对 StructArray 的元素级搜索结果进行分组。当多个 Struct 元素匹配查询条件时,元素级搜索可能会返回来自同一实体的多个匹配结果。分组功能会将这些元素级匹配结果合并,确保每个父实体最多只出现一次。
本页面使用“创建 StructArray 字段”中的tech_articles Collection。该 Collection 包含一个名为chunks 的 StructArray 字段。其chunks[emb] 向量子字段已针对元素级搜索进行了索引,并采用常规向量度量标准。
分组如何应用于 StructArray
| 搜索模式 | 分组行为 | 结果行为 |
|---|---|---|
| EmbeddingList 搜索 | 不支持。 | 不适用。 |
| 元素级搜索 | 支持按主键分组。 | 每个父实体最多返回一个结果。元素级元数据得以保留,因此当 API 或 SDK 公开时,可以返回所选元素的索引或偏移量。 |
| 混合搜索 | 仅当所有子搜索都针对同一 StructArray 字段下的元素级向量字段时才受支持。 | 在最终结果处理之前,元素级子搜索会按主键进行分组。 |
当未分组的元素级搜索返回过多重复的父实体时,请使用分组功能。若希望将每个匹配的 Struct 元素作为单独的命中结果,请使用不带 `group_by_field`的 StructArray 基本向量搜索。
开始之前
在运行分组搜索之前,请准备好Collection、数据和索引。
| 要求 | 详细信息 |
|---|---|
| 元素级向量子字段 | 请使用 StructArray 向量子字段(例如chunks[emb] ),并使用常规向量度量进行索引。 |
| 常规向量查询 | 请使用常规查询向量,而非EmbeddingList 。 |
| 主键分组 | 将Collection主键设置为group_by_field ,例如doc_id 。 |
| 不使用范围参数 | 请勿将分组搜索与范围搜索参数(如radius 或range_filter )结合使用。 |
有关索引设置,请参阅“Index StructArray Fields”。
运行分组元素级搜索
以下示例首先搜索各个数据块,然后根据父实体的主键对元素匹配结果进行分组。
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"` 时,每个父实体最多出现一次。分组会保留元素级元数据,因此当 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] ,且两者均使用常规向量度量进行索引。
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 元素的从零开始的索引位置。 |
| 重复的主键 | 按主键分组时不应出现此情况。 |
limit | 适用于按父实体分组的结果。 |
限制
分组搜索仅适用于元素级 StructArray 向量搜索。EmbeddingList 搜索和 EmbeddingList 级混合搜索不支持按组分组。
请将主键用作
group_by_field。StructArray 元素级分组并非针对任意标量字段的通用分组操作。请勿将分组搜索与范围搜索结合使用。
请勿在分组搜索中使用
EmbeddingList查询或MAX_SIM*度量。仅当所有子搜索都针对同一 StructArray 字段下的元素级向量字段时,才支持混合分组。
当混合搜索混合了普通向量字段、不同的 StructArray 字段或 EmbeddingList 级请求时,不支持混合分组。
常见错误
将分组与
chunks[emb_list_vector]结合使用,而该字段专用于EmbeddingList搜索。按非主键标量字段进行分组。
按多个字段进行分组。元素级 StructArray 分组仅支持主键分组。
期望分组结果能代表每个匹配的 Struct 元素。分组每个父实体最多返回一个结果。
假设按元素级别分组的搜索会重新计算 EmbeddingList 风格的
MAX_SIM*得分。分组操作会合并元素级别的匹配结果,但不会改变评分模型。将
group_by_field与radius或range_filter结合使用。
下一步
若要先了解未分组的元素级搜索,请阅读《使用 StructArray 进行基础向量搜索》。
若要为分组搜索添加标量过滤器,请阅读《使用 StructArray 进行过滤搜索》。
若要使用得分或距离边界代替分组,请阅读《使用 StructArray 进行范围搜索》。
要查看 StructArray 的搜索限制,请阅读《StructArray 限制》。