使用 StructArray 进行过滤搜索

使用本页面可在 StructArray 字段的向量搜索中添加标量过滤。StructArray 过滤分为两个层次:行级过滤器用于选择父实体,而元素级过滤器则用于限定哪些 Struct 元素参与元素级向量搜索。

本页面使用“创建 StructArray 字段”中的tech_articles Collection。该 Collection 包含一个名为chunks 的 StructArray 字段,其中包含sectionpagequality_scorehas_code 等标量子字段,以及用于搜索的向量字段。

选择过滤器类型

目标用途结果行为
按顶级标量字段(例如category )进行过滤。常规筛选表达式。在搜索之前或期间选择父实体。
将元素级向量搜索限制为符合标量条件的 Struct 元素。element_filter.仅搜索匹配的 Struct 元素,并可返回匹配元素的偏移量。
根据任意、全部或特定数量的 Struct 元素是否匹配谓词来选择实体。MATCH_ANYMATCH_ALLMATCH_LEASTMATCH_MOSTMATCH_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 将元素级向量搜索限制在满足以下条件的块中:sectionquality_scorehas_code 在同一个 Struct 元素中均匹配。

警告

当将顶级谓词与element_filter 结合使用时,请将element_filter 置于表达式的末尾。一个过滤表达式中只能包含一个element_filter ,且不能将element_filterMATCH_* 嵌套在另一个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_filterMATCH_* 之外使用$[subfield]

  • 使用chunks.section 代替StructArray操作符语法(如element_filter(chunks, $[section] == "index") )。

  • 仅需行级过滤时却使用 `element_filter `。若仅需选择实体,请改用 `MATCH_ANY `。

  • 期望 `MATCH_* ` 返回元素偏移量。这些操作符用于选择实体,本身并不能识别出单个匹配元素。

  • 编写诸如$[has_code] 之类的裸布尔谓词。请使用显式比较,例如$[has_code] == true

  • 在同一过滤表达式中,将 `element_filter ` 置于顶级谓词之前。

后续步骤

  1. 要查看完整的 StructArray 过滤语法,请阅读《StructArray 操作符》。

  2. 若要先运行未过滤的向量搜索,请阅读《使用 StructArray 进行基本向量搜索》。

  3. 要为常用 StructArray 过滤器创建标量索引,请参阅《索引 StructArray 字段》。

  4. 要查看特定版本的过滤和搜索限制,请参阅《StructArray 限制》

翻译自DeepL

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

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

免费试用 Zilliz Cloud
反馈

此页对您是否有帮助?