使用 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
不使用范围参数请勿将分组搜索与范围搜索参数(如radiusrange_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_fieldradiusrange_filter 结合使用。

下一步

  1. 若要先了解未分组的元素级搜索,请阅读《使用 StructArray 进行基础向量搜索》。

  2. 若要为分组搜索添加标量过滤器,请阅读《使用 StructArray 进行过滤搜索》。

  3. 若要使用得分或距离边界代替分组,请阅读《使用 StructArray 进行范围搜索》。

  4. 要查看 StructArray 的搜索限制,请阅读《StructArray 限制》。

翻译自DeepL

想要更快、更简单、更好用的 Milvus SaaS服务 ?

Zilliz Cloud是基于Milvus的全托管向量数据库,拥有更高性能,更易扩展,以及卓越性价比

免费试用 Zilliz Cloud
反馈

此页对您是否有帮助?