Créer et gérer des index vectoriels

Cette page explique comment créer et gérer des index vectoriels Spanner, qui utilisent la recherche approximative du voisin le plus proche (ANN) et des structures arborescentes pour accélérer les recherches de similarité vectorielle dans vos données.

Spanner accélère les recherches vectorielles du voisin le plus proche approximatives (ANN) en utilisant un index vectoriel spécialisé. Cet index s'appuie sur Scalable Nearest Neighbor (ScaNN), un algorithme de recherche du voisin le plus proche très efficace développé par Google Research.

L'index vectoriel utilise une structure arborescente pour partitionner les données et faciliter des recherches plus rapides. Spanner propose des configurations d'arborescence à deux et trois niveaux :

  • Configuration de l'arborescence à deux niveaux : les nœuds feuilles (num_leaves) contiennent des groupes de vecteurs étroitement liés ainsi que leur centroïde correspondant. Le niveau racine se compose des centroïdes de tous les nœuds feuilles.
  • Configuration d'arborescence à trois niveaux : semblable à une arborescence à deux niveaux, mais avec une couche de branche supplémentaire (num_branches) à partir de laquelle les centroïdes des nœuds feuilles sont partitionnés pour former le niveau racine (num_leaves).

Spanner choisit un index pour vous. Toutefois, si vous savez qu'un index spécifique fonctionne mieux, vous pouvez utiliser l'indication FORCE_INDEX pour choisir l'index vectoriel le plus adapté à votre cas d'utilisation.

Pour en savoir plus, consultez la section Instructions VECTOR INDEX.

Limites

Créer un index vectoriel

Pour optimiser le rappel et les performances d'un index vectoriel, nous vous recommandons de :

  • Créez votre index vectoriel une fois que la plupart des lignes avec des embeddings ont été écrites dans votre base de données. Vous devrez peut-être aussi reconstruire périodiquement l'index vectoriel après avoir inséré de nouvelles données. Pour en savoir plus, consultez Reconstruire l'index vectoriel.

  • Utilisez la clause STORING pour stocker une copie d'une colonne dans l'index vectoriel. Si une valeur de colonne est stockée dans l'index vectoriel, Spanner effectue le filtrage au niveau de la feuille de l'index pour améliorer les performances des requêtes. Nous vous recommandons de stocker une colonne si elle est utilisée dans une condition de filtrage. Pour en savoir plus sur l'utilisation de STORING dans un index, consultez Créer un index pour les analyses d'index uniquement.

Lorsque vous créez votre table, la colonne d'intégration doit être un tableau de type de données FLOAT32 (recommandé) ou FLOAT64, et comporter une annotation vector_length indiquant la dimension des vecteurs.

L'instruction LDD suivante crée une table Documents avec une colonne d'embedding DocEmbedding avec une longueur de vecteur :

CREATE TABLE Documents (
  UserId INT64 NOT NULL,
  DocId INT64 NOT NULL,
  Author STRING (1024),
  DocContents Bytes(MAX),
  DocEmbedding ARRAY<FLOAT32>(vector_length=>128) NOT NULL,
  NullableDocEmbedding ARRAY<FLOAT32>(vector_length=>128),
  WordCount INT64,
) PRIMARY KEY (DocId);

Une fois que vous avez rempli votre table Documents, vous pouvez créer un index vectoriel avec un arbre à deux niveaux et 1 000 nœuds feuilles sur la table Documents avec une colonne d'intégration DocEmbedding à l'aide de la distance cosinus :

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

Si votre colonne d'intégration n'est pas marquée comme NOT NULL dans la définition de la table, vous devez la déclarer avec une clause WHERE COLUMN_NAME IS NOT NULL dans la définition de l'index vectoriel, où COLUMN_NAME est le nom de votre colonne d'intégration. Pour créer un index vectoriel avec un arbre à trois niveaux et 1 000 000 de nœuds feuilles sur la colonne d'embedding pouvant être nulle NullableDocEmbedding à l'aide de la distance cosinus :

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

Filtrer un index vectoriel

Vous pouvez également créer un index vectoriel filtré pour trouver les éléments les plus similaires de votre base de données qui correspondent à la condition de filtre. Un index vectoriel filtré indexe de manière sélective les lignes qui répondent aux conditions de filtre spécifiées, ce qui améliore les performances de recherche.

Dans l'exemple suivant, la table Documents2 comporte une colonne appelée Category. Dans notre recherche vectorielle, nous souhaitons indexer la catégorie "Tech". Nous créons donc une colonne générée qui renvoie NULL si la condition de catégorie n'est pas remplie.

CREATE TABLE Documents2 (
  DocId INT64 NOT NULL,
  Category STRING(MAX),
  NullIfFiltered BOOL AS (IF(Category = 'Tech', TRUE, NULL)) HIDDEN,
  DocEmbedding ARRAY<FLOAT32>(vector_length=>128),
) PRIMARY KEY (DocId);

Ensuite, nous créons un index vectoriel avec un filtre. L'index vectoriel TechDocEmbeddingIndex n'indexe que les documents de la catégorie "Tech".

CREATE VECTOR INDEX TechDocEmbeddingIndex
  ON Documents2(DocEmbedding)
  STORING(NullIfFiltered)
  WHERE DocEmbedding IS NOT NULL AND NullIfFiltered IS NOT NULL
  OPTIONS (...);

Lorsque Spanner exécute la requête suivante, qui comporte des filtres correspondant à TechDocEmbeddingIndex, il sélectionne automatiquement TechDocEmbeddingIndex et est accéléré par cette requête. La requête ne recherche que les documents de la catégorie "Tech". Vous pouvez également utiliser {@FORCE_INDEX=TechDocEmbeddingIndex} pour forcer Spanner à utiliser explicitement TechDocEmbeddingIndex.

SELECT *
FROM Documents2
WHERE DocEmbedding IS NOT NULL AND NullIfFiltered IS NOT NULL
ORDER BY APPROX_(....)
LIMIT 10;

Étapes suivantes