使用 StructArray 进行过滤搜索
使用本页面可在 StructArray 字段的向量搜索中添加标量过滤。StructArray 过滤分为两个层次:行级过滤器用于选择父实体,而元素级过滤器则用于限定哪些 Struct 元素参与元素级向量搜索。
本页面使用“创建 StructArray 字段”中的tech_articles Collection。该 Collection 包含一个名为chunks 的 StructArray 字段,其中包含section 、page 、quality_score 和has_code 等标量子字段,以及用于搜索的向量字段。
选择过滤器类型
| 目标 | 用途 | 结果行为 |
|---|---|---|
按顶级标量字段(例如category )进行过滤。 | 常规筛选表达式。 | 在搜索之前或期间选择父实体。 |
| 将元素级向量搜索限制为符合标量条件的 Struct 元素。 | element_filter. | 仅搜索匹配的 Struct 元素,并可返回匹配元素的偏移量。 |
| 根据任意、全部或特定数量的 Struct 元素是否匹配谓词来选择实体。 | MATCH_ANY、MATCH_ALL 、MATCH_LEAST 、MATCH_MOST 或MATCH_EXACT 。 | 行级过滤。这些操作符本身不会返回偏移量。 |
本页说明如何在搜索工作流中使用 StructArray 过滤器。有关完整的语法规则、支持的谓词类型以及不支持的谓词矩阵,请参阅StructArray 操作符。
按顶级字段过滤
当条件属于父实体而非单个 Struct 元素时,请使用常规过滤表达式。这适用于 EmbeddingList 搜索和元素级搜索。
from pymilvus import MilvusClient
from pymilvus.client.embedding_list import EmbeddingList
client = MilvusClient(
uri="http://localhost:19530",
token="root:Milvus",
)
query = EmbeddingList()
query.add([0.12, 0.21, 0.32, 0.44])
query.add([0.18, 0.23, 0.29, 0.36])
results = client.search(
collection_name="tech_articles",
data=[query],
anns_field="chunks[emb_list_vector]",
filter='category == "search"',
limit=3,
output_fields=[
"doc_id",
"title",
"category",
"chunks[text]",
"chunks[section]",
],
)
上述过滤器仅选择其顶级category 字段值为"search" 的实体。它不会识别出单个匹配的Struct元素。
过滤元素级向量搜索
当标量条件必须应用于参与元素级向量搜索的同一 Struct 元素时,请使用element_filter(structArrayField, predicate) 。在谓词内部,使用$[subfield] 来引用当前 Struct 元素的标量子字段。
query_vector = [0.19, 0.24, 0.30, 0.37]
filter_expr = (
'category == "search" && '
'element_filter(chunks, '
'$[section] == "index" && '
'$[quality_score] > 0.9 && '
'$[has_code] == true)'
)
results = client.search(
collection_name="tech_articles",
data=[query_vector],
anns_field="chunks[emb]",
filter=filter_expr,
limit=5,
output_fields=[
"doc_id",
"title",
"chunks[text]",
"chunks[section]",
"chunks[page]",
"chunks[quality_score]",
"chunks[has_code]",
],
)
for hits in results:
for hit in hits:
print(
"doc_id:", hit["id"],
"distance:", hit["distance"],
"offset:", hit.get("offset"),
"entity:", hit["entity"],
)
在此示例中,顶级谓词category == "search" 用于选择候选实体,而element_filter 将元素级向量搜索限制在满足以下条件的块中:section 、quality_score 和has_code 在同一个 Struct 元素中均匹配。
警告
当将顶级谓词与element_filter 结合使用时,请将element_filter 置于表达式的末尾。一个过滤表达式中只能包含一个element_filter ,且不能将element_filter 或MATCH_* 嵌套在另一个StructArray操作符内部。
使用 MATCH 操作符过滤实体
当筛选需根据父实体的 Struct 元素来决定其是否符合条件时,请使用MATCH_* 操作符。这些操作符属于行级筛选:它们用于选择实体,但本身不会返回元素偏移量。
| 操作符 | 适用场景 | 示例 |
|---|---|---|
MATCH_ANY | 至少有一个 Struct 元素必须满足谓词。 | MATCH_ANY(chunks, $[section] == "index") |
MATCH_ALL | 所有 Struct 元素都必须满足谓词。 | MATCH_ALL(chunks, $[quality_score] > 0.5) |
MATCH_LEAST | 至少有N 个 Struct 元素必须满足该谓词。 | MATCH_LEAST(chunks, $[has_code] == true, threshold=2) |
MATCH_MOST | 至多有N 个Struct元素必须满足该谓词。 | MATCH_MOST(chunks, $[section] == "appendix", threshold=1) |
MATCH_EXACT | 必须有恰好N 个Struct元素满足该谓词。 | MATCH_EXACT(chunks, $[section] == "summary", threshold=1) |
filter_expr = (
'category == "search" && '
'MATCH_ANY(chunks, $[section] == "index" && $[quality_score] > 0.9)'
)
results = client.search(
collection_name="tech_articles",
data=[query],
anns_field="chunks[emb_list_vector]",
filter=filter_expr,
limit=3,
output_fields=[
"doc_id",
"title",
"category",
"chunks[text]",
"chunks[section]",
"chunks[quality_score]",
],
)
此处使用MATCH_ANY ,因为EmbeddingList的搜索结果是实体级别的。该过滤器要求该实体中至少有一个片段是高质量的"index" 片段,但搜索结果本身仍代表父实体。
在混合搜索中使用过滤器
在混合搜索中,应在条件需生效的位置应用 StructArray 过滤器。顶级过滤器可供整个混合搜索共享。对于需要元素级约束的 StructArray 元素级请求,应附加element_filter 。
from pymilvus import AnnSearchRequest, RRFRanker
query_vector = [0.19, 0.24, 0.30, 0.37]
title_req = AnnSearchRequest(
data=[query_vector],
anns_field="title_vector",
limit=10,
)
chunk_req = AnnSearchRequest(
data=[query_vector],
anns_field="chunks[emb]",
limit=10,
expr='element_filter(chunks, $[section] == "index" && $[quality_score] > 0.9)',
)
results = client.hybrid_search(
collection_name="tech_articles",
reqs=[title_req, chunk_req],
ranker=RRFRanker(),
filter='category == "search"',
limit=5,
output_fields=[
"doc_id",
"title",
"category",
"chunks[text]",
"chunks[section]",
"chunks[quality_score]",
],
)
filter 参数应用顶级实体条件,而chunk_req 上的expr 仅对StructArray元素级向量请求进行约束。有关受支持的混合搜索组合及特定版本的限制,请参阅《基于StructArray的混合搜索》和《StructArray限制》。
谓词支持摘要
在 StructArray 谓词中使用向量子字段。向量子字段不能作为标量谓词的输入。
| 子字段类型 | 典型谓词示例 |
|---|---|
BOOL | $[has_code] == true,!($[has_code] == true) |
| 整数类型 | $[page] >= 2,$[page] in [1, 2, 3] |
FLOAT,DOUBLE | $[quality_score] > 0.9,0.7 < $[quality_score] < 0.95 |
VARCHAR | $[section] == "index",$[text] like "range%" |
| 向量子场 | 不支持作为$[...] 标量谓词的输入。请改用向量搜索来处理向量子字段。 |
对于不支持的情况,例如 JSON 路径、数组容器函数、文本匹配函数、针对$[...] 的 null 谓词、几何函数、Timestamptz 表达式以及泛型函数调用,请参阅StructArray 操作符。
常见错误
在
element_filter或MATCH_*之外使用$[subfield]。使用
chunks.section代替StructArray操作符语法(如element_filter(chunks, $[section] == "index"))。仅需行级过滤时却使用 `
element_filter`。若仅需选择实体,请改用 `MATCH_ANY`。期望 `
MATCH_*` 返回元素偏移量。这些操作符用于选择实体,本身并不能识别出单个匹配元素。编写诸如
$[has_code]之类的裸布尔谓词。请使用显式比较,例如$[has_code] == true。在同一过滤表达式中,将 `
element_filter` 置于顶级谓词之前。
后续步骤
要查看完整的 StructArray 过滤语法,请阅读《StructArray 操作符》。
若要先运行未过滤的向量搜索,请阅读《使用 StructArray 进行基本向量搜索》。
要为常用 StructArray 过滤器创建标量索引,请参阅《索引 StructArray 字段》。
要查看特定版本的过滤和搜索限制,请参阅《StructArray 限制》。