Trovare i vicini più prossimi approssimativi per indicizzare e eseguire query sugli incorporamenti vettoriali in Spanner

Questa pagina descrive come creare un indice di vettori ed eseguire query sui vettori di embedding utilizzando la distanza di coseno approssimativa, la distanza euclidea approssimativa e le funzioni di vettore del prodotto scalare approssimativo. Puoi utilizzare queste funzioni per trovare vicini più prossimi approssimativi (ANN) in Spanner. Quando un set di dati è piccolo, puoi utilizzare la tecnica K-Nearest Neighbor (KNN) per trovare i vettori k-nearest esatti. Tuttavia, con l'aumento del set di dati, aumentano anche la latenza e il costo di una ricerca KNN. Puoi utilizzare le ANN per trovare i vicini più prossimi approssimativi con latenza e costi notevolmente ridotti.

K vicini più vicini approssimati

In una ricerca ANN, i vettori restituiti da k non sono i veri vicini più prossimi di k. A volte vengono restituiti alcuni vettori che non sono tra i k più vicini. Questo fenomeno è noto come perdita di richiamo. La quantità di perdita di richiamo accettabile dipende dal caso d'uso, ma nella maggior parte dei casi, perdere un po' di richiamo in cambio di un miglioramento delle prestazioni del database è un compromesso accettabile.

Per ulteriori dettagli sulle funzioni di distanza approssimativa di Spanner, consulta:

Indice vettoriale

Spanner accelera le ricerche di vettori ANN utilizzando un indice vettoriale specializzato. Questo indice si avvale dello strumento Scalable Nearest (Scalable Nearest)" di Google Research Vicino (ScaNN), un algoritmo molto efficiente per il vicino più prossimo.

L'indice di vettori utilizza una struttura basata su albero per partizionare i dati e favorire ricerche più rapide. Spanner offre configurazioni ad albero sia a due che a tre livelli:

  • Configurazione ad albero a due livelli: i nodi foglia (num_leaves) contengono gruppi di vettori strettamente correlati insieme al centroide corrispondente. Il livello radice è costituito dai centroidi di tutti i nodi foglia.
  • Configurazione ad albero su tre livelli: concettualmente simile a un albero a due livelli, mentre introducendo un ulteriore strato di ramo (num_branches), da cui nodo foglia i centroidi sono ulteriormente partizionati in modo da formare il livello principale (num_leaves).

Inoltre, devi creare l'indice di vettori con una metrica di distanza specifica. Puoi scegliere la metrica di distanza più appropriata per il tuo caso d'uso impostando distance_type a uno tra COSINE, DOT_PRODUCT o EUCLIDEAN.

Per saperne di più, consulta gli estratto conto di VECTOR INDEX.

Limitazioni

L'indice vettoriale di Spanner ha le seguenti limitazioni:

  • ALTER VECTOR INDEX non supportato.

Crea indice vettoriale

Per ottimizzare al meglio l'indice vettoriale per un buon richiamo e prestazioni, consigliamo di creare l'indice vettoriale dopo che la maggior parte delle righe con incorporamenti sono vengono scritte nel database. Potrebbe essere necessario inoltre eseguire periodicamente ricreare l'indice vettoriale dopo aver inserito nuovi dati. Per ulteriori informazioni, vedi Ricrea l'indice vettoriale.

Per creare un indice vettoriale con un albero a due livelli e 1000 nodi foglia su una Tabella Documents con una colonna di incorporamento DocEmbedding che utilizza il coseno distanza:

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

Per creare un indice vettoriale con un albero a tre livelli e 1000000 nodi foglia:

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);

Se la colonna di incorporamento è nullable, devi dichiararla con una clausola 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);

Esegui query sugli embedding vettoriali

Per eseguire una query su un indice di vettori, utilizza una delle tre funzioni di distanza approssimativa:

  • APPROX_COSINE_DISTANCE
  • APPROX_EUCLIDEAN_DISTANCE
  • APPROX_DOT_PRODUCT

Le limitazioni relative all'utilizzo delle funzioni di distanza approssimativa includono seguenti:

  • Per utilizzare l'indice vettoriale, devi fornire un suggerimento per la query.
  • Devi utilizzare un'espressione costante come argomento della funzione di distanza (ad esempio un parametro o un valore letterale).
  • La query o la sottoquery in cui viene utilizzata la funzione di distanza approssimativa deve hanno una forma specifica: la funzione di distanza deve essere l'unico tasto ORDER BY, ed è necessario specificare un limite.

Per un elenco dettagliato delle limitazioni, consulta la pagina di riferimento della funzione di distanza approssimativa.

Esempio

Per cercare i 100 vettori più vicini a [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

Se la colonna di incorporamento ammette valori nulli:

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

Best practice

Segui queste best practice per ottimizzare i tuoi indici vettoriali e migliorare le query che consentono di analizzare i dati e visualizzare i risultati.

Ottimizza le opzioni di ricerca vettoriale

Il valore di ricerca vettoriale ottimale dipende dal caso d'uso, il vettore e sui vettori di query. Potresti dover eseguire un'ottimizzazione iterativa i valori migliori per il tuo carico di lavoro specifico.

Ecco alcune linee guida utili da seguire per scegliere valori appropriati:

  • tree_depth (a livello di albero): se la tabella da indicizzare ha meno di 10 milioni di righe, utilizza un valore tree_depth di 2. In caso contrario, un valore di tree_depth di 3 supporta tabelle con un massimo di 10 miliardi di righe.

  • num_leaves: utilizza la radice quadrata del numero di righe nel set di dati. Un valore più elevato può aumentare il tempo di compilazione dell'indice di vettori. Evita di impostare num_leaves più grande di table_row_count/1000, perché le foglie sono troppo piccole e un rendimento scarso.

  • num_leaves_to_search: questa opzione specifica il numero di nodi fogli dell'indice sottoposti a ricerca. L'aumento di num_leaves_to_search migliora il richiamo, ma aumenta anche la latenza e i costi. Ti consigliamo di utilizzare un numero che corrisponda all'1% del totale numero di foglie definito nell'istruzione CREATE VECTOR INDEX come valore per num_leaves_to_search. Se utilizzi una clausola di filtro, aumenta questo valore per ampliare la ricerca.

Se si ottiene un richiamo accettabile, ma il costo dell'interrogazione è troppo elevato, generando un valore QPS massimo basso, prova ad aumentare num_leaves seguendo questi passaggi:

  1. Imposta num_leaves su alcuni multipli k del suo valore originale (ad esempio, 2 * sqrt(table_row_count)).
  2. Imposta num_leaves_to_search come lo stesso multiplo k del valore originale.
  3. Prova a ridurre num_leaves_to_search per migliorare il costo e il QPS mantenendo il richiamo.

Migliorare il ricordo

Esistono diverse possibilità di peggioramento del richiamo, tra cui:

  • num_leaves_to_search è troppo piccolo: potresti riscontrare difficoltà a trovare i vicini più prossimi per alcuni vettori di query, quindi aumentare num_leaves_to_search per cercare più foglie può contribuire a migliorare il richiamo. Le query recenti potrebbero aver iniziato a contenere più di questi vettori difficili.

  • L'indice di vettori deve essere ricostruito: la struttura ad albero dell'indice di vettori è ottimizzata per il set di dati al momento della creazione ed è statica in seguito. Pertanto, se vengono aggiunti vettori notevolmente diversi dopo la creazione dell'indice iniziale dei vettori, la struttura ad albero potrebbe non essere ottimale, con un conseguente peggioramento del recupero.

Ricrea l'indice vettoriale

Per ricreare l'indice vettoriale senza tempi di inattività:

  1. Crea un nuovo indice vettoriale nella stessa colonna di incorporamento del vettore corrente di Google, aggiornando i parametri (ad es. OPTIONS) in modo appropriato.
  2. Al termine della creazione dell'indice, modifica il suggerimento FORCE_INDEX puntare al nuovo indice per aggiornare la query di ricerca vettoriale. In questo modo, la query utilizzerà il nuovo indice di vettori. Potresti anche dover eseguire nuovamente l'accordatura num_leaves_to_search nella nuova query.
  3. Elimina l'indice vettoriale obsoleto.

Passaggi successivi