Trouver les voisins les plus proches pour indexer et interroger des représentations vectorielles continues dans Spanner

Cette page explique comment créer un index vectoriel et interroger des représentations vectorielles continues de vecteurs en utilisant en utilisant la distance de cosinus approximative, la distance euclidienne approximative et fonctions de vecteur approximative de produit scalaire. Vous pouvez utiliser ces pour trouver les voisins les plus proches (ANN) dans Spanner. Lorsqu'un ensemble de données est de petite taille, vous pouvez utiliser les plus proches k voisins (KNN). pour trouver les vecteurs k les plus proches exacts. Cependant, à mesure que votre ensemble de données s'agrandit, la latence et le coût d'une recherche sur KNN augmentent également. Vous pouvez utiliser un ANN pour obtenir k voisins les plus proches avec une latence et des coûts considérablement réduits.

Nombre approximatif de k voisins les plus proches

Dans une recherche ANN, les k vecteurs renvoyés ne sont pas les k k-valeurs les plus proches les plus proches. entre voisins. Parfois, quelques vecteurs qui ne figurent pas parmi les k premiers k les plus proches les voisins sont renvoyés. C'est ce que l'on appelle la perte de rappel. Quelle est la perte de rappel ? acceptable pour vous dépend du cas d'utilisation, mais dans la plupart des cas, en échange d'une amélioration des performances de la base de données est une un compromis.

Pour en savoir plus sur les fonctions de distance approximative de Spanner, voir:

Index vectoriel

Spanner accélère les recherches vectorielles ANN en utilisant une requête et un index vectoriel. Cet index s'appuie sur l'outil Scalable Voisin (ScaNN), un algorithme très efficace des voisins les plus proches.

L'index vectoriel utilise une structure arborescente pour partitionner les données et faciliter des recherches plus rapides. Spanner propose à la fois Configurations en arborescence:

  • Configuration d'arborescence à deux niveaux: les nœuds feuille (num_leaves) contiennent des groupes de de vecteurs étroitement liés et de leur centroïde correspondant. La racine se compose des centroïdes de tous les nœuds feuilles.
  • Arborescence à trois niveaux: conceptuelle semblable à une arborescence à deux niveaux, ajout d'une couche de ramification (num_branches), à partir de laquelle le nœud feuille les centroïdes sont ensuite partitionnés pour former le niveau racine (num_leaves).

En outre, vous devez créer votre index vectoriel avec une métrique de distance spécifique. Vous pouvez choisir la métrique de distance la plus adaptée à votre cas d'utilisation en définissant distance_type sur COSINE, DOT_PRODUCT ou EUCLIDEAN.

Pour en savoir plus, consultez Instructions VECTOR INDEX.

Limites

L'index vectoriel Spanner présente les limites suivantes:

  • ALTER VECTOR INDEX n'est pas compatible.

Créer un index vectoriel

Pour optimiser au mieux l'index vectoriel afin d'obtenir un bon rappel et de bonnes performances, nous recommandons créer votre index vectoriel une fois que la plupart des lignes avec des représentations vectorielles continues ont été écrits dans votre base de données. Vous devrez peut-être aussi régulièrement de recréer l'index vectoriel après avoir inséré de nouvelles données. Pour en savoir plus, consultez Reconstruisez l'index vectoriel.

Pour créer un index vectoriel avec une arborescence à deux niveaux et 1 000 nœuds feuilles sur un Table Documents avec une colonne de représentation vectorielle continue DocEmbedding utilisant le cosinus distance:

CREATE VECTOR INDEX DocEmbeddingIndex
  ON Documents(DocEmbedding),
  OPTIONS (distance_type = 'COSINE', tree_depth = 2, num_leaves = 1000);

Pour créer un index vectoriel avec une arborescence à trois niveaux et 1 000 000 nœuds feuilles:

CREATE VECTOR INDEX DocEmbeddingIndex
  ON Documents(NullableDocEmbedding)
  WHERE NullableDocEmbedding IS NOT NULL
  OPTIONS (distance_type = 'COSINE', tree_depth = 3, num_branches=1000, num_leaves = 1000000);

Si votre colonne de représentations vectorielles continues peut avoir une valeur nulle, vous devez la déclarer avec une Clause WHERE column_name IS NOT NULL:

CREATE VECTOR INDEX DocEmbeddingIndex
  ON Documents(NullableDocEmbedding)
  WHERE NullableDocEmbedding IS NOT NULL
  OPTIONS (distance_type = 'COSINE', tree_depth = 2, num_leaves = 1000);

Interroger les embeddings vectoriels

Pour interroger un index vectoriel, utilisez l'une des trois fonctions de distance approximative:

  • APPROX_COSINE_DISTANCE
  • APPROX_EUCLIDEAN_DISTANCE
  • APPROX_DOT_PRODUCT

Lorsque vous utilisez les fonctions de distance approximative, certaines restrictions s'appliquent, entre autres : suivantes:

  • Vous devez fournir un indice de requête pour utiliser l'index vectoriel.
  • Vous devez utiliser une expression constante comme argument de la fonction de distance (un paramètre ou un littéral, par exemple).
  • La requête ou sous-requête dans laquelle la fonction de distance approximative est utilisée doit prennent une forme spécifique: la fonction de distance doit être la seule touche ORDER BY, et une limite doit être spécifiée.

Pour obtenir la liste détaillée des limites, consultez les page de référence sur la fonction de distance approximative.

Exemple

Pour rechercher les 100 vecteurs les plus proches de [1.0, 2.0, 3.0]:

SELECT DocId
FROM Documents@{FORCE_INDEX=DocEmbeddingIndex}
ORDER BY APPROX_EUCLIDEAN_DISTANCE(
  ARRAY<FLOAT32>[1.0, 2.0, 3.0], DocEmbedding,
  options => JSON '{"num_leaves_to_search": 10}')
LIMIT 100

Si la colonne de représentations vectorielles continues peut avoir une valeur nulle:

SELECT DocId
FROM Documents@{FORCE_INDEX=DocEmbeddingIndex}
WHERE NullableDocEmbedding IS NOT NULL
ORDER BY APPROX_EUCLIDEAN_DISTANCE(
  ARRAY<FLOAT32>[1.0, 2.0, 3.0], NullableDocEmbedding,
  options => JSON '{"num_leaves_to_search": 10}')
LIMIT 100

Bonnes pratiques

Suivez ces bonnes pratiques pour optimiser vos index vectoriels et améliorer les requêtes résultats.

Ajuster les options de la recherche vectorielle

La valeur optimale de la recherche vectorielle dépend du cas d'utilisation : le vecteur et sur les vecteurs de requête. Vous devrez peut-être effectuer un réglage itératif pour trouver les valeurs les plus adaptées à votre charge de travail.

Voici quelques consignes utiles à suivre lors du choix des valeurs appropriées:

  • tree_depth (arborescence): si la table en cours d'indexation comporte moins de 10 millions de lignes, utilisez une tree_depth de 2. Sinon, une tree_depth de 3 accepte des tables contenant jusqu'à 10 milliards de lignes.

  • num_leaves: utilise la racine carrée du nombre de lignes dans l'ensemble de données. A peut augmenter la durée de compilation de l'index vectoriel. Éviter de définir num_leaves supérieure à table_row_count/1000, car les feuilles sont alors trop petites et de mauvaises performances.

  • num_leaves_to_search: cette option spécifie le nombre de nœuds feuilles de l'index font l'objet d'une recherche. Augmenter num_leaves_to_search améliore le rappel, mais aussi augmente la latence et les coûts. Nous vous recommandons d'utiliser un nombre représentant 1% du total nombre de feuilles défini dans l'instruction CREATE VECTOR INDEX comme valeur pour num_leaves_to_search. Si vous utilisez une clause de filtre, augmentez cette valeur pour élargir la recherche.

Si le rappel est acceptable, mais que le coût de l'interrogation est trop élevé, ce qui entraîne un faible nombre maximal de RPS, essayez d'augmenter num_leaves en suivant ces étapes:

  1. Définissez num_leaves sur plusieurs "k" de sa valeur d'origine (par exemple, 2 * sqrt(table_row_count)).
  2. Définissez num_leaves_to_search de sorte qu'il soit identique à la valeur "k" de sa valeur d'origine.
  3. Testez la réduction des num_leaves_to_search pour améliorer le coût et le nombre de RPS tout en maintenant le rappel.

Améliorer le rappel

Il existe plusieurs possibilités d'aggravation du rappel, dont les suivantes:

  • num_leaves_to_search est trop petit: il peut s'avérer plus difficile de trouver les voisins les plus proches pour certains vecteurs de requête. num_leaves_to_search pour rechercher plus de feuilles peut contribuer à améliorer le rappel. Récents les requêtes ont peut-être changé pour contenir davantage de ces vecteurs difficiles.

  • L'index vectoriel doit être recompilé: l'arborescence de l'index vectoriel est optimisé pour l'ensemble de données au moment de la création, puis statique. Par conséquent, si des vecteurs très différents sont ajoutés après la création de la l'index vectoriel initial, la structure arborescente risque d'être sous-optimale, un souvenir publicitaire moins important.

Reconstruire l'index vectoriel

Pour reconstruire votre index vectoriel sans temps d'arrêt:

  1. Créer un index vectoriel sur la même colonne de représentation vectorielle continue que le vecteur actuel en mettant à jour les paramètres (par exemple, OPTIONS) le cas échéant.
  2. Une fois l'index créé, modifiez l'indice FORCE_INDEX. à pointer vers le nouvel index pour mettre à jour la requête de recherche vectorielle. Cela garantit que la requête utilise le nouvel index vectoriel. (Vous devrez peut-être aussi régler num_leaves_to_search dans votre nouvelle requête).
  3. Supprimez l'index vectoriel obsolète.

Étape suivante