使用 StructArray 进行混合搜索

使用本页面可将 StructArray 向量搜索与其他向量搜索结合,形成一个混合搜索请求。StructArray 混合搜索可返回实体级结果或元素级结果,具体取决于您组合的AnnSearchRequest 对象。

本页面使用来自“创建 StructArray 字段”中的 tech_articles Collection。该 Collection 包含一个名为title_vector 的顶级向量字段,以及一个名为chunks 的 StructArray 字段。chunks[emb_list_vector] 子字段已为 EmbeddingList 搜索建立索引,而chunks[emb] 已为元素级搜索建立索引。

混合搜索如何应用于 StructArray

AnnSearchRequest 组合最终候选范围结果行为element_scope
Collection 级向量字段 + StructArray 的 EmbeddingList 子字段实体级别最终候选项以主键为键。请勿使用。
Collection级向量字段 + StructArray 元素级子字段实体级别元素级命中结果会在混合重新排序之前折叠为实体级候选结果。StructArray 元素级AnnSearchRequest 上的可选折叠配置。
同一 StructArray 字段下的多个元素级子字段元素级别最终候选结果以主键加上 Struct 元素偏移量作为键。请勿使用。
位于不同 StructArray 字段下的元素级子字段实体级别元素偏移量不共享标识,因此每个 StructArray 元素级别的AnnSearchRequest 都会在重新排序之前被折叠。每个 StructArray 元素级AnnSearchRequest 上的可选折叠配置。

警告

仅在非同结构元素级混合搜索中,使用 `element_scope ` 来配置 StructArray 元素级 `AnnSearchRequest ` 对象的折叠。请勿将其用于 EmbeddingList 请求、Collection 级向量请求或同 StructArray 元素级混合搜索。

开始之前

在运行混合搜索之前,请准备好Collection、数据和索引。

要求详细信息
StructArray 字段Collection 包含一个 StructArray 字段,例如chunks
向量子场请为 EmbeddingList 搜索和元素级搜索分别使用独立的向量字段。
索引chunks[emb_list_vector] 使用MAX_SIM* 度量。chunks[emb] 使用常规向量度量,例如COSINEIPL2
Rerankers请选择一种混合Reranker,例如RRFRanker 或您的应用程序支持的其他Rerankers。

有关索引设置,请参阅《索引 StructArray 字段》。

使用 EmbeddingList 请求运行混合搜索

在混合搜索中,针对 StructArray 向量子字段的 EmbeddingList 搜索属于实体级搜索。其行为类似于实体级向量搜索请求,不会返回单个匹配的 Struct 元素偏移量。

from pymilvus import AnnSearchRequest, MilvusClient, RRFRanker
from pymilvus.client.embedding_list import EmbeddingList

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

query_vector = [0.19, 0.24, 0.30, 0.37]

query_list = EmbeddingList()
query_list.add([0.12, 0.21, 0.32, 0.44])
query_list.add([0.18, 0.23, 0.29, 0.36])

title_req = AnnSearchRequest(
    data=[query_vector],
    anns_field="title_vector",
    limit=10,
)

chunk_list_req = AnnSearchRequest(
    data=[query_list],
    anns_field="chunks[emb_list_vector]",
    limit=10,
)

results = client.hybrid_search(
    collection_name="tech_articles",
    reqs=[title_req, chunk_list_req],
    ranker=RRFRanker(),
    limit=5,
    output_fields=[
        "doc_id",
        "title",
        "category",
        "chunks[text]",
        "chunks[section]",
    ],
)

在此示例中,两个AnnSearchRequest 对象均生成实体级候选结果。最终结果以父实体的主键作为键。请勿在 EmbeddingList 请求中添加element_scope

当所有 `AnnSearchRequest ` 对象均针对同一 `StructArray` 字段下的元素级向量子字段时,混合搜索可通过重新排序保留元素级候选结果。这是唯一一种最终结果仍保持为元素级的 `StructArray` 混合模式。

以下示例假设chunks 的 StructArray 字段包含两个元素级向量子字段:chunks[emb]chunks[code_emb] ,且两者均使用常规向量度量。

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,
    output_fields=[
        "doc_id",
        "title",
        "chunks[text]",
        "chunks[section]",
        "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"],
        )

这两个AnnSearchRequest 对象均在chunks 下搜索向量子字段。相同的基于零的偏移量指向同一个Struct元素,因此混合Reranker可以直接对元素候选项进行排序。在此模式下请勿设置element_scope ,因为不会执行实体级别的折叠。

如果混合搜索将 StructArray 元素级别的AnnSearchRequest 与 Collection 级别的向量请求、EmbeddingList 请求,或位于不同 StructArray 字段下的元素级请求混合使用,则最终的候选范围为实体级别。在这种情况下,每个 StructArray 元素级别的AnnSearchRequest 都会在混合重新排序之前被折叠为实体级别的候选项。

当需要控制同一实体中多个匹配元素的折叠方式时,请在 StructArray 元素级AnnSearchRequestparams 中使用element_scope

title_req = AnnSearchRequest(
    data=[query_vector],
    anns_field="title_vector",
    limit=10,
)

chunk_req = AnnSearchRequest(
    data=[query_vector],
    anns_field="chunks[emb]",
    param={
        "params": {
            "element_scope": {
                "collapse": {
                    "strategy": "topk_sum",
                    "topk": 3,
                },
            },
        },
    },
    limit=30,
    expr='element_filter(chunks, $[quality_score] > 0.8)',
)

results = client.hybrid_search(
    collection_name="tech_articles",
    reqs=[title_req, chunk_req],
    ranker=RRFRanker(),
    limit=5,
    output_fields=[
        "doc_id",
        "title",
        "category",
        "chunks[text]",
        "chunks[section]",
        "chunks[quality_score]",
    ],
)

在此示例中,title_req 为实体级,因此最终的混合结果也是实体级的。chunk_req 请求首先返回来自chunks[emb] 的元素命中结果,然后通过汇总同一实体的三个最佳元素得分来折叠返回的元素。如果在需要实体级折叠时省略了element_scope ,折叠策略将默认采用max

选择汇总策略

策略行为topk指标要求
max保留该实体返回的最高元素得分。不允许。任何受支持的常规向量度量。
sum将该实体的所有返回元素得分相加。不允许。仅限正相关度量,例如IPCOSINE
avg对该实体的所有返回元素得分求平均值。不允许。任何受支持的常规向量指标。
topk_sum将该实体的最佳K 返回元素得分相加。必填项,且必须为正值。仅限正相关度量,例如IPCOSINE
topk_avg对该实体返回的K 中最佳元素得分取平均值。必填,且必须为正数。任何受支持的常规向量度量。

Collapse 仅使用该 StructArray 元素级AnnSearchRequest 返回的元素命中结果。它在 ANN 搜索后不会扫描实体中的每个 Struct 元素。请将请求的limit 设置得足够高,以确保提供您希望用于折叠的元素。

添加过滤器、范围搜索和分组

当标量条件需应用于参与向量搜索的同一组 Struct 元素时,可将element_filter 附加到 StructArray 元素级别的AnnSearchRequest 上。您还可以使用顶级filter 针对hybrid_search() 设置父实体条件。

StructArray 元素级向量字段在混合搜索中支持范围搜索。请在元素级AnnSearchRequest 中添加radius ,并可选地添加range_filter 。EmbeddingList 级别的 StructArray 请求不支持范围搜索。

仅当所有AnnSearchRequest 对象均指向同一StructArray字段下的元素级向量字段,且group_by_field 必须为主键时,才支持元素级混合分组。若请求混合了集合级向量字段、不同的StructArray字段或EmbeddingList级请求,则不支持混合分组。请勿将范围搜索与分组结合使用。

解释混合结果

最终候选范围结果键偏移量行为发生条件
实体级别主键。最终结果中不包含元素偏移量。混合请求包含 Collection 级向量字段、EmbeddingList 请求,或位于不同 StructArray 字段下的元素级请求。
元素级别主键加上父级 StructArray 字段加上元素偏移量。当 API 或 SDK 公开时,可返回所选元素的偏移量。所有AnnSearchRequest 对象均为元素级,且位于同一个StructArray字段下。

限制

  • 仅将 `element_scope ` 用于 StructArray 元素级别的 `AnnSearchRequest ` 对象,这些对象在混合搜索中必须折叠为实体级别的候选结果。

  • 请勿将element_scope 用于 EmbeddingList 请求、Collection 级向量请求或同一 StructArray 元素级的混合搜索。

  • sum topk_sum 折叠策略需要正相关度量,例如 或 。请勿将其与 配合使用。IP COSINE L2

  • topk_sumtopk_avg 需要正的topk 值。其他折叠策略不得包含topk

  • EmbeddingList 级别的 StructArray 请求不支持范围搜索或分组操作。

  • 混合分组仅支持针对同一 StructArray 元素级别的混合搜索,且仅支持按主键进行。

  • 请勿将范围搜索与分组操作结合使用。

常见错误

  • 在同一 StructArray 元素级混合请求中添加element_scope 。该请求仍为元素级,不会执行实体级折叠。

  • element_scope 添加到chunks[emb_list_vector] 中。EmbeddingList搜索已经是实体级别的。

  • 假设两个 StructArray 字段共享元素偏移量。chunks 中的偏移量3 与另一个 StructArray 字段中的偏移量3 对应的是不同的元素,因此该混合请求将变为实体级。

  • 使用topk_sum 时需配合L2 。若距离度量为负值,请使用maxavgtopk_avg

  • 预期实体级混合结果在折叠后将包含所选 Struct 元素的偏移量。

后续步骤

  1. 要了解两种基本的 StructArray 向量搜索模式,请阅读《使用 StructArray 进行基本向量搜索》。

  2. 若要在混合搜索中添加标量过滤器,请参阅《使用 StructArray 进行过滤搜索》。

  3. 要了解如何在混合搜索中使用得分或距离边界,请阅读《使用 StructArray 进行范围搜索》。

  4. 要按父实体对元素级混合搜索结果进行分组,请阅读《使用 StructArray 进行分组搜索》。

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