Gérer des index vectoriels
Ce document explique comment créer et gérer des index vectoriels pour accélérer vos recherches vectorielles.
Un index vectoriel est une structure de données conçue pour permettre à la fonction VECTOR_SEARCH
de s'exécuter plus efficacement, en particulier sur de grands ensembles de données.
Lorsqu'il utilise un index, VECTOR_SEARCH
emploie des algorithmes ANN (Approximate Nearest Neighbor) pour réduire la latence des requêtes et les coûts de calcul. Bien que l'ANN introduise un certain degré d'approximation, ce qui signifie que le rappel peut ne pas être de 100 %, les améliorations de performances offrent généralement un avantage pour la plupart des applications.
Rôles et autorisations
Pour créer un index vectoriel, vous devez disposer de l'autorisation IAM bigquery.tables.createIndex
sur la table dans laquelle vous créez l'index. Pour supprimer un index vectoriel, vous devez disposer de l'autorisation bigquery.tables.deleteIndex
. Chacun des rôles IAM prédéfinis suivants inclut les autorisations dont vous avez besoin pour travailler avec les index vectoriels :
- Propriétaire de données BigQuery (
roles/bigquery.dataOwner
) - Éditeur de données BigQuery (
roles/bigquery.dataEditor
)
Choisir un type d'index vectoriel
BigQuery propose deux types d'index vectoriels, IVF et TreeAH, chacun prenant en charge différents cas d'utilisation. BigQuery accepte le traitement par lot pour la recherche vectorielle en traitant plusieurs lignes de données d'entrée dans la fonction VECTOR_SEARCH
.
Pour les petits lots de requêtes, les index IVF sont préférables. Pour les grands lots de requêtes, les index TreeAH, qui sont créés avec l'algorithme ScaNN de Google, sont préférables.
Index IVF
L'IVF est un index de fichier inversé, qui utilise un algorithme basé sur les k-moyennes pour regrouper les données vectorielles en clusters, puis qui partitionne les données vectorielles en fonction de ces clusters définis. La fonction VECTOR_SEARCH
peut utiliser ces partitions pour réduire la quantité de données à lire afin de déterminer un résultat.
Index TreeAH
Le type d'index TreeAH doit son nom à sa structure arborescente et à son utilisation du hachage asymétrique (AH), une technique de quantification de base de l'algorithme ScaNN sous-jacent. Un index TreeAH fonctionne comme suit :
- La table de base est divisée en segments plus petits et plus faciles à gérer.
- Un modèle de clustering est entraîné, avec le nombre de clusters dérivé de l'option
leaf_node_embedding_count
dans l'argumenttree_ah_options
de l'instructionCREATE VECTOR INDEX
. - Les vecteurs sont compressés à l'aide de la quantification produit, une technique qui réduit leur utilisation de la mémoire. Les vecteurs compressés sont ensuite stockés dans les tables d'index au lieu des vecteurs d'origine, ce qui réduit la taille des index vectoriels.
- Lorsque la fonction
VECTOR_SEARCH
s'exécute, une liste de candidats pour chaque vecteur de requête est calculée efficacement à l'aide d'un hachage asymétrique, qui bénéficie d'une optimisation matérielle pour les calculs de distance approximative. Ces candidats sont ensuite réévalués et reclassés à l'aide d'embeddings exacts.
L'algorithme TreeAH est optimisé pour les requêtes par lot qui traitent plusieurs centaines de vecteurs de requête, ou plus. L'utilisation de la quantification par produit peut réduire considérablement la latence et les coûts, potentiellement de plusieurs ordres de grandeur par rapport à l'index de fichier inversé (IVF). Toutefois, en raison de la surcharge accrue, l'algorithme IVF peut être plus efficace lorsque vous avez un nombre réduit de vecteurs de requête.
Nous vous suggérons d'essayer le type d'index TreeAH si votre cas d'utilisation répond aux critères suivants :
Votre table ne contient pas plus de 200 millions de lignes.
Vous exécutez fréquemment de grandes requêtes par lot impliquant plusieurs centaines de vecteurs de requête, ou plus.
Pour les petites requêtes par lot avec le type d'index TreeAH, VECTOR_SEARCH
peut revenir à la recherche par force brute.
Dans ce cas, un IndexUnusedReason est fourni pour expliquer pourquoi l'index vectoriel n'a pas été utilisé.
Créer un index vectoriel IVF
Pour créer un index vectoriel IVF, utilisez l'instruction LDD (langage de définition de données) CREATE VECTOR INDEX
:
Accédez à la page BigQuery.
Dans l'éditeur de requête, exécutez l'instruction SQL suivante :
Pour créer un index vectoriel IVF :
CREATE [ OR REPLACE ] VECTOR INDEX [ IF NOT EXISTS ] INDEX_NAME ON DATASET_NAME.TABLE_NAME(COLUMN_NAME) STORING(STORED_COLUMN_NAME [, ...]) OPTIONS(index_type = 'IVF', distance_type = 'DISTANCE_TYPE', ivf_options = '{"num_lists":NUM_LISTS}')
Remplacez les éléments suivants :
INDEX_NAME
: nom de l'index vectoriel que vous créez. Étant donné que l'index est toujours créé dans le même projet et le même ensemble de données que la table de base, il n'est pas nécessaire de les spécifier dans le nom.DATASET_NAME
: nom de l'ensemble de données contenant la table.TABLE_NAME
: nom de la table contenant la colonne avec des données d'embeddings.COLUMN_NAME
: nom d'une colonne contenant des données d'embeddings. La colonne doit être de typeARRAY<FLOAT64>
. La colonne ne peut pas comporter de champs enfants. Tous les éléments du tableau doivent être non-NULL
, et toutes les valeurs de la colonne doivent avoir les mêmes dimensions de tableau.STORED_COLUMN_NAME
: nom d'une colonne de premier niveau dans la table à stocker dans l'index vectoriel. Le type de colonne ne peut pas êtreRANGE
. Les colonnes stockées ne sont pas utilisées si la table dispose d'une règle d'accès au niveau des lignes ou si la colonne comporte un tag avec stratégie. Pour savoir comment activer les colonnes stockées, consultez la section Stocker des colonnes et définir un préfiltrage.DISTANCE_TYPE
: spécifie le type de distance par défaut à utiliser lors de l'exécution d'une recherche vectorielle à l'aide de cet index. Les valeurs acceptées sontEUCLIDEAN
,COSINE
etDOT_PRODUCT
.EUCLIDEAN
est la valeur par défaut.La création d'index utilise toujours la distance
EUCLIDEAN
pour l'entraînement, mais la distance utilisée dans la fonctionVECTOR_SEARCH
peut être différente.Si vous spécifiez une valeur pour l'argument
distance_type
de la fonctionVECTOR_SEARCH
, cette valeur est utilisée à la place de la valeurDISTANCE_TYPE
.NUM_LISTS
: valeurINT64
qui spécifie le nombre de listes dans lesquelles l'index IVF regroupe, puis partitionne vos données vectorielles. Cette valeur doit être inférieure ou égale à 5 000. Lors de l'indexation, les vecteurs sont attribués à la liste correspondant au centroïde de cluster le plus proche. Si vous omettez cet argument, BigQuery détermine une valeur par défaut en fonction des caractéristiques de vos données. La valeur par défaut fonctionne bien pour la plupart des cas d'utilisation.NUM_LISTS
contrôle la précision de l'optimisation des requêtes. Des valeurs plus élevées créent davantage de listes. Vous pouvez donc définir l'optionfraction_lists_to_search
de la fonctionVECTOR_SEARCH
pour analyser un pourcentage plus faible de l'index. Par exemple, il est préférable d'analyser 1 % de 100 listes plutôt que 10 % de 10 listes. Cela permet de contrôler plus précisément la vitesse de recherche et le rappel, mais augmente légèrement le coût d'indexation. Définissez la valeur de cet argument en fonction de la précision avec laquelle vous devez ajuster le champ d'application de la requête.
L'exemple suivant crée un index vectoriel sur la colonne embedding
de my_table
:
CREATE TABLE my_dataset.my_table(embedding ARRAY<FLOAT64>); CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding) OPTIONS(index_type = 'IVF');
L'exemple suivant crée un index vectoriel sur la colonne embedding
de my_table
et spécifie le type de distance à utiliser et les options IVF :
CREATE TABLE my_dataset.my_table(embedding ARRAY<FLOAT64>); CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding) OPTIONS(index_type = 'IVF', distance_type = 'COSINE', ivf_options = '{"num_lists": 2500}')
Créer un index vectoriel TreeAH
Pour créer un index vectoriel TreeAH, utilisez l'instruction LDD (langage de définition de données) CREATE VECTOR INDEX
:
Accédez à la page BigQuery.
Dans l'éditeur de requête, exécutez l'instruction SQL suivante :
CREATE [ OR REPLACE ] VECTOR INDEX [ IF NOT EXISTS ] INDEX_NAME ON DATASET_NAME.TABLE_NAME(COLUMN_NAME) STORING(STORED_COLUMN_NAME [, ...]) OPTIONS(index_type = 'TREE_AH', distance_type = 'DISTANCE_TYPE', tree_ah_options = '{"leaf_node_embedding_count":LEAF_NODE_EMBEDDING_COUNT, "normalization_type":"NORMALIZATION_TYPE"}')
Remplacez les éléments suivants :
INDEX_NAME
: nom de l'index vectoriel que vous créez. Étant donné que l'index est toujours créé dans le même projet et le même ensemble de données que la table de base, il n'est pas nécessaire de les spécifier dans le nom.DATASET_NAME
: nom de l'ensemble de données contenant la table.TABLE_NAME
: nom de la table contenant la colonne avec des données d'embeddings.COLUMN_NAME
: nom d'une colonne contenant des données d'embeddings. La colonne doit être de typeARRAY<FLOAT64>
. La colonne ne peut pas comporter de champs enfants. Tous les éléments du tableau doivent être non-NULL
, et toutes les valeurs de la colonne doivent avoir les mêmes dimensions de tableau.STORED_COLUMN_NAME
: nom d'une colonne de premier niveau dans la table à stocker dans l'index vectoriel. Le type de colonne ne peut pas êtreRANGE
. Les colonnes stockées ne sont pas utilisées si la table dispose d'une règle d'accès au niveau des lignes ou si la colonne comporte un tag avec stratégie. Pour savoir comment activer les colonnes stockées, consultez la section Stocker des colonnes et définir un préfiltrage.DISTANCE_TYPE
: argument facultatif qui spécifie le type de distance par défaut à utiliser lors de l'exécution d'une recherche vectorielle à l'aide de cet index. Les valeurs acceptées sontEUCLIDEAN
,COSINE
etDOT_PRODUCT
.EUCLIDEAN
est la valeur par défaut.La création d'index utilise toujours la distance
EUCLIDEAN
pour l'entraînement, mais la distance utilisée dans la fonctionVECTOR_SEARCH
peut être différente.Si vous spécifiez une valeur pour l'argument
distance_type
de la fonctionVECTOR_SEARCH
, cette valeur est utilisée à la place de la valeurDISTANCE_TYPE
.LEAF_NODE_EMBEDDING_COUNT
: valeurINT64
supérieure ou égale à 500, qui spécifie le nombre approximatif de vecteurs dans chaque nœud feuille de l'arborescence créée par l'algorithme TreeAH. L'algorithme TreeAH divise l'intégralité de l'espace de données en un certain nombre de listes, chacune contenant un nombre de points de données correspondant approximativement àLEAF_NODE_EMBEDDING_COUNT
. Une valeur inférieure crée davantage de listes comportant chacune moins de points de données, tandis qu'une valeur plus élevée crée moins de listes, mais avec davantage de points de données. La valeur par défaut est 1 000, ce qui convient à la plupart des ensembles de données.NORMALIZATION_TYPE
: une valeurSTRING
. Les valeurs acceptées sontNONE
ouL2
. La valeur par défaut estNONE
. La normalisation intervient avant tout traitement, à la fois pour les données de la table de base et pour les données de requête, mais elle ne modifie pas la colonne d'embeddingCOLUMN_NAME
dans la tableTABLE_NAME
. En fonction de l'ensemble de données, du modèle d'embedding et du type de distance utilisé lors de la rechercheVECTOR_SEARCH
, la normalisation des embeddings peut améliorer le rappel.
L'exemple suivant crée un index vectoriel sur la colonne embedding
de la table my_table
, et spécifie le type de distance à utiliser et les options TreeAH :
CREATE TABLE my_dataset.my_table(id INT64, embedding ARRAY<FLOAT64>); CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding) OPTIONS (index_type = 'TREE_AH', distance_type = 'EUCLIDEAN', tree_ah_options = '{"normalization_type": "L2"}');
Filtrage
Les sections suivantes expliquent comment les préfiltres et les postfiltres affectent les résultats de la recherche vectorielle, et comment préfiltrer en utilisant des colonnes et des partitions stockées dans l'index vectoriel.
Préfiltres et postfiltres
Dans les opérations VECTOR_SEARCH
de BigQuery, le préfiltrage et le post-filtrage permettent d'affiner les résultats de recherche en appliquant des conditions basées sur les colonnes de métadonnées associées aux embeddings vectoriels. Il est important de comprendre leurs différences, leur implémentation et leur impact afin d'optimiser les performances, le coût et la précision des requêtes.
Le préfiltrage et le postfiltrage sont définis comme suit :
- Préfiltrage : applique les conditions de filtrage avant que la recherche approximative du voisin le plus proche (ANN) n'effectue des calculs de distance sur les vecteurs candidats. Cela réduit le pool de vecteurs pris en compte lors de la recherche. Par conséquent, le préfiltrage permet souvent d'accélérer les requêtes et de réduire les coûts de calcul, car la recherche ANN évalue moins de candidats potentiels.
- Post-filtrage : applique les conditions de filtrage après l'identification des
top_k
voisins les plus proches initiaux par la recherche ANN. Cela permet d'affiner l'ensemble de résultats final en fonction des critères spécifiés.
L'emplacement de votre clause WHERE
détermine si un filtre agit comme un préfiltre ou un post-filtre.
Pour créer un préfiltre, la clause WHERE
de la requête doit s'appliquer à l'argument de table de base de la fonction VECTOR_SEARCH
.
Le prédicat doit s'appliquer à une colonne stockée, sinon il devient effectivement un post-filtre.
L'exemple suivant montre comment créer un préfiltre :
-- Pre-filter on a stored column. The index speeds up the query. SELECT * FROM VECTOR_SEARCH( (SELECT * FROM my_dataset.my_table WHERE type = 'animal'), 'embedding', TABLE my_dataset.my_testdata); -- Filter on a column that isn't stored. The index is used to search the -- entire table, and then the results are post-filtered. You might see fewer -- than 5 matches returned for some embeddings. SELECT query.test_id, base.type, distance FROM VECTOR_SEARCH( (SELECT * FROM my_dataset.my_table WHERE id = 123), 'embedding', TABLE my_dataset.my_testdata, top_k => 5); -- Use pre-filters with brute force. The data is filtered and then searched -- with brute force for exact results. SELECT query.test_id, base.type, distance FROM VECTOR_SEARCH( (SELECT * FROM my_dataset.my_table WHERE id = 123), 'embedding', TABLE my_dataset.my_testdata, options => '{"use_brute_force":true}');
Pour créer un post-filtre, la clause WHERE
de la requête doit être appliquée en dehors de la fonction VECTOR_SEARCH
, afin qu'elle filtre les résultats renvoyés par la recherche.
L'exemple suivant montre comment créer un post-filtre :
-- Use post-filters. The index is used, but the entire table is searched and -- the post-filtering might reduce the number of results. SELECT query.test_id, base.type, distance FROM VECTOR_SEARCH( TABLE my_dataset.my_table, 'embedding', TABLE my_dataset.my_testdata, top_k => 5) WHERE base.type = 'animal'; SELECT base.id, distance FROM VECTOR_SEARCH( TABLE mydataset.base_table, 'embedding', (SELECT embedding FROM mydataset.query_table), top_k => 10 ) WHERE type = 'document' AND year > 2022
Lorsque vous utilisez le post-filtrage ou que les filtres de table de base que vous spécifiez font référence à des colonnes non stockées et agissent donc comme des post-filtres, l'ensemble de résultats final peut contenir moins de top_k
lignes, voire aucune si le prédicat est sélectif. Si vous avez besoin d'un nombre spécifique de résultats après le filtrage, envisagez de spécifier une valeur top_k
plus élevée ou d'augmenter la valeur fraction_lists_to_search
dans l'appel VECTOR_SEARCH
.
Dans certains cas, en particulier si le préfiltre est très sélectif, le préfiltrage peut également réduire la taille de l'ensemble de résultats. Dans ce cas, essayez d'augmenter la valeur fraction_lists_to_search
dans l'appel VECTOR_SEARCH
.
Préfiltrer avec des colonnes stockées
Pour améliorer l'efficacité de votre index vectoriel, vous pouvez spécifier des colonnes de votre table de base à stocker dans votre index vectoriel. L'utilisation de colonnes stockées peut optimiser les requêtes qui appellent la fonction VECTOR_SEARCH
de différentes manières :
Au lieu d'effectuer une recherche dans une table entière, vous pouvez appeler la fonction
VECTOR_SEARCH
sur une instruction de requête qui préfiltre la table de base à l'aide d'une clauseWHERE
. Si votre table comporte un index et que vous filtrez uniquement les colonnes stockées, BigQuery optimise la requête en filtrant les données avant la recherche, puis en utilisant l'index pour rechercher le plus petit ensemble de résultats. Si vous filtrez des colonnes qui ne sont pas stockées, BigQuery applique le filtre après la recherche dans la table, ou post-filtres.La fonction
VECTOR_SEARCH
génère une structure appeléebase
qui contient toutes les colonnes de la table de base. Sans colonnes stockées, une jointure potentiellement coûteuse est nécessaire pour récupérer les colonnes stockées dansbase
. Si vous utilisez un index IVF et que votre requête ne sélectionne que les colonnes stockées dansbase
, BigQuery optimise votre requête pour éliminer cette jointure. Pour les index TreeAH, la jointure avec la table de base n'est pas supprimée. Les colonnes stockées dans les index TreeAH ne sont utilisées qu'à des fins de préfiltrage.
Pour stocker des colonnes, regroupez-les dans la clause STORING
de l'instruction CREATE VECTOR INDEX
.
Le stockage des colonnes augmente la taille de l'index vectoriel. Il est donc préférable de ne stocker que les colonnes les plus fréquemment utilisées ou filtrées.
L'exemple suivant crée un index vectoriel avec des colonnes stockées, puis exécute une requête de recherche vectorielle qui ne sélectionne que les colonnes stockées :
-- Create a table that contains an embedding. CREATE TABLE my_dataset.my_table(embedding ARRAY<FLOAT64>, type STRING, creation_time DATETIME, id INT64); -- Create a query table that contains an embedding. CREATE TABLE my_dataset.my_testdata(embedding ARRAY<FLOAT64>, test_id INT64); -- Create a vector index with stored columns. CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding) STORING (type, creation_time) OPTIONS (index_type = 'IVF'); -- Select only stored columns from a vector search to avoid an expensive join. SELECT query, base.type, distance FROM VECTOR_SEARCH( TABLE my_dataset.my_table, 'embedding' TABLE my_dataset.my_testdata);
Limites des colonnes stockées
- Si le mode, le type ou le schéma d'une colonne est modifié dans la table de base, et s'il s'agit d'une colonne stockée dans l'index vectoriel, il peut y avoir un délai avant que cette modification ne soit reflétée dans l'index vectoriel. Jusqu'à ce que les mises à jour aient été appliquées à l'index, les requêtes de recherche vectorielle utilisent les colonnes stockées modifiées de la table de base.
- Si vous sélectionnez une colonne de type
STRUCT
dans la sortiequery
d'une requêteVECTOR_SEARCH
, portant sur une table comportant un index avec des colonnes stockées, la requête entière peut échouer.
Préfiltrer avec des partitions
Si la table sur laquelle vous créez l'index vectoriel est partitionnée, vous pouvez choisir de partitionner également l'index vectoriel. Le partitionnement de l'index vectoriel présente les avantages suivants :
- L'élimination des partitions est appliquée aux index vectoriels en plus des partitions de table. La restriction de partition se produit lorsque la recherche vectorielle utilise un filtre éligible sur la valeur de la colonne de partitionnement. Cela permet à BigQuery d'analyser les partitions correspondant au filtre et d'ignorer les partitions restantes. La restriction de partition peut réduire les coûts d'E/S. Pour en savoir plus sur l'élagage de partitions, consultez Interroger des tables partitionnées.
- La recherche vectorielle est moins susceptible de manquer des résultats si vous préfiltrez sur la colonne de partitionnement.
Vous ne pouvez partitionner que les index vectoriels TreeAH.
Le partitionnement d'un index vectoriel n'est recommandé que si vous utilisez le préfiltrage pour limiter la plupart de vos recherches vectorielles à quelques partitions.
Pour créer un index partitionné, utilisez la clause PARTITION BY
de l'instruction CREATE VECTOR INDEX
. La clause PARTITION BY
que vous spécifiez dans l'instruction CREATE VECTOR INDEX
doit être identique à la clause PARTITION BY
spécifiée dans l'instruction CREATE TABLE
de la table sur laquelle vous créez l'index vectoriel, comme indiqué dans l'exemple suivant :
-- Create a date-partitioned table. CREATE TABLE my_dataset.my_table( embeddings ARRAYid INT64, date DATE, ) PARTITION BY date; -- Create a partitioned vector index on the table. CREATE VECTOR INDEX my_index ON my_dataset.my_table(embeddings) PARTITION BY date OPTIONS(index_type='TREE_AH', distance_type='COSINE');
Si la table utilise le partitionnement par plages d'entiers ou par colonnes d'unités de temps, la colonne de partitionnement est stockée dans l'index vectoriel, ce qui augmente les coûts de stockage.
Si une colonne de table est utilisée à la fois dans les clauses STORING
et PARTITION BY
de l'instruction CREATE VECTOR INDEX
, elle n'est stockée qu'une seule fois.
Pour utiliser la partition d'index vectoriel, filtrez la colonne de partitionnement dans la sous-requête de table de base de l'instruction VECTOR_SEARCH
. Dans l'exemple suivant, la table samples.items
est partitionnée par la colonne produced_date
. La sous-requête de la table de base dans l'instruction VECTOR_SEARCH
filtre donc la colonne produced_date
:
SELECT query.id, base.id, distance FROM VECTOR_SEARCH( (SELECT * FROM my_dataset.my_table WHERE produced_date = '2025-01-01'), 'embedding', TABLE samples.test, distance_type => 'COSINE', top_k => 10 );
Exemples
Créez un index vectoriel partitionné sur une table partitionnée par date et heure :
-- Create a datetime-partitioned table. CREATE TABLE my_dataset.my_table( id INT64, produced_date DATETIME, embeddings ARRAY) PARTITION BY produced_date; -- Create a partitioned vector index on the table. CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings) PARTITION BY produced_date OPTIONS(index_type='TREE_AH', distance_type='COSINE');
Créez un index vectoriel partitionné sur une table partitionnée par code temporel :
-- Create a timestamp-partitioned table. CREATE TABLE my_dataset.my_table( id INT64, produced_time TIMESTAMP, embeddings ARRAY) PARTITION BY TIMESTAMP_TRUNC(produced_time, HOUR); -- Create a partitioned vector index on the table. CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings) PARTITION BY TIMESTAMP_TRUNC(produced_time, HOUR) OPTIONS(index_type='TREE_AH', distance_type='COSINE');
Créez un index vectoriel partitionné sur une table partitionnée par plages d'entiers :
-- Create a integer range-partitioned table. CREATE TABLE my_dataset.my_table( id INT64, embeddings ARRAY) PARTITION BY RANGE_BUCKET(id, GENERATE_ARRAY(-100, 100, 20)); -- Create a partitioned vector index on the table. CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings) PARTITION BY RANGE_BUCKET(id, GENERATE_ARRAY(-100, 100, 20)) OPTIONS(index_type='TREE_AH', distance_type='COSINE');
Créez un index vectoriel partitionné sur une table partitionnée par date d'ingestion :
-- Create a ingestion time-partitioned table. CREATE TABLE my_dataset.my_table( id INT64, embeddings ARRAY) PARTITION BY TIMESTAMP_TRUNC(_PARTITIONTIME, DAY); -- Create a partitioned vector index on the table. CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings) PARTITION BY TIMESTAMP_TRUNC(_PARTITIONTIME, DAY) OPTIONS(index_type='TREE_AH', distance_type='COSINE');
Limites du pré-filtrage
- Vous ne pouvez pas utiliser de vues logiques dans votre pré-filtre.
- Si votre préfiltre contient une sous-requête, cela peut interférer avec l'utilisation de l'index.
Comprendre quand les données sont indexées
Les index vectoriels sont entièrement gérés par BigQuery et sont actualisés automatiquement lorsque la table indexée est modifiée.
L'indexation est asynchrone. Il existe un délai entre l'ajout de lignes à la table de base et leur affichage dans l'index. Toutefois, la fonction VECTOR_SEARCH
prend toujours en compte toutes les lignes et ne manque pas les lignes non indexées. La fonction effectue une recherche à l'aide de l'index pour les enregistrements indexés et utilise la recherche par force brute pour les enregistrements qui ne sont pas encore indexés.
Si vous créez un index vectoriel sur une table de taille inférieure à 10 Mo, l'index vectoriel n'est pas renseigné. De même, si vous supprimez les données d'une table indexée et que sa taille est inférieure à 10 Mo, l'index vectoriel est temporairement désactivé. Dans ce cas, les requêtes de recherche vectorielle n'utilisent pas l'index et le code indexUnusedReasons
de la section vectorSearchStatistics
de la ressource Job
est BASE_TABLE_TOO_SMALL
. Sans l'index, la requête VECTOR_SEARCH
bascule automatiquement sur la recherche par force brute pour identifier les voisins les plus proches des embeddings.
Si vous supprimez la colonne indexée d'une table ou renommez la table elle-même, l'index vectoriel est automatiquement supprimé.
Surveiller l'état des index vectoriels
Vous pouvez surveiller l'état de vos index vectoriels en interrogeant les vues INFORMATION_SCHEMA
. Les vues suivantes contiennent des métadonnées sur les index vectoriels :
La vue
INFORMATION_SCHEMA.VECTOR_INDEXES
contient des informations sur les index vectoriels d'un ensemble de données.Une fois l'instruction
CREATE VECTOR INDEX
terminée, vous devez renseigner l'index pour pouvoir l'utiliser. Vous pouvez utiliser les colonneslast_refresh_time
etcoverage_percentage
pour vérifier la disponibilité d'un index vectoriel. Si l'index vectoriel n'est pas prêt, vous pouvez toujours utiliser la fonctionVECTOR_SEARCH
sur une table. En revanche, elle peut s'exécuter plus lentement sans l'index.La vue
INFORMATION_SCHEMA.VECTOR_INDEX_COLUMNS
contient des informations sur les colonnes dotées d'un index vectoriel pour toutes les tables d'un ensemble de données.La vue
INFORMATION_SCHEMA.VECTOR_INDEX_OPTIONS
contient des informations sur les options utilisées par les index vectoriels d'un ensemble de données.
Exemples d'index vectoriels
L'exemple suivant montre tous les index vectoriels actifs sur les tables de l'ensemble de données my_dataset
, situées dans le projet my_project
. Cela inclut leur nom, les instructions LDD utilisées pour les créer et leur pourcentage de couverture. Si une table de base indexée est inférieure à 10 Mo, son index n'est pas renseigné, auquel cas la valeur de coverage_percentage
est égale à 0.
SELECT table_name, index_name, ddl, coverage_percentage FROM my_project.my_dataset.INFORMATION_SCHEMA.VECTOR_INDEXES WHERE index_status = 'ACTIVE';
Le résultat ressemble à ce qui suit :
+------------+------------+-------------------------------------------------------------------------------------------------+---------------------+ | table_name | index_name | ddl | coverage_percentage | +------------+------------+-------------------------------------------------------------------------------------------------+---------------------+ | table1 | indexa | CREATE VECTOR INDEX `indexa` ON `my_project.my_dataset.table1`(embeddings) | 100 | | | | OPTIONS (distance_type = 'EUCLIDEAN', index_type = 'IVF', ivf_options = '{"num_lists": 100}') | | +------------+------------+-------------------------------------------------------------------------------------------------+---------------------+ | table2 | indexb | CREATE VECTOR INDEX `indexb` ON `my_project.my_dataset.table2`(vectors) | 42 | | | | OPTIONS (distance_type = 'COSINE', index_type = 'IVF', ivf_options = '{"num_lists": 500}') | | +------------+------------+-------------------------------------------------------------------------------------------------+---------------------+ | table3 | indexc | CREATE VECTOR INDEX `indexc` ON `my_project.my_dataset.table3`(vectors) | 98 | | | | OPTIONS (distance_type = 'DOT_PRODUCT', index_type = 'TREE_AH', | | | | | tree_ah_options = '{"leaf_node_embedding_count": 1000, "normalization_type": "NONE"}') | | +------------+------------+-------------------------------------------------------------------------------------------------+---------------------+
Exemples de colonnes d'index vectoriels
La requête suivante extrait des informations sur les colonnes comportant des index vectoriels :
SELECT table_name, index_name, index_column_name, index_field_path FROM my_project.dataset.INFORMATION_SCHEMA.VECTOR_INDEX_COLUMNS;
Le résultat ressemble à ce qui suit :
+------------+------------+-------------------+------------------+ | table_name | index_name | index_column_name | index_field_path | +------------+------------+-------------------+------------------+ | table1 | indexa | embeddings | embeddings | | table2 | indexb | vectors | vectors | | table3 | indexc | vectors | vectors | +------------+------------+-------------------+------------------+
Exemples d'options d'index vectoriels
La requête suivante extrait des informations sur les options d'index vectoriels :
SELECT table_name, index_name, option_name, option_type, option_value FROM my_project.dataset.INFORMATION_SCHEMA.VECTOR_INDEX_OPTIONS;
Le résultat ressemble à ce qui suit :
+------------+------------+------------------+------------------+-------------------------------------------------------------------+ | table_name | index_name | option_name | option_type | option_value | +------------+------------+------------------+------------------+-------------------------------------------------------------------+ | table1 | indexa | index_type | STRING | IVF | | table1 | indexa | distance_type | STRING | EUCLIDEAN | | table1 | indexa | ivf_options | STRING | {"num_lists": 100} | | table2 | indexb | index_type | STRING | IVF | | table2 | indexb | distance_type | STRING | COSINE | | table2 | indexb | ivf_options | STRING | {"num_lists": 500} | | table3 | indexc | index_type | STRING | TREE_AH | | table3 | indexc | distance_type | STRING | DOT_PRODUCT | | table3 | indexc | tree_ah_options | STRING | {"leaf_node_embedding_count": 1000, "normalization_type": "NONE"} | +------------+------------+------------------+------------------+-------------------------------------------------------------------+
Vérifier l'utilisation de l'index vectoriel
Des informations sur l'utilisation des index vectoriels sont disponibles dans les métadonnées du job qui a exécuté la requête de recherche vectorielle. Vous pouvez afficher les métadonnées du job à l'aide de la console Google Cloud , de l'outil de ligne de commande bq, de l'API BigQuery ou des bibliothèques clientes.
Lorsque vous utilisez la console Google Cloud , vous pouvez trouver des informations sur l'utilisation des index vectoriels dans les champs Mode d'utilisation de l'index vectoriel et Motifs de non-utilisation de l'index vectoriel.
Lorsque vous utilisez l'outil bq ou l'API BigQuery, vous pouvez trouver des informations sur l'utilisation des index vectoriels dans la section VectorSearchStatistics
de la ressource Job
.
Le mode d'utilisation de l'index indique si un index vectoriel a été utilisé en fournissant l'une des valeurs suivantes :
UNUSED
: aucun index vectoriel n'a été utilisé.PARTIALLY_USED
: certaines fonctionsVECTOR_SEARCH
de la requête utilisaient des index vectoriels, et d'autres non.FULLY_USED
: chaque fonctionVECTOR_SEARCH
de la requête a utilisé un index vectoriel.
Lorsque la valeur du mode d'utilisation de l'index est UNUSED
ou PARTIALLY_USED
, les motifs de non-utilisation de l'index indiquent pourquoi les index vectoriels n'ont pas été utilisés dans la requête.
Par exemple, les résultats suivants renvoyés par bq show --format=prettyjson -j my_job_id
indiquent que l'index n'a pas été utilisé, car l'option use_brute_force
a été spécifiée dans la fonction VECTOR_SEARCH
:
"vectorSearchStatistics": { "indexUnusedReasons": [ { "baseTable": { "datasetId": "my_dataset", "projectId": "my_project", "tableId": "my_table" }, "code": "INDEX_SUPPRESSED_BY_FUNCTION_OPTION", "message": "No vector index was used for the base table `my_project:my_dataset.my_table` because use_brute_force option has been specified." } ], "indexUsageMode": "UNUSED" }
Options de gestion des index
Pour créer des index et laisser BigQuery les gérer, deux options s'offrent à vous :
- Utiliser le pool d'emplacements partagés par défaut : lorsque les données que vous prévoyez d'indexer sont inférieures à votre limite par organisation, vous pouvez utiliser le pool d'emplacements partagé gratuit pour la gestion des index.
- Utiliser votre propre réservation : pour obtenir une progression d'indexation plus prévisible et cohérente sur vos charges de travail de production plus importantes, vous pouvez utiliser vos propres réservations pour la gestion des index.
Utiliser les emplacements partagés
Si vous n'avez pas configuré votre projet pour utiliser une réservation dédiée pour l'indexation, la gestion des index est gérée dans le pool d'emplacements partagés gratuit, qui est soumis aux contraintes suivantes.
Si vous ajoutez des données à une table, ce qui entraîne le dépassement de la limite des tables indexées pour votre organisation, BigQuery suspend la gestion des index pour toutes les tables indexées. Dans ce cas, le champ index_status
de la vue INFORMATION_SCHEMA.VECTOR_INDEXES
affiche PENDING DISABLEMENT
et l'index est mis en file d'attente pour suppression. Tant que l'index est en attente de désactivation, il est toujours utilisé dans les requêtes et le stockage des index vous est facturé.
Une fois l'index supprimé, le champ index_status
affiche l'état de l'index comme étant TEMPORARILY DISABLED
. Dans cet état, les requêtes n'utilisent pas l'index et le stockage d'index ne vous est pas facturé. Dans ce cas, le code IndexUnusedReason
est BASE_TABLE_TOO_LARGE
.
Si vous supprimez des données de la table et que la taille totale des tables indexées est inférieure à la limite par organisation, la gestion des index est réactivée pour toutes les tables indexées. Le champ index_status
dans la vue INFORMATION_SCHEMA.VECTOR_INDEXES
est ACTIVE
, les requêtes peuvent utiliser l'index et le stockage d'index vous est facturé.
Vous pouvez utiliser la vue INFORMATION_SCHEMA.SEARCH_INDEXES_BY_ORGANIZATION
pour comprendre votre consommation actuelle par rapport à la limite par organisation dans une région donnée, ventilée par projets et par tables.
BigQuery ne garantit pas la capacité disponible du pool partagé ni le débit d'indexation que vous voyez. Pour les applications de production, vous pouvez utiliser des emplacements dédiés pour le traitement des index.
Utiliser votre propre réservation
Au lieu d'utiliser le pool d'emplacements partagés par défaut, vous pouvez éventuellement définir votre propre réservation pour indexer vos tables. L'utilisation de votre propre réservation garantit des performances prévisibles et cohérentes pour les jobs de gestion des index, telles que la création, l'actualisation et les optimisations en arrière-plan.
- Il n'y a aucune limite de taille de table lorsqu'un job d'indexation s'exécute dans votre réservation.
- L'utilisation de votre propre réservation vous donne une certaine flexibilité dans la gestion de vos index. Si vous devez créer un index très volumineux ou effectuer une mise à jour majeure d'une table indexée, vous pouvez ajouter temporairement d'autres emplacements à l'attribution.
Pour indexer les tables d'un projet avec une réservation désignée, créez une réservation dans la région où se trouvent vos tables. Ensuite, attribuez le projet à la réservation en définissant job_type
sur BACKGROUND
:
SQL
Utilisez l'instruction LDD CREATE ASSIGNMENT
:
Dans la console Google Cloud , accédez à la page BigQuery.
Dans l'éditeur de requête, saisissez l'instruction suivante :
CREATE ASSIGNMENT `ADMIN_PROJECT_ID.region-LOCATION.RESERVATION_NAME.ASSIGNMENT_ID` OPTIONS ( assignee = 'projects/PROJECT_ID', job_type = 'BACKGROUND');
Remplacez les éléments suivants :
ADMIN_PROJECT_ID
: ID du projet d'administration propriétaire de la ressource de réservationLOCATION
: emplacement de la réservation.RESERVATION_NAME
: nom de la réservationASSIGNMENT_ID
: ID de l'attributionL'ID doit être unique au projet et à l'emplacement. Il doit commencer et se terminer par une lettre minuscule ou un chiffre, et ne doit contenir que des lettres minuscules, des chiffres et des tirets.
PROJECT_ID
: ID du projet contenant les tables à indexer. Ce projet est attribué à la réservation.
Cliquez sur
Exécuter.
Pour en savoir plus sur l'exécution des requêtes, consultez Exécuter une requête interactive.
bq
Exécutez la commande bq mk
:
bq mk \ --project_id=ADMIN_PROJECT_ID \ --location=LOCATION \ --reservation_assignment \ --reservation_id=RESERVATION_NAME \ --assignee_id=PROJECT_ID \ --job_type=BACKGROUND \ --assignee_type=PROJECT
Remplacez les éléments suivants :
ADMIN_PROJECT_ID
: ID du projet d'administration propriétaire de la ressource de réservationLOCATION
: emplacement de la réservation.RESERVATION_NAME
: nom de la réservationPROJECT_ID
: ID du projet à attribuer à cette réservation
Afficher vos tâches d'indexation
Un job d'indexation est créée chaque fois qu'un index est créé ou mis à jour sur une table unique. Pour afficher des informations sur la tâche, interrogez les vues INFORMATION_SCHEMA.JOBS*
. Vous pouvez filtrer les tâches d'indexation en définissant job_type IS NULL AND SEARCH(job_id, '`search_index`')
dans la clause WHERE
de votre requête. L'exemple suivant répertorie les cinq tâches d'indexation les plus récentes du projet my_project
:
SELECT * FROM region-us.INFORMATION_SCHEMA.JOBS WHERE project_id = 'my_project' AND job_type IS NULL AND SEARCH(job_id, '`search_index`') ORDER BY creation_time DESC LIMIT 5;
Choisir votre taille de réservation
Pour choisir le nombre approprié d'emplacements pour votre réservation, vous devez prendre en compte le moment où les tâches de gestion des index sont exécutées, ainsi que le nombre d'emplacements utilisés et votre utilisation au fil du temps. BigQuery déclenche une tâche de gestion des index dans les situations suivantes :
- Vous créez un index sur une table.
- Des données sont modifiées dans une table indexée.
- Le schéma d'une table change, ce qui affecte les colonnes indexées.
- Les données et les métadonnées d'index sont régulièrement optimisées ou mises à jour.
Le nombre d'emplacements dont vous avez besoin pour exécuter une tâche de gestion des index sur une table dépend des facteurs suivants :
- Taille de la table
- Taux d'ingestion de données dans la table
- Taux d'instructions LMD appliquées à la table
- Délai acceptable pour créer et gérer l'index
- Complexité de l'index, généralement déterminée par les attributs des données, tels que le nombre de termes en double
Surveiller l'utilisation et la progression
Le meilleur moyen d'évaluer le nombre d'emplacements dont vous avez besoin pour exécuter efficacement vos tâches de gestion des index consiste à surveiller l'utilisation des emplacements et à ajuster la taille de la réservation en conséquence. La requête suivante permet d'obtenir l'utilisation quotidienne des emplacements pour les tâches de gestion des index. Seuls les 30 derniers jours sont inclus dans la région us-west1
:
SELECT TIMESTAMP_TRUNC(job.creation_time, DAY) AS usage_date, -- Aggregate total_slots_ms used for index-management jobs in a day and divide -- by the number of milliseconds in a day. This value is most accurate for -- days with consistent slot usage. SAFE_DIVIDE(SUM(job.total_slot_ms), (1000 * 60 * 60 * 24)) AS average_daily_slot_usage FROM `region-us-west1`.INFORMATION_SCHEMA.JOBS job WHERE project_id = 'my_project' AND job_type IS NULL AND SEARCH(job_id, '`search_index`') GROUP BY usage_date ORDER BY usage_date DESC limit 30;
Lorsque les emplacements sont insuffisants pour exécuter des tâches de gestion des index, un index peut ne plus être synchronisé avec sa table. Par conséquent, les tâches d'indexation peuvent échouer. Dans ce cas, BigQuery recrée l'index à partir de zéro. Pour éviter la désynchronisation d'index, assurez-vous de disposer de suffisamment d'emplacements pour gérer les mises à jour d'index liées à l'ingestion et à l'optimisation des données. Pour en savoir plus sur l'utilisation des emplacements, consultez la page Graphiques de ressources pour les administrateurs.
Supprimer un index vectoriel
Lorsque vous n'avez plus besoin d'un index vectoriel ou que vous souhaitez modifier la colonne indexée sur une table, vous pouvez supprimer l'index de cette table à l'aide de l'instruction LDD DROP VECTOR INDEX
.
Exemple :
DROP VECTOR INDEX my_index ON my_dataset.indexed_table;
Si une table indexée est supprimée, son index est automatiquement supprimé.
Étapes suivantes
- Pour obtenir une présentation des cas d'utilisation, des tarifs et des limites des index de vecteurs, consultez la présentation de la recherche vectorielle.
- Découvrez comment effectuer une recherche vectorielle à l'aide de la fonction
VECTOR_SEARCH
. - En savoir plus sur l'instruction
CREATE VECTOR INDEX
- Suivez le tutoriel Rechercher des embeddings à l'aide de la recherche vectorielle.