使用 StructArray 進行篩選搜尋

請使用此頁面,為 StructArray 欄位的向量搜尋新增標量篩選功能。StructArray 篩選分為兩個層級:列層級篩選用於選取父實體,而元素層級篩選則用於限制哪些 Struct 元素會參與元素層級的向量搜尋。

本頁面使用來自「建立 StructArray 欄位」中的tech_articles 集合。該集合包含一個名為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 篩選器。頂層篩選器可由整個混合搜尋共用。若需元素層級的限制條件,應將 `element_filter ` 附加至需要元素層級限制的 StructArray 元素層級請求上。

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 ` 代替 `element_filter(chunks, $[section] == "index")` 等 `StructArray` 運算子語法。

  • 僅需進行列級篩選時卻使用 `element_filter `。若僅需選取實體,請改用 `MATCH_ANY `。

  • 預期 `MATCH_* ` 會返回元素偏移量。這些運算子僅用於選取實體,本身並不會識別出單一符合條件的元素。

  • 撰寫如$[has_code] 這類未加修飾的布林謂詞。請改用如$[has_code] == true 這類明確的比較運算子。

  • 將 `element_filter ` 置於同一篩選表達式中頂層判別式的前方。

下一步

  1. 若要檢視完整的 StructArray 篩選語法,請參閱《StructArray 運算子》。

  2. 若要先執行未過濾的向量搜尋,請參閱《使用 StructArray 進行基本向量搜尋》

  3. 若要為常用 StructArray 篩選條件建立標量索引,請參閱《索引 StructArray 欄位》。

  4. 若要查看特定版本的篩選與搜尋限制,請參閱《StructArray 限制》