Questa pagina spiega come creare e gestire gli indici vettoriali di Spanner, che utilizzano la ricerca del vicino più prossimo approssimato (ANN) e le strutture basate su alberi per accelerare le ricerche di similarità vettoriale sui dati.
Spanner accelera le ricerche vettoriali del vicino più prossimo approssimato (ANN) utilizzando un indice vettoriale specializzato. Questo indice sfrutta Google Research's ScaNN (Scalable Nearest Neighbor), un algoritmo del vicino più prossimo altamente efficiente.
L'indice vettoriale utilizza una struttura basata su alberi per partizionare i dati e facilitare le ricerche più rapide. Spanner offre configurazioni di alberi a due e tre livelli:
- Configurazione dell'albero a due livelli: i nodi foglia (
num_leaves) contengono gruppi di vettori strettamente correlati insieme al centroide corrispondente. Il livello principale è costituito dai centroidi di tutti i nodi foglia. - Configurazione dell'albero a tre livelli: simile nel concetto a un albero a due livelli, ma introduce un livello di ramificazione aggiuntivo (
num_branches), da cui i centroidi dei nodi foglia vengono ulteriormente partizionati per formare il livello principale (num_leaves).
Spanner sceglie un indice per te. Tuttavia, se sai che un
indice specifico funziona meglio, puoi utilizzare l'FORCE_INDEX hint
per scegliere di utilizzare l'indice vettoriale più appropriato per il tuo caso d'uso.
Per saperne di più, consulta le istruzioni
VECTOR INDEX per GoogleSQL
e le istruzioni INDEX per PostgreSQL.
Limitazioni
- Non puoi pre-dividere gli indici vettoriali. Per saperne di più, consulta Panoramica della pre-divisione.
Crea indice vettoriale
Per ottimizzare il richiamo e il rendimento di un indice vettoriale, ti consigliamo di:
Crea l'indice vettoriale dopo aver scritto la maggior parte delle righe con gli embedding nel database. Potresti anche dover ricompilare periodicamente l'indice vettoriale dopo aver inserito nuovi dati. Per saperne di più, consulta Ricompila l'indice vettoriale.
Per GoogleSQL, utilizza la clausola
STORINGe per PostgreSQL, utilizza la clausolaINCLUDEper archiviare una copia di una colonna nell'indice vettoriale. Se un valore di colonna è archiviato nell'indice vettoriale, Spanner esegue il filtraggio a livello di foglia dell'indice per migliorare il rendimento delle query. Ti consigliamo di archiviare una colonna se viene utilizzata in una condizione di filtro.Utilizza colonne chiave non di embedding nell'indice vettoriale. Le colonne chiave sono simili alle colonne
STORINGoINCLUDE, ma consentono al motore di query di eseguire il filtraggio in modo più efficiente durante la ricerca vettoriale. Per saperne di più, consulta Crea indice vettoriale (GoogleSQL) o Istruzioni dell'indice (PostgreSQL).
Quando crei la tabella, la colonna di embedding deve essere un array del
FLOAT32 (GoogleSQL) o float4[] (PostgreSQL) tipo di dati (consigliato) e avere un'
annotazione di lunghezza del vettore (vector_length=>N per GoogleSQL o VECTOR LENGTH N per PostgreSQL),
che indica la dimensione dei vettori.
La lunghezza ottimale del vettore dipende dal carico di lavoro, dalle dimensioni del set di dati e dalle risorse di calcolo disponibili. Sperimenta con dimensioni diverse per trovare la dimensione più piccola che mantenga l'accuratezza e il rendimento della tua applicazione.
La seguente istruzione DDL crea una tabella Documents con una colonna di embedding DocEmbedding con una lunghezza del vettore:
GoogleSQL
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);
PostgreSQL
CREATE TABLE documents (
user_id bigint not null,
doc_id bigint not null,
author varchar(1024),
doc_contents bytea,
doc_embedding float4[] VECTOR LENGTH 128 not null,
nullable_doc_embedding float4[] VECTOR LENGTH 128,
word_count bigint,
PRIMARY KEY (doc_id)
);
Dopo aver compilato la tabella Documents, puoi creare un indice vettoriale con un albero a due livelli e 1000 nodi foglia nella tabella Documents con una colonna di embedding DocEmbedding utilizzando la distanza del coseno:
GoogleSQL
CREATE VECTOR INDEX DocEmbeddingIndex
ON Documents(DocEmbedding)
STORING (WordCount)
OPTIONS (distance_type = 'COSINE', tree_depth = 2, num_leaves = 1000);
PostgreSQL
CREATE INDEX doc_embedding_index
ON documents
USING scann(doc_embedding)
INCLUDE (word_count)
WITH (distance_type = 'COSINE', num_leaves = 1000)
WHERE doc_embedding IS NOT NULL;
Se la colonna di embedding non è contrassegnata come NOT NULL nella definizione della tabella, devi dichiararla con una clausola WHERE COLUMN_NAME IS NOT NULL nella definizione dell'indice vettoriale, dove COLUMN_NAME è il nome della colonna di embedding. Per creare un indice vettoriale con un albero a tre livelli e 1000000 nodi foglia nella colonna di embedding nullable NullableDocEmbedding utilizzando la distanza del coseno:
GoogleSQL
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);
PostgreSQL
CREATE INDEX doc_embedding_index
ON documents
USING scann(nullable_doc_embedding)
INCLUDE (word_count)
WITH (distance_type = 'COSINE', tree_depth = 3, num_branches = 1000, num_leaves = 1000000)
WHERE nullable_doc_embedding IS NOT NULL;
Filtra un indice vettoriale
Puoi anche creare un indice vettoriale filtrato per trovare gli elementi più simili nel database che corrispondono alla condizione di filtro. Un indice vettoriale filtrato indicizza in modo selettivo le righe che soddisfano le condizioni di filtro specificate, migliorando il rendimento della ricerca.
Nell'esempio seguente, la tabella Documents2 ha una colonna denominata Category.
Nella ricerca vettoriale, vogliamo indicizzare la categoria "Tech", quindi creiamo una colonna generata che restituisce NULL se la condizione della categoria non è soddisfatta.
GoogleSQL
CREATE TABLE Documents2 (
UserId INT64 NOT NULL,
DocId INT64 NOT NULL,
DocName STRING (1024),
Author STRING (1024),
DocContents Bytes(MAX),
Category STRING(MAX),
NullIfFiltered BOOL AS (IF(Category = 'Tech', TRUE, NULL)) HIDDEN,
DocEmbedding ARRAY<FLOAT32>(vector_length=>128)
) PRIMARY KEY (DocId);
PostgreSQL
CREATE TABLE documents2 (
user_id bigint not null,
doc_id bigint not null,
doc_name varchar(1024),
author varchar(1024),
doc_contents bytea,
category varchar,
null_if_filtered boolean GENERATED ALWAYS AS (CASE WHEN category = 'Tech' THEN true END) VIRTUAL HIDDEN,
doc_embedding float4[] VECTOR LENGTH 128,
PRIMARY KEY (doc_id)
);
Poi creiamo un indice vettoriale con un filtro. L'indice vettoriale TechDocEmbeddingIndex indicizza solo i documenti nella categoria "Tech".
GoogleSQL
CREATE VECTOR INDEX TechDocEmbeddingIndex
ON Documents2(DocEmbedding)
STORING(NullIfFiltered)
WHERE DocEmbedding IS NOT NULL AND NullIfFiltered IS NOT NULL
OPTIONS (...);
PostgreSQL
CREATE INDEX tech_doc_embedding_index
ON documents2
USING scann(doc_embedding)
INCLUDE (null_if_filtered)
WITH (distance_type = 'COSINE', num_leaves = 1000)
WHERE doc_embedding IS NOT NULL AND null_if_filtered IS NOT NULL;
Quando Spanner esegue la seguente query, che contiene filtri che corrispondono a TechDocEmbeddingIndex, la sceglie automaticamente e viene accelerata da TechDocEmbeddingIndex. La query cerca solo i documenti nella categoria "Tech". Puoi anche utilizzare l'hint FORCE_INDEX (@{FORCE_INDEX=TechDocEmbeddingIndex} per GoogleSQL o /*@ FORCE_INDEX = tech_doc_embedding_index */ per PostgreSQL) per forzare
Spanner a utilizzare l'indice in modo esplicito.
GoogleSQL
SELECT *
FROM Documents2
WHERE DocEmbedding IS NOT NULL AND NullIfFiltered IS NOT NULL
ORDER BY APPROX_(....)
LIMIT 10;
PostgreSQL
SELECT *
FROM documents2
WHERE doc_embedding IS NOT NULL AND null_if_filtered IS NOT NULL
ORDER BY spanner.approx_cosine_distance(doc_embedding, ARRAY[1.0::float4, 2.0::float4, 3.0::float4])
LIMIT 10;
Per migliorare il rendimento delle query, puoi includere colonne chiave non di embedding nell'indice vettoriale. In questo modo, il motore di query può eseguire il filtraggio in modo più efficiente durante la ricerca vettoriale.
Nell'istruzione di creazione dell'indice, devi elencare queste colonne chiave aggiuntive dopo la colonna di embedding. Ad esempio, la seguente istruzione crea un indice vettoriale che include le colonne chiave DocName e Author per un filtraggio più efficiente:
GoogleSQL
CREATE VECTOR INDEX DocEmbeddingIndexWithKeys
ON Documents2(DocEmbedding, DocName, Author)
STORING(NullIfFiltered)
WHERE DocEmbedding IS NOT NULL AND NullIfFiltered IS NOT NULL
OPTIONS (...);
PostgreSQL
CREATE INDEX doc_embedding_index_with_keys
ON documents2
USING scann(doc_embedding, doc_name, author)
INCLUDE (null_if_filtered)
WITH (distance_type = 'COSINE', num_leaves = 1000)
WHERE doc_embedding IS NOT NULL AND null_if_filtered IS NOT NULL;
Passaggi successivi
Scopri di più sui vicini più prossimi approssimati di Spanner .
Scopri di più sulle funzioni di distanza approssimativa in GoogleSQL e PostgreSQL.
Scopri di più sulle istruzioni dell'indice per GoogleSQL
VECTOR INDEXe PostgreSQLINDEX.Scopri di più sulle best practice per gli indici vettoriali.