Pertinence dans la recherche vectorielle

Pendant l’exécution d’une requête vectorielle, le moteur recherche des vecteurs similaires pour trouver les meilleurs candidats à retourner dans les résultats de la recherche. Selon la manière dont vous avez indexé le contenu vectoriel, la recherche des correspondances pertinentes est exhaustive ou limitée aux voisins proches pour un traitement plus rapide. Une fois les candidats trouvés, des métriques de similarité sont utilisées pour évaluer chaque résultat en fonction de la force de la correspondance.

Cet article explique les algorithmes utilisés pour trouver les correspondances pertinentes et les métriques de similarité utilisées pour le scoring. Il contient également des conseils pour améliorer la pertinence si les résultats de la recherche ne répondent pas aux attentes.

Les algorithmes de recherche vectorielle sont l’algorithme KNN (k plus proches voisins) exhaustif et l’algorithme HNSW (Hierarchical Navigable Small World).

Seuls les champs vectoriels marqués comme searchable dans l’index ou comme searchFields dans la requête sont utilisés pour la recherche et le scoring.

Quand utiliser l’algorithme KNN exhaustif

L’algorithme KNN exhaustif calcule les distances entre toutes les paires de points de données et recherche les plus proches voisins k exacts pour un point de requête. Il est destiné aux scénarios où un rappel élevé est de la plus haute importance et où les utilisateurs sont prêts à accepter des compromis dans la latence des requêtes. Comme il utilise une grande quantité de calcul, utilisez KNN exhaustif pour des jeux de données de petite à moyenne taille ou quand les exigences de précision l’emportent sur les considérations du niveau de performance des requêtes.

Un deuxième cas d’utilisation consiste à créer un jeu de données pour évaluer le rappel de l’algorithme des plus proches voisins approximatifs. L’algorithme KNN exhaustif peut être utilisé pour créer l’ensemble de réalité terrain des plus proches voisins.

La prise en charge de KNN exhaustif est disponible via l’API REST 2023-11-01, l’API REST 2023-10-01-Preview et dans les bibliothèques clientes du SDK Azure qui ciblent l’une ou l’autre des versions d’API REST.

Quand utiliser l’algorithme HNSW

Lors de l’indexation, HNSW crée des structures de données supplémentaires pour permettre une recherche plus rapide, en organisant les points de données dans une structure de graphique hiérarchique. HNSW a plusieurs paramètres de configuration qui peuvent être ajustés pour atteindre les objectifs de débit, de latence et de rappel de votre application de recherche. Par exemple, au moment de la requête, vous pouvez spécifier des options de recherche exhaustive, même si le champ vectoriel est indexé pour HNSW.

Pendant l’exécution de la requête, HNSW permet des requêtes voisines rapides en parcourant le graphique. Cette approche permet d’équilibrer la précision de la recherche et l’efficacité du calcul. HNSW est recommandé dans la plupart des scénarios en raison de son efficacité lors de la recherche dans de plus grands jeux de données.

Fonctionnement de la recherche du plus proche voisin

Les requêtes vectorielles s’exécutent sur un espace d’incorporation composé de vecteurs générés à partir du même modèle d’incorporation. En règle générale, la valeur d’entrée dans une demande de requête est transmise au même modèle Machine Learning que celui qui a généré des incorporations dans l’index vectoriel. La sortie est un vecteur dans le même espace d’incorporation. Étant donné que les vecteurs similaires sont regroupés dans un même cluster, la recherche de correspondances équivaut à rechercher les vecteurs les plus proches du vecteur de requête et à renvoyer les documents associés comme résultat de recherche.

Par exemple, si une demande de requête concerne des hôtels, le modèle mappe la requête à un vecteur existant dans un emplacement du cluster de vecteurs qui représente des documents sur les hôtels. L’identification des vecteurs qui sont les plus similaires à la requête, en fonction d’une métrique de similarité, détermine les documents qui sont les plus pertinents.

Quand les champs vectoriels sont indexés pour un algorithme KNN exhaustif, la requête s’exécute sur « tous les voisins ». En ce qui concerne les champs indexés pour HNSW, le moteur de recherche utilise un graphe HNSW pour effectuer la recherche sur un sous-ensemble de nœuds au sein de l’index vectoriel.

Création du graphe HNSW

Pendant l’indexation, le service de recherche construit le graphique HNSW. L’objectif de l’indexation d’un nouveau vecteur dans un graphe HNSW est de l’ajouter à la structure de graphe de sorte à permettre une recherche efficace du plus proche voisin. Les étapes suivantes montrent la procédure à suivre :

  1. Initialisation : commencez par un graphe HNSW vide ou le graphe HNSW existant s’il ne s’agit pas d’un nouvel index.

  2. Point d’entrée : il s’agit du niveau supérieur du graphe hiérarchique qui sert de point de départ pour l’indexation.

  3. Ajout au graphe : les différents niveaux hiérarchiques représentent les diverses granularités du graphe, les niveaux supérieurs étant plus globaux et les niveaux inférieurs étant plus granulaires. Chaque nœud du graphe représente un point vectoriel.

    • Chaque nœud est connecté à m plus proches voisins au maximum. Il s’agit du paramètre m.

    • Le nombre de points de données considérés comme des connexions candidates est gouverné par le paramètre efConstruction. Cette liste dynamique forme l’ensemble de points les plus proches dans le graphe existant que l’algorithme doit prendre en compte. Les valeurs efConstruction supérieures entraînent la prise en compte d’autres nœuds, ce qui conduit souvent à des voisinages locaux plus denses pour chaque vecteur.

    • Ces connexions utilisent la similarité metric configurée pour déterminer la distance. Certaines connexions sont des connexions « longue distance » qui se connectent à divers niveaux hiérarchiques, créant dans le graphe des raccourcis qui améliorent l’efficacité de la recherche.

  4. Nettoyage et optimisation du graphe : cela peut se produire après l’indexation de tous les vecteurs et améliorent la navigabilité et l’efficacité du graphe HNSW.

Une requête vectorielle navigue dans la structure du graphique hiérarchique pour rechercher les correspondances. Voici un résumé des étapes du processus :

  1. Initialisation : l’algorithme lance la recherche au niveau supérieur du graphe hiérarchique. Ce point d’entrée contient le jeu de vecteurs qui sert de point de départ pour la recherche.

  2. Traversée : il traverse ensuite le graphe niveau par niveau, en commençant par le niveau supérieur puis les niveaux inférieurs, sélectionnant les nœuds candidats qui sont les plus proches du vecteur de requête en fonction de la métrique de distance configurée, telle que la similarité cosinus.

  3. Nettoyage : pour améliorer l’efficacité, l’algorithme nettoie l’espace de recherche en tenant compte uniquement des nœuds susceptibles de contenir les plus proches voisins. Pour ce faire, il maintient une file d’attente prioritaire des candidats possibles et la met à jour à mesure que la recherche progresse. La longueur de cette file d’attente est configurée par le paramètre efSearch.

  4. Affinement : quand l’algorithme passe aux niveaux inférieurs, plus granulaires, HNSW prend en compte d’autres voisins près de la requête, ce qui permet à l’ensemble candidat de vecteurs d’être affiné et d’améliorer l’exactitude.

  5. Achèvement : la recherche se termine quand le nombre souhaité de plus proches voisins a été identifié ou quand d’autres critères d’arrêt sont respectés. Ce nombre souhaité de plus proches voisins est régi par le paramètre k de durée de la requête.

Métriques de similarité utilisées pour mesurer la proximité

L’algorithme recherche des vecteurs candidats pour évaluer la similarité. Pour effectuer cette tâche, un calcul de métrique de similarité compare le vecteur candidat au vecteur de requête et mesure la similarité. L’algorithme garde un suivi de l’ensemble ordonné des vecteurs les plus similaires qu’il a trouvés, qui constitue le jeu de résultats classé quand l’algorithme a atteint l’achèvement.

Métrique Description
cosine Cette métrique mesure l’angle entre deux vecteurs et n’est pas affectée par des longueurs de vecteurs différentes. Mathématiquement, elle calcule l’angle entre deux vecteurs. Le cosinus étant la métrique de similarité utilisée par les modèles incorporés Azure OpenAI, si vous utilisez Azure OpenAI, spécifiez cosine dans la configuration vectorielle.
dotProduct Cette métrique mesure à la fois la longueur de chaque paire de deux vecteurs et l’angle entre eux. Mathématiquement, elle calcule les produits des grandeurs des vecteurs et l’angle entre eux. Pour les vecteurs normalisés, la métrique est identique à la similarité cosine, mais légèrement plus performante.
euclidean (également appelée l2 norm) Cette métrique mesure la longueur de la différence vectorielle entre deux vecteurs. Mathématiquement, elle calcule la distance euclidienne entre deux vecteurs, qui est la norme l2 de la différence des deux vecteurs.

Scores dans les résultats d’une recherche vectorielle

Des scores sont calculés et affectés à chaque correspondance, celles qui ont les scores les plus élevés étant retournées en tant que k résultats. La propriété @search.score contient le score. Le tableau suivant montre la plage dans laquelle un score va se trouver.

Méthode de recherche Paramètre Métrique de scoring Plage
recherche vectorielle @search.score Cosinus 0,333 – 1,00

Pour la métrique cosine, il est important de noter que le @search.score calculé n’est pas la valeur du cosinus entre le vecteur de la requête et les vecteurs du document. Recherche Azure AI applique à la place des transformations pour que la fonction de score soit décroissante de façon monotone, ce qui signifie que les valeurs de score diminuent toujours en valeur quand la similarité augmente. Cette transformation veille à ce que les scores de recherche soient utilisables à des fins de classement.

Il existe certaines nuances avec les scores de similarité :

  • La similarité cosinus est définie comme le cosinus de l’angle entre deux vecteurs.
  • La distance cosinus est définie en tant que 1 - cosine_similarity.

Pour créer une fonction décroissante de façon monotone, le @search.score est défini comme 1 / (1 + cosine_distance).

Les développeurs qui ont besoin d’une valeur cosinus au lieu de la valeur synthétique peuvent utiliser une formule pour convertir le score de recherche en distance cosinus :

double ScoreToSimilarity(double score)
{
    double cosineDistance = (1 - score) / score;
    return  -cosineDistance + 1;
}

Avoir la valeur cosinus d’origine peut être utile dans des solutions personnalisées qui configurent des seuils pour réduire les résultats de qualité faible.

Conseils pour l’optimisation de la pertinence

Si vous n’obtenez pas de résultats pertinents, faites des essais avec des modifications de la configuration de la requête. Il n’existe pas de fonctionnalités d’optimisation spécifiques pour les requêtes vectorielles, comme un profil de scoring ou la mise en avant d’un champ ou d’un terme :

  • Faites des essais avec des tailles et des chevauchements de blocs. Essayez en augmentant la taille des blocs et en vérifiant qu’il existe un chevauchement suffisant pour préserver le contexte ou la continuité entre les blocs.

  • Pour HNSW, essayez différents niveaux de efConstruction pour changer la composition interne du graphique de proximité. La valeur par défaut est 400. La plage est comprise entre 100 et 1,000.

  • Augmentez les k résultats pour utiliser plus de résultats de recherche dans un modèle de conversation, si vous en utilisez un.

  • Essayez des requêtes hybrides avec un classement sémantique. Dans les tests de point de référence, cette combinaison a produit de façon cohérente les résultats les plus pertinents.

Étapes suivantes