Recherche par intervalle avec StructArray

Utilisez cette page pour effectuer une recherche par plage sur les sous-champs vectoriels de StructArray. La recherche par plage renvoie les résultats vectoriels dont le score ou la distance se situe dans une plage spécifiée. Pour les champs StructArray, utilisez la recherche par plage avec la recherche vectorielle au niveau des éléments, où chaque élément Struct est recherché indépendamment.

Cette page utilise la collection « tech_articles » issue de la section « Créer un champ StructArray ». Cette collection comporte un champ StructArray nommé « chunks ». Le sous-champ vectoriel « chunks[emb] » est indexé pour la recherche au niveau des éléments à l’aide d’une métrique vectorielle standard telle que « COSINE », « IP » ou « L2 ».

Comment la recherche par plage s’applique à StructArray

Mode de rechercheComportement de la recherche par plageGranularité des résultats
Recherche dans EmbeddingListNon pris en charge.Sans objet.
Recherche au niveau des élémentsUtilisez une requête vectorielle standard avec radius et, éventuellement, range_filter.Niveau des éléments de structure.
Recherche hybridePrise en charge lorsque la requête StructArray cible un champ vectoriel au niveau des éléments. Les requêtes au niveau de l’EmbeddingList ne prennent pas en charge la recherche par plage.Sous-recherche au niveau des éléments, puis reclassement hybride.

Si vous n’avez besoin que des éléments Struct les plus proches, commencez par une recherche vectorielle de base avec StructArray. Utilisez la recherche par plage lorsque le résultat doit respecter une limite de score ou de distance, et non pas uniquement un classement Top-K.

Avant de commencer

Préparez la collection, les données et les index avant d'exécuter une recherche par plage.

Conditions requisesDétails
Champ StructArrayLa collection contient un champ StructArray tel que chunks.
Sous-champ vectoriel au niveau de l’élémentLe sous-champ vectoriel cible est chunks[emb], et non chunks[emb_list_vector].
Métrique d’indexationLe sous-champ vectoriel est indexé à l'aide d'une métrique vectorielle standard, telle que COSINE, IP ou L2.
Données de requêteLa requête est un vecteur standard, et non un EmbeddingList.

Pour la configuration de l’index, voir Champs StructArray de l’index.

Utilisation de radius et range_filter

Définissez ` radius ` pour délimiter la zone de recherche. Définissez ` range_filter ` si vous avez également besoin d’une limite intérieure. Le choix de la direction dépend de ce qui est privilégié : une distance plus courte ou un score de similarité plus élevé.

Type de métriqueUn score plus élevé est-il préférable ?Condition de plage lorsque « range_filter » est utilisé
L2Non. Une distance plus courte est préférable.range_filter <= distance < radius
IP, COSINEOui. Un score plus élevé est préférable.radius < distance <= range_filter

Lorsque seule l'radius est définie, la recherche par plage renvoie les résultats qui respectent la limite extérieure de la métrique. Choisissez les valeurs en fonction de l'échelle de score ou de distance de vos représentations.

L’exemple suivant recherche des segments individuels dont les vecteurs d’ chunks[emb] sont suffisamment similaires au vecteur de requête. Chaque résultat correspond à un élément Struct apparié.

from pymilvus import MilvusClient

client = MilvusClient(
    uri="http://localhost:19530",
    token="root:Milvus",
)

query_vector = [0.19, 0.24, 0.30, 0.37]

results = client.search(
    collection_name="tech_articles",
    data=[query_vector],
    anns_field="chunks[emb]",
    search_params={
        "params": {
            "radius": 0.80,
            "range_filter": 0.95,
        },
    },
    limit=10,
    output_fields=[
        "doc_id",
        "title",
        "chunks[text]",
        "chunks[section]",
        "chunks[page]",
        "chunks[quality_score]",
    ],
)

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, « COSINE » est une métrique de type « similarité » ; l’intervalle de résultats est donc supérieur à radius et inférieur ou égal à range_filter. La valeur « offset » identifie l’élément Struct correspondant dans le tableau « chunks » lors du renvoi.

Ajouter des filtres scalaires

Vous pouvez combiner la recherche par plage au niveau des éléments avec le filtrage scalaire de StructArray. Utilisez un prédicat de niveau supérieur pour les champs de l’entité parente, et utilisez element_filter pour restreindre les éléments Struct participant à la recherche par plage vectorielle.

filter_expr = (
    'category == "search" && '
    'element_filter(chunks, '
    '$[section] == "index" && '
    '$[quality_score] > 0.9)'
)

results = client.search(
    collection_name="tech_articles",
    data=[query_vector],
    anns_field="chunks[emb]",
    search_params={
        "params": {
            "radius": 0.80,
            "range_filter": 0.95,
        },
    },
    filter=filter_expr,
    limit=10,
    output_fields=[
        "doc_id",
        "title",
        "category",
        "chunks[text]",
        "chunks[section]",
        "chunks[quality_score]",
    ],
)

Le prédicat de niveau supérieur sélectionne les entités candidates. Le prédicat « element_filter » limite la recherche par plage vectorielle aux éléments Struct correspondants. Pour plus d’exemples de filtrage, consultez la section « Recherche filtrée avec StructArray ».

Les champs vectoriels au niveau des éléments de StructArray prennent en charge la recherche par plage dans la recherche hybride. Ajoutez « radius » et, éventuellement, « range_filter » à la requête « AnnSearchRequest » qui cible le champ vectoriel au niveau des éléments de StructArray.

from pymilvus import AnnSearchRequest, RRFRanker

title_req = AnnSearchRequest(
    data=[query_vector],
    anns_field="title_vector",
    limit=10,
)

chunk_req = AnnSearchRequest(
    data=[query_vector],
    anns_field="chunks[emb]",
    param={
        "params": {
            "radius": 0.80,
            "range_filter": 0.95,
        },
    },
    limit=10,
    expr='element_filter(chunks, $[section] == "index")',
)

results = client.hybrid_search(
    collection_name="tech_articles",
    reqs=[title_req, chunk_req],
    ranker=RRFRanker(),
    limit=5,
    output_fields=[
        "doc_id",
        "title",
        "chunks[text]",
        "chunks[section]",
        "chunks[quality_score]",
    ],
)

Dans cet exemple, seule la sous-requête « chunks[emb] » utilise des paramètres de recherche par plage. La requête StructArray suit toujours la sémantique au niveau des éléments : la limite de la plage s’applique aux résultats correspondant aux éléments Struct avant que la recherche hybride ne combine et ne reclasse les résultats.

Interprétation des résultats de la recherche par plage

Élément de résultatSignification
idClé primaire de l’entité contenant l’élément Struct correspondant.
distance ou scoreLe score ou la distance entre le vecteur de requête et le vecteur de l'élément Struct correspondant.
offsetPosition (à partir de zéro) de l’élément Struct correspondant dans le champ StructArray lors du renvoi.
Clés primaires répétéesPossible. Plus d’un élément Struct d’une même entité peut se situer dans la plage spécifiée.
limitS'applique aux occurrences d'éléments, et non aux entités parentes uniques.

Limitations

  • N’utilisez pas de requête « EmbeddingList » ni de métrique « MAX_SIM* » pour la recherche par plage sur les sous-champs vectoriels de StructArray. La recherche au niveau de l’EmbeddingList ne prend pas en charge la recherche par plage.

  • Ne combinez pas la recherche par plage avec la recherche par regroupement. Si vous avez besoin d’un résultat par entité parente, effectuez une recherche au niveau des éléments sans paramètres de plage et utilisez le regroupement lorsque cela est pris en charge.

  • La recherche par plage hybride est prise en charge pour les champs vectoriels au niveau des éléments de StructArray. Elle n’est pas prise en charge pour les requêtes StructArray au niveau de l’EmbeddingList.

Erreurs courantes

  • Lancer une recherche par plage sur chunks[emb_list_vector], qui est destiné à la recherche au niveau de l’EmbeddingList.

  • Utiliser MAX_SIM_COSINE au lieu d’une métrique standard telle que COSINE pour une recherche par plage au niveau des éléments.

  • Utilisation d’une requête de type « EmbeddingList » à la place d’une requête vectorielle classique.

  • S'attendre à ce que les résultats de la recherche par plage soient uniques par entité parente. La recherche par plage renvoie les occurrences d'éléments Struct correspondantes.

  • Utilisation de « chunks.emb » au lieu de la syntaxe requise pour le chemin d’accès au sous-champ « chunks[emb] ».

Étapes suivantes

  1. Pour découvrir les deux modes de recherche vectorielle de base avec StructArray, consultez la section « Recherche vectorielle de base avec StructArray ».

  2. Pour ajouter des filtres scalaires à la recherche par plage, consultez la section « Recherche filtrée avec StructArray ».

  3. Pour renvoyer au maximum un résultat par entité parente lorsque cela est pris en charge, consultez la section « Recherche groupée avec StructArray ».

  4. Pour vérifier les limites de recherche spécifiques à chaque version, consultez la section « Limites de StructArray ».