使用 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] 使用常规向量度量,例如COSINE 、IP 或L2 。 |
| 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 。
运行同一 StructArray 的元素级混合搜索
当所有 `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 元素级AnnSearchRequest 的params 中使用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 | 将该实体的所有返回元素得分相加。 | 不允许。 | 仅限正相关度量,例如IP 或COSINE 。 |
avg | 对该实体的所有返回元素得分求平均值。 | 不允许。 | 任何受支持的常规向量指标。 |
topk_sum | 将该实体的最佳K 返回元素得分相加。 | 必填项,且必须为正值。 | 仅限正相关度量,例如IP 或COSINE 。 |
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 元素级的混合搜索。sumtopk_sum折叠策略需要正相关度量,例如 或 。请勿将其与 配合使用。IPCOSINEL2topk_sum且topk_avg需要正的topk值。其他折叠策略不得包含topk。EmbeddingList 级别的 StructArray 请求不支持范围搜索或分组操作。
混合分组仅支持针对同一 StructArray 元素级别的混合搜索,且仅支持按主键进行。
请勿将范围搜索与分组操作结合使用。
常见错误
在同一 StructArray 元素级混合请求中添加
element_scope。该请求仍为元素级,不会执行实体级折叠。将
element_scope添加到chunks[emb_list_vector]中。EmbeddingList搜索已经是实体级别的。假设两个 StructArray 字段共享元素偏移量。
chunks中的偏移量3与另一个 StructArray 字段中的偏移量3对应的是不同的元素,因此该混合请求将变为实体级。使用
topk_sum时需配合L2。若距离度量为负值,请使用max、avg或topk_avg。预期实体级混合结果在折叠后将包含所选 Struct 元素的偏移量。
后续步骤
要了解两种基本的 StructArray 向量搜索模式,请阅读《使用 StructArray 进行基本向量搜索》。
若要在混合搜索中添加标量过滤器,请参阅《使用 StructArray 进行过滤搜索》。
要了解如何在混合搜索中使用得分或距离边界,请阅读《使用 StructArray 进行范围搜索》。
要按父实体对元素级混合搜索结果进行分组,请阅读《使用 StructArray 进行分组搜索》。
要查看 StructArray 的搜索限制,请阅读《StructArray 限制》。