Recherche filtrée avec StructArray

Utilisez cette page pour ajouter un filtrage scalaire à la recherche vectorielle sur les champs StructArray. Le filtrage StructArray comporte deux niveaux : les filtres au niveau des lignes sélectionnent les entités parentes, tandis que les filtres au niveau des éléments restreignent les éléments Struct participant à la recherche vectorielle au niveau des éléments.

Cette page utilise la collection « tech_articles » issue de la section «Créer un champ StructArray». Cette collection comporte un champ StructArray nommé « chunks », avec des sous-champs scalaires tels que « section », « page », « quality_score » et « has_code », ainsi que des sous-champs vectoriels destinés à la recherche.

Choisissez un type de filtre

ObjectifUtilisationComportement du résultat
Filtrer selon un champ scalaire de niveau supérieur, tel que category.Expression de filtrage standard.Sélectionne les entités parentes avant ou pendant la recherche.
Limite la recherche vectorielle au niveau des éléments aux éléments Struct qui répondent aux conditions scalaires.element_filter.Recherche uniquement les éléments Struct correspondants et peut renvoyer les décalages des éléments correspondants.
Sélectionne les entités selon qu’aucun, tous ou un nombre spécifique d’éléments Struct correspondent à un prédicat.MATCH_ANY, MATCH_ALL, MATCH_LEAST, MATCH_MOST ou MATCH_EXACT.Filtrage au niveau des lignes. Ces opérateurs ne renvoient pas d’offset en eux-mêmes.

Cette page explique comment utiliser les filtres StructArray dans les workflows de recherche. Pour connaître l’ensemble des règles de syntaxe, les types de prédicats pris en charge et la matrice des prédicats non pris en charge, consultez la section Opérateurs StructArray.

Filtrage par champs de niveau supérieur

Utilisez des expressions de filtrage classiques lorsque la condition s’applique à l’entité parente, et non à un élément Struct individuel. Cela fonctionne aussi bien avec la recherche EmbeddingList qu’avec la recherche au niveau des éléments.

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

Le filtre ci-dessus sélectionne uniquement les entités dont le champ de niveau supérieur « category » est « "search" ». Il n’identifie pas un élément Struct correspondant en particulier.

Utilisez ` element_filter(structArrayField, predicate) ` lorsque les conditions scalaires doivent s’appliquer au même élément Struct participant à la recherche vectorielle au niveau des éléments. À l’intérieur du prédicat, utilisez ` $[subfield] ` pour faire référence aux sous-champs scalaires de l’élément Struct actuel.

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

Dans cet exemple, le prédicat de niveau supérieur category == "search" sélectionne les entités candidates, et element_filter restreint la recherche vectorielle au niveau des éléments aux segments où section, quality_score et has_code correspondent tous dans le même élément Struct.

Avertissement

Lorsque vous combinez un prédicat de niveau supérieur avec element_filter, placez element_filter à la fin de l’expression. Une expression de filtrage ne peut contenir qu’un seul element_filter, et vous ne pouvez pas imbriquer element_filter ou MATCH_* à l’intérieur d’un autre opérateur StructArray.

Filtrer des entités à l’aide d’opérateurs MATCH

Utilisez les opérateurs « MATCH_* » lorsque le filtre doit déterminer si une entité parente est éligible en fonction de ses éléments Struct. Ces opérateurs sont des filtres au niveau des lignes : ils sélectionnent des entités, mais ne renvoient pas d’offset d’élément en eux-mêmes.

OpérateurÀ utiliser lorsqueExemple
MATCH_ANYAu moins un élément Struct doit satisfaire le prédicat.MATCH_ANY(chunks, $[section] == "index")
MATCH_ALLTous les éléments Struct doivent satisfaire le prédicat.MATCH_ALL(chunks, $[quality_score] > 0.5)
MATCH_LEASTAu moins N éléments de la structure doivent satisfaire le prédicat.MATCH_LEAST(chunks, $[has_code] == true, threshold=2)
MATCH_MOSTAu plus N éléments de la structure doivent satisfaire le prédicat.MATCH_MOST(chunks, $[section] == "appendix", threshold=1)
MATCH_EXACTN éléments Struct exactement doivent satisfaire le prédicat.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]",
    ],
)

Utilisez « MATCH_ANY » ici car le résultat de recherche EmbeddingList est au niveau de l’entité. Le filtre exige qu’au moins un fragment de l’entité soit un fragment « "index" » de haute qualité, mais le résultat de recherche lui-même représente toujours l’entité parente.

Dans la recherche hybride, appliquez les filtres StructArray là où la condition doit s’appliquer. Un filtre de niveau supérieur peut être partagé par l’ensemble de la recherche hybride. Un filtre « element_filter » doit être associé à la requête de niveau élément StructArray qui nécessite des contraintes au niveau des éléments.

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

L’argument « filter » applique la condition d’entité de niveau supérieur, tandis que l’argument « expr » sur chunk_req ne contraint que la requête vectorielle au niveau des éléments de StructArray. Pour connaître les combinaisons de recherche hybride prises en charge et les limites spécifiques à chaque version, consultez les sections « Recherche hybride avec StructArray » et « Limites de StructArray ».

Résumé de la prise en charge des prédicats

Utilisez des sous-champs scalaires dans les prédicats StructArray. Les sous-champs vectoriels ne constituent pas des entrées de prédicats scalaires.

Type de sous-champExemples typiques de prédicats
BOOL$[has_code] == true, !($[has_code] == true)
Types entiers$[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%"
Sous-champs vectorielsNon pris en charge en tant qu’entrées de prédicats scalaires d’ $[...]. Utilisez plutôt les sous-champs vectoriels via la recherche vectorielle.

Pour les cas non pris en charge, tels que les chemins JSON, les fonctions de conteneur de tableaux, les fonctions de correspondance de texte, les prédicats null sur $[...], les fonctions de géométrie, les expressions Timestamptz et les appels de fonctions génériques, consultez la section Opérateurs StructArray.

Erreurs courantes

  • Utilisation de ` $[subfield] ` en dehors de ` element_filter ` ou ` MATCH_*`.

  • Utilisation de ` chunks.section ` à la place de la syntaxe des opérateurs StructArray, telle que ` element_filter(chunks, $[section] == "index")`.

  • Utiliser element_filter alors que vous n'avez besoin que d'un filtrage au niveau des lignes. Utilisez plutôt MATCH_ANY si vous avez uniquement besoin de sélectionner des entités.

  • S'attendre à ce que ` MATCH_* ` renvoie des indices d'éléments. Ces opérateurs sélectionnent des entités et n'identifient pas eux-mêmes un élément correspondant.

  • Écrire des prédicats booléens nus tels que $[has_code]. Utilisez des comparaisons explicites telles que $[has_code] == true.

  • Placer « element_filter » avant un prédicat de niveau supérieur dans la même expression de filtre.

Étapes suivantes

  1. Pour consulter la syntaxe complète des filtres StructArray, lisez la section Opérateurs StructArray.

  2. Pour effectuer d’abord des recherches vectorielles non filtrées, consultez la section « Recherche vectorielle de base avec StructArray ».

  3. Pour créer des index scalaires pour les filtres StructArray fréquemment utilisés, consultez la section « Indexer les champs StructArray ».

  4. Pour connaître les limites de filtrage et de recherche spécifiques à chaque version, consultez la section « Limites de StructArray ».