Gefilterte Suche mit StructArray

Verwenden Sie diese Seite, um die Vektorsuche in StructArray-Feldern um eine skalare Filterung zu erweitern. Die StructArray-Filterung erfolgt auf zwei Ebenen: Filter auf Zeilenebene wählen übergeordnete Entitäten aus, während Filter auf Elementebene festlegen, welche Struct-Elemente an der Vektorsuche auf Elementebene teilnehmen.

Diese Seite verwendet die Sammlung „ tech_articles “ aus dem Abschnitt „Erstellen eines StructArray-Feldes“. Die Sammlung enthält ein StructArray-Feld namens „ chunks “ mit skalaren Unterfeldern wie „ section “, „ page “, „ quality_score “ und „ has_code “ sowie Vektor-Unterfeldern für die Suche.

Wählen Sie einen Filtertyp

ZielVerwendungVerhalten des Ergebnisses
Filtern nach einem Skalarfeld der obersten Ebene, z. B. category.Regulärer Filterausdruck.Wählt übergeordnete Entitäten vor oder während der Suche aus.
Beschränkt die Vektorsuche auf Elementebene auf Struct-Elemente, die den skalaren Bedingungen entsprechen.element_filter.Durchsucht nur übereinstimmende Struct-Elemente und kann Offsets der übereinstimmenden Elemente zurückgeben.
Wählt Entitäten danach aus, ob einige, alle oder eine bestimmte Anzahl von Struct-Elementen einem Prädikat entsprechen.MATCH_ANY, MATCH_ALL, MATCH_LEAST, MATCH_MOST oder MATCH_EXACT.Filterung auf Zeilenebene. Diese Operatoren geben selbst keine Offsets zurück.

Auf dieser Seite wird erläutert, wie StructArray-Filter in Such-Workflows verwendet werden. Die vollständigen Syntaxregeln, unterstützte Prädikattypen und die Liste der nicht unterstützten Prädikate finden Sie unter „StructArray-Operatoren“.

Filtern nach Feldern der obersten Ebene

Verwenden Sie reguläre Filterausdrücke, wenn die Bedingung zur übergeordneten Entität gehört und nicht zu einem einzelnen Struct-Element. Dies funktioniert sowohl bei der EmbeddingList-Suche als auch bei der Suche auf Elementebene.

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]",
    ],
)

Der obige Filter wählt nur Entitäten aus, deren Feld „ category “ auf oberster Ebene den Wert „ "search" “ hat. Er identifiziert kein einzelnes übereinstimmendes Struct-Element.

Verwenden Sie „ element_filter(structArrayField, predicate) “, wenn die skalaren Bedingungen für dasselbe Struct-Element gelten müssen, das an der Vektorsuche auf Elementebene beteiligt ist. Verwenden Sie innerhalb des Prädikats „ $[subfield] “, um auf skalare Unterfelder des aktuellen Struct-Elements zu verweisen.

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"],
        )

In diesem Beispiel wählt das Prädikat oberster Ebene „ category == "search" “ Kandidatenentitäten aus, und „ element_filter “ beschränkt die Vektorsuche auf Elementebene auf Blöcke, in denen „ section “, „ quality_score “ und „ has_code “ alle im selben Struct-Element übereinstimmen.

Warnung

Wenn Sie ein Prädikat der obersten Ebene mit „ element_filter “ kombinieren, platzieren Sie „ element_filter “ am Ende des Ausdrucks. Ein Filterausdruck darf nur ein „ element_filter “ enthalten, und Sie können „ element_filter “ oder „ MATCH_* “ nicht innerhalb eines anderen „StructArray“-Operators verschachteln.

Entitäten mit MATCH-Operatoren filtern

Verwenden Sie „ MATCH_* “-Operatoren, wenn der Filter anhand der Struct-Elemente entscheiden soll, ob eine übergeordnete Entität die Bedingungen erfüllt. Diese Operatoren sind Filter auf Zeilenebene: Sie wählen Entitäten aus, geben jedoch selbst keine Element-Offsets zurück.

OperatorVerwenden Sie ihn, wennBeispiel
MATCH_ANYMindestens ein Struct-Element muss das Prädikat erfüllen.MATCH_ANY(chunks, $[section] == "index")
MATCH_ALLAlle Struct-Elemente müssen das Prädikat erfüllen.MATCH_ALL(chunks, $[quality_score] > 0.5)
MATCH_LEASTMindestens N -Struktur-Elemente müssen das Prädikat erfüllen.MATCH_LEAST(chunks, $[has_code] == true, threshold=2)
MATCH_MOSTHöchstens N Struct-Elemente müssen das Prädikat erfüllen.MATCH_MOST(chunks, $[section] == "appendix", threshold=1)
MATCH_EXACTGenau N Struct-Elemente müssen das Prädikat erfüllen.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]",
    ],
)

Verwenden Sie hier „ MATCH_ANY “, da das Suchergebnis von „EmbeddingList“ auf Entitätsebene erfolgt. Der Filter erfordert, dass mindestens ein Chunk in der Entität ein „ "index" “-Chunk mit hoher Qualität ist, das Suchergebnis selbst repräsentiert jedoch weiterhin die übergeordnete Entität.

Wenden Sie in der hybriden Suche „StructArray“-Filter dort an, wo die Bedingung wirksam werden soll. Ein Filter auf oberster Ebene kann von der gesamten hybriden Suche gemeinsam genutzt werden. Ein „ element_filter “ sollte an die „StructArray“-Anfrage auf Elementebene angehängt werden, die Einschränkungen auf Elementebene erfordert.

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]",
    ],
)

Das Argument „ filter “ wendet die Entitätsbedingung der obersten Ebene an, während „ expr “ auf „ chunk_req “ nur die Vektorabfrage auf StructArray-Ebene einschränkt. Informationen zu unterstützten Kombinationen der hybriden Suche und versionsspezifischen Einschränkungen finden Sie unter „Hybride Suche mit StructArray“ und „StructArray-Einschränkungen“.

Zusammenfassung der Prädikatunterstützung

Verwenden Sie skalare Unterfelder in StructArray-Prädikaten. Vektor-Unterfelder sind keine Eingaben für skalare Prädikate.

UnterfeldtypTypische Prädikatbeispiele
BOOL$[has_code] == true, !($[has_code] == true)
Ganzzahltypen$[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%"
Vektor-TeilfelderWerden nicht als skalare Prädikate für „ $[...] “ unterstützt. Verwenden Sie stattdessen Vektor-Teilfelder über die Vektorsuche.

Für nicht unterstützte Fälle wie JSON-Pfade, Array-Container-Funktionen, Textabgleichsfunktionen, Null-Prädikate auf ` $[...]`, Geometrie-Funktionen, `Timestamptz`-Ausdrücke und generische Funktionsaufrufe siehe „StructArray-Operatoren“.

Häufige Fehler

  • Verwendung von „ $[subfield] “ außerhalb von „ element_filter “ oder „ MATCH_* “.

  • Verwendung von „ chunks.section “ anstelle der StructArray-Operatorsyntax wie beispielsweise „ element_filter(chunks, $[section] == "index") “.

  • Verwendung von „ element_filter “, wenn nur eine Filterung auf Zeilenebene erforderlich ist. Verwenden Sie stattdessen „ MATCH_ANY “, wenn Sie lediglich Entitäten auswählen müssen.

  • Die Erwartung, dass ` MATCH_* ` Element-Offsets zurückgibt. Diese Operatoren wählen Entitäten aus und identifizieren selbst kein einzelnes übereinstimmendes Element.

  • Das Schreiben von bloßen booleschen Prädikaten wie „ $[has_code] “. Verwenden Sie explizite Vergleiche wie „ $[has_code] == true “.

  • element_filter “ vor einem Prädikat der obersten Ebene im selben Filterausdruck platzieren.

Nächste Schritte

  1. Um die vollständige StructArray-Filtersyntax nachzulesen, lesen Sie „StructArray-Operatoren“.

  2. Um zunächst ungefilterte Vektorsuchen durchzuführen, lesen Sie „Grundlegende Vektorsuche mit StructArray“.

  3. Informationen zum Erstellen von Skalarindizes für häufig verwendete StructArray-Filter finden Sie unter „StructArray-Felder indizieren“.

  4. Informationen zu versionsspezifischen Filter- und Suchbeschränkungen finden Sie unter „StructArray-Beschränkungen“.