Partager via


Ajouter un filtre dans une requête vectorielle dans Recherche Azure AI

Vous pouvez définir une requête vectorielle qui inclut une expression de filtre pour ajouter des critères d’inclusion ou d’exclusion à vos requêtes. Dans cet article, découvrez comment :

Cet article utilise REST pour l’illustration. Pour obtenir des exemples de code dans d’autres langages, consultez les azure-search-vector-samples référentiel GitHub pour les solutions de bout en bout qui incluent des requêtes vectorielles.

Vous pouvez également utiliser l’Explorateur de recherche dans le Portail Azure pour interroger le contenu vectoriel. Si vous utilisez la vue JSON, vous pouvez ajouter des filtres et spécifier le mode filtre.

Fonctionnement du filtrage dans une requête vectorielle

Les filtres s'appliquent aux champs filterable non vectoriels, soit un champ de chaîne soit un champ numérique, pour inclure ou exclure des documents de recherche en fonction de critères de filtre. Bien qu’un champ vectoriel ne soit pas filtrable lui-même, les filtres peuvent être appliqués à d’autres champs dans le même index, en incluant ou excluant des documents qui contiennent également des champs vectoriels.

Les filtres sont appliqués avant ou après l’exécution de la requête en fonction du paramètre vectorFilterMode.

Définir un filtre

Les filtres déterminent l’étendue d’une requête de vecteur. Les filtres sont définis et itérés sur des champs chaîne et numériques non-vecteur attribués comme filterable dans l’index, mais le but d’un filtre détermine ce sur quoi la requête vectorielle s’exécute : l’espace entier dans lequel rechercher ou le contenu d’un résultat de recherche.

Si vous n’avez pas de champs sources avec du texte ou des valeurs numériques, recherchez les métadonnées de document, telles que les propriétés LastModified ou CreatedBy, qui peuvent être utiles dans un filtre de métadonnées.

2024-07-01 est la version stable de cette API. Il comprend :

  • vectorFilterMode pour le préfiltre (valeur par défaut) ou les modes de filtrage postfilter.
  • filter fournit les critères.

Dans l’exemple suivant, le vecteur est une représentation de cette chaîne de requête : « ce que les services Azure prennent en charge la recherche en texte intégral ». La requête cible le champ contentVector. Le vecteur réel a 1536 incorporations. Il est donc rogné dans cet exemple pour la lisibilité.

Les critères de filtrage sont appliqués à un champ de texte filtrable (category dans cet exemple) avant que le moteur de recherche n'exécute la requête vectorielle.

POST https://{{search-service-name}}.search.windows.net/indexes/{{index-name}}/docs/search?api-version=2024-07-01
Content-Type: application/json
api-key: {{admin-api-key}}
{
    "count": true,
    "select": "title, content, category",
    "filter": "category eq 'Databases'",
    "vectorFilterMode": "preFilter",
    "vectorQueries": [
        {
            "kind": "vector",
            "vector": [
                -0.009154141,
                0.018708462,
                . . . 
                -0.02178128,
                -0.00086512347
            ],
            "exhaustive": true,
            "fields": "contentVector",
            "k": 5
        }
    ]
}

Définir vectorFilterMode

Le paramètre de requête vectorFilterMode détermine si le filtre est appliqué avant ou après l’exécution de la requête vectorielle.

Utiliser le mode préfiltre

Le préfiltrage applique des filtres avant l’exécution de la requête, ce qui réduit la zone de surface de recherche sur laquelle l’algorithme de recherche vectorielle recherche du contenu similaire.

Dans une requête vectorielle, preFilter est la valeur par défaut.

Diagramme des préfiltres.

Utiliser le mode post-filtre

Le post-filtrage applique des filtres après l'exécution de la requête, ce qui réduit les résultats de la recherche.

Diagramme des post-filtres.

Test d’évaluation des modes de filtre vectoriel

Pour comprendre les conditions dans lesquelles un mode de filtre fonctionne mieux que l’autre, nous avons exécuté une série de tests pour évaluer les résultats des requêtes sur des index de petite, moyenne et grande taille.

  • Petit (100 000 documents, index de 2,5 Go, 1536 dimensions)
  • Moyen (1 million de documents, index de 25 Go, 1536 dimensions)
  • Large (1 milliard de documents, index de 1,9 To, 96 dimensions)

Pour les charges de travail petites et moyennes, nous avons utilisé un service Standard 2 (S2) avec une partition et un réplica. Pour la charge de travail importante, nous avons utilisé un service Standard 3 (S3) avec 12 partitions et une réplique.

Les index ont une construction identique : un champ clé, un champ vectoriel, un champ de texte et un champ filtrable numérique. L’index suivant est défini avec la syntaxe 2023-11-03.

def get_index_schema(self, index_name, dimensions):
    return {
        "name": index_name,
        "fields": [
            {"name": "id", "type": "Edm.String", "key": True, "searchable": True},
            {"name": "content_vector", "type": "Collection(Edm.Single)", "dimensions": dimensions,
              "searchable": True, "retrievable": True, "filterable": False, "facetable": False, "sortable": False,
              "vectorSearchProfile": "defaulthnsw"},
            {"name": "text", "type": "Edm.String", "searchable": True, "filterable": False, "retrievable": True,
              "sortable": False, "facetable": False},
            {"name": "score", "type": "Edm.Double", "searchable": False, "filterable": True,
              "retrievable": True, "sortable": True, "facetable": True}
        ],
      "vectorSearch": {
        "algorithms": [
            {
              "name": "defaulthnsw",
              "kind": "hnsw",
              "hnswParameters": { "metric": "euclidean" }
            }
          ],
          "profiles": [
            {
              "name": "defaulthnsw",
              "algorithm": "defaulthnsw"
            }
        ]
      }
    }

Dans les requêtes, nous avons utilisé un filtre identique pour les opérations de préfiltrage et de post-filtre. Nous avons utilisé un filtre simple pour nous assurer que les variations de performance étaient dues au mode de filtrage et non à la complexité du filtre.

Les résultats ont été mesurés dans les requêtes par seconde (QPS).

Éléments importants à retenir

  • Le préfiltrage est presque toujours plus lent que le postfiltrage, sauf sur les petits index où les performances sont approximativement égales.

  • Sur des ensembles de données plus importants, le préfiltrage est beaucoup plus lent.

  • Pourquoi est-ce que le préfiltrer la valeur par défaut s’il est presque toujours plus lent ? Le préfiltrage garantit que les résultats k sont retournés s’ils existent dans l’index, où le biais favorise le rappel et la précision par rapport à la vitesse.

  • Le postfiltrage est destiné aux clients qui :

    • vitesse de valeur sur la sélection (postfiltrage peut retourner moins de k résultats)
    • utiliser des filtres qui ne sont pas trop sélectifs
    • ont des index d'une taille suffisante pour que les performances du préfiltrage soient inacceptables

Détails

  • Compte tenu d’un jeu de données avec 100 000 vecteurs à 1536 dimensions :

    • Lors du filtrage de plus de 30 % du jeu de données, le préfiltrage et le postfiltrage étaient comparables.
    • Lors du filtrage inférieur à 0,1 % du jeu de données, le préfiltrage était d’environ 50 % plus lent que le postfiltrage.
  • Étant donné un ensemble de données comprenant 1 million de vecteurs à 1536 dimensions :

    • Lors du filtrage de plus de 30 % du jeu de données, le préfiltrage était d’environ 30 % plus lent.
    • Lorsque le filtrage porte sur moins de 2 % de l'ensemble de données, le préfiltrage est environ sept fois plus lent.
  • Étant donné un ensemble de données comprenant 1 milliard de vecteurs à 96 dimensions :

    • Lors du filtrage de plus de 5 % du jeu de données, le préfiltrage était d’environ 50 % plus lent.
    • Lorsque le filtrage porte sur moins de 10 % de l'ensemble de données, le préfiltrage est environ sept fois plus lent.

Le graphique suivant montre le QPS relatif au préfiltre, calculé en tant que QPS préfiltré divisé par QPS postfilter.

Graphique montrant les performances QPS pour les index de petite, moyenne et grand taille pour les QPS relatifs.

L’axe vertical est QPS de préfiltrage sur QPS de postfiltrage. Par exemple, une valeur de 0,0 signifie que le préfiltrage est 100 % plus lent, 0,5 sur l'axe vertical signifie que le préfiltrage est 50 % plus lent, 1,0 signifie que le préfiltrage et le post-filtrage sont équivalents.

L’axe horizontal représente le taux de filtrage ou le pourcentage de documents candidats après l’application du filtre. Par exemple, 1.00% signifie qu’un pourcentage du corpus de recherche a été sélectionné par les critères de filtre.