Questo documento mostra come ottimizzare gli indici per ottenere prestazioni delle query più rapide e un migliore richiamo.
Ottimizzare un indice ScaNN
L'indice ScaNN utilizza l'indicizzazione basata sulla quantizzazione ad albero. Nelle tecniche di quantizzazione ad albero, gli indici apprendono un albero di ricerca insieme a una funzione di quantizzazione (o hashing). Quando esegui una query, l'albero di ricerca viene utilizzato per ridurre lo spazio di ricerca, mentre la quantizzazione viene utilizzata per comprimere le dimensioni dell'indice. Questa potatura accelera il calcolo della somiglianza (ovvero della distanza) tra il vettore della query e i vettori del database.
Per ottenere una frequenza di query al secondo (QPS) elevata
e un richiamo elevato con le query dei vicini più prossimi, devi partizionare
l'albero dell'indice ScaNN
nel modo più appropriato per i tuoi dati
e le tue query.
Prima di creare un indice ScaNN
, completa le seguenti operazioni:
- Assicurati che sia già stata creata una tabella con i tuoi dati.
- Assicurati che il valore impostato per il flag
maintenance_work_mem
eshared_buffers
sia inferiore alla memoria totale della macchina per evitare problemi durante la generazione dell'indice.
Parametri di correzione
I seguenti parametri di indice e flag di database vengono utilizzati insieme per trovare il giusto equilibrio tra richiamo e QPS. Tutti i parametri si applicano a entrambi i tipi di indice ScaNN
.
Parametro di ottimizzazione | Descrizione | Tipo di parametro |
---|---|---|
num_leaves |
Il numero di partizioni da applicare a questo indice. Il numero di partizioni a cui applichi un indice al momento della creazione influisce sulle prestazioni dell'indice. Aumentando le partizioni per un numero fisso di vettori, crei un indice più granulare, che migliora il richiamo e le prestazioni delle query. Tuttavia, questo comporta tempi di creazione dell'indice più lunghi. Poiché gli alberi a tre livelli vengono creati più velocemente di quelli a due livelli, puoi aumentare il valore di num_leaves_value durante la creazione di un indice ad albero a tre livelli per ottenere prestazioni migliori.
|
Creazione dell'indice |
quantizer |
Il tipo di quantizzatore che vuoi utilizzare per l'albero K-means. Il valore predefinito è SQ8 per migliorare il rendimento delle query.Imposta il valore su FLAT per un migliore recupero. |
Creazione dell'indice |
enable_pca |
Attiva l'analisi delle componenti principali (PCA), una tecnica di riduzione delle dimensioni utilizzata per ridurre automaticamente
le dimensioni dell'incorporamento quando possibile. Questa opzione è attivata per impostazione predefinita. Imposta su false se noti un peggioramento del richiamo. |
Creazione dell'indice |
scann.num_leaves_to_search |
Il flag del database controlla il compromesso tra richiamo e QPS. Il valore predefinito è l'1% del valore impostato in num_leaves . Più alto è il valore impostato, migliore è il richiamo, ma si traduce in un QPS inferiore e viceversa. |
Tempo di esecuzione della query |
scann.max_top_neighbors_buffer_size |
Il flag del database specifica le dimensioni della cache utilizzata per migliorare le prestazioni delle query filtrate assegnando un punteggio o classificando i vicini candidati scansionati in memoria anziché sul disco. Il valore predefinito è 20000 . Più alto è il valore impostato, migliore è il QPS nelle query filtrate, ma comporta un maggiore utilizzo della memoria e viceversa. |
Tempo di esecuzione della query |
scann.pre_reordering_num_neighbors |
Il flag del database, se impostato, specifica il numero di vicini candidati da considerare durante le fasi di riordinamento dopo che la ricerca iniziale identifica un insieme di candidati. Imposta questo valore su un valore superiore al numero di vicini che vuoi che la query restituisca. Set di valori più elevati comportano un richiamo migliore, ma questo approccio comporta un QPS inferiore. |
Tempo di esecuzione della query |
max_num_levels |
Il numero massimo di livelli dell'albero di clustering K-means.
|
Creazione dell'indice |
Ottimizzare un indice ScaNN
Prendi in considerazione i seguenti esempi per gli indici ScaNN
a due e tre livelli che mostrano come vengono impostati i parametri di ottimizzazione:
Indice a due livelli
SET LOCAL scann.num_leaves_to_search = 1;
SET LOCAL scann.pre_reordering_num_neighbors=50;
CREATE INDEX my-scann-index ON my-table
USING scann (vector_column cosine)
WITH (num_leaves = [power(1000000, 1/2)]);
Indice a tre livelli
SET LOCAL scann.num_leaves_to_search = 10;
SET LOCAL scann.pre_reordering_num_neighbors=50;
CREATE INDEX my-scann-index ON my-table
USING scann (vector_column cosine)
WITH (num_leaves = [power(1000000, 2/3)], max_num_levels = 2);
Qualsiasi operazione di inserimento o aggiornamento su una tabella in cui è già stato generato un indice ScaNN
influisce sul modo in cui l'albero appreso ottimizza l'indice. Se
la tua tabella è soggetta a aggiornamenti o inserimenti frequenti, ti consigliamo di
reindicizzare periodicamente l'indice ScaNN
esistente per migliorare l'accuratezza del recupero.
Puoi monitorare le metriche dell'indice per determinare il numero di mutazioni create dalla creazione dell'indice e poi eseguire nuovamente l'indicizzazione di conseguenza. Per maggiori informazioni sulle metriche, consulta Metriche dell'indice vettoriale.
Best practice per l'ottimizzazione
A seconda del tipo di indice ScaNN
che prevedi di utilizzare, i suggerimenti per ottimizzare l'indice variano. Questa sezione fornisce consigli su come ottimizzare i parametri dell'indice per ottenere un equilibrio ottimale tra richiamo e QPS.
Indice ad albero a due livelli
Per applicare i consigli che ti aiutano a trovare i valori ottimali di num_leaves
e num_leaves_to_search
per il tuo set di dati,
segui questi passaggi:
- Crea l'indice
ScaNN
connum_leaves
impostato sulla radice quadrata del conteggio delle righe della tabella indicizzata. - Esegui le query di test, aumentando il valore di
scann.num_of_leaves_to_search
, finché non raggiungi l'intervallo di richiamo target, ad esempio il 95%. Per ulteriori informazioni sull'analisi delle query, vedi Analizzare le query. - Prendi nota del rapporto tra
scann.num_leaves_to_search
enum_leaves
che verrà utilizzato nei passaggi successivi. Questo rapporto fornisce un'approssimazione del set di dati che ti aiuterà a raggiungere il richiamo target.
Se lavori con vettori di dimensioni elevate (500 dimensioni o più) e vuoi migliorare il richiamo, prova a modificare il valore discann.pre_reordering_num_neighbors
. Come punto di partenza, imposta il valore su100 * sqrt(K)
, doveK
è il limite impostato nella query. - Se il tuo QPS è troppo basso dopo che le query raggiungono un richiamo target, segui questi passaggi:
- Ricrea l'indice, aumentando il valore di
num_leaves
escann.num_leaves_to_search
in base alle seguenti indicazioni:- Imposta
num_leaves
su un fattore maggiore della radice quadrata del numero di righe. Ad esempio, se l'indice hanum_leaves
impostato sulla radice quadrata del conteggio delle righe, prova a impostarlo sul doppio della radice quadrata. Se il valore è già il doppio, prova a impostarlo sul triplo della radice quadrata. - Aumenta
scann.num_leaves_to_search
in base alle necessità per mantenere il rapporto connum_leaves
, che hai annotato nel passaggio 3. - Imposta
num_leaves
su un valore minore o uguale al numero di righe diviso per 100.
- Imposta
- Esegui di nuovo le query di test.
Mentre esegui le query di test, prova a ridurre
scann.num_leaves_to_search
, trovando un valore che aumenti le QPS mantenendo un richiamo elevato. Prova valori diversi discann.num_leaves_to_search
senza ricompilare l'indice.
- Ricrea l'indice, aumentando il valore di
- Ripeti il passaggio 4 finché sia il QPS sia l'intervallo di richiamo non avranno raggiunto valori accettabili.
Indice ad albero a tre livelli
Oltre ai consigli per l'indice dell'albero a due livelli ScaNN
, utilizza le seguenti indicazioni e i passaggi per ottimizzare l'indice:
- Aumentare il valore di
max_num_levels
da1
per un albero a due livelli a2
per un albero a tre livelli riduce significativamente il tempo necessario per creare un indice, ma a scapito dell'accuratezza del richiamo. Impostamax_num_levels
utilizzando il seguente consiglio:- Imposta il valore su
2
se il numero di righe del vettore supera i 100 milioni. - Imposta il valore su
1
se il numero di righe del vettore è inferiore a 10 milioni. - Imposta
1
o2
se il numero di righe vettoriali è compreso tra 10 milioni e 100 milioni di righe, in base al bilanciamento del tempo di creazione dell'indice e alla precisione del recupero che ti serve.
- Imposta il valore su
Per applicare i consigli per trovare il valore ottimale dei parametri di indice num_leaves
e max_num_levels
:
Crea l'indice
ScaNN
con le seguenti combinazioni dinum_leaves
emax_num_levels
in base al tuo set di dati:- Righe vettoriali superiori a 100 milioni di righe: imposta
max_num_levels
come2
enum_leaves
comepower(rows, ⅔)
. - Righe vettoriali inferiori a 100 milioni di righe: imposta
max_num_levels
come1
enum_leaves
comesqrt(rows)
. - Righe di vettori tra 10 milioni e 100 milioni di righe: inizia impostando
max_num_levels
come1
enum_leaves
comesqrt(rows)
.
- Righe vettoriali superiori a 100 milioni di righe: imposta
Esegui le query di test. Per maggiori informazioni sull'analisi delle query, vedi Analizzare le query.
Se il tempo di creazione dell'indice è soddisfacente, mantieni il valore
max_num_levels
e prova con il valorenum_leaves
per un'accuratezza ottimale del recupero.Se non sei soddisfatto del tempo di creazione dell'indice, procedi nel seguente modo:
Se il valore di
max_num_levels
è1
, elimina l'indice. Ricostruisci l'indice con il valoremax_num_levels
impostato su2
.Esegui le query e regola il valore di
num_leaves
per un'accuratezza ottimale del richiamo.Se il valore
max_num_levels
è2
, elimina l'indice. Ricostruisci l'indice con lo stesso valoremax_num_levels
e ottimizza il valorenum_leaves
per una precisione di recupero ottimale.
Ottimizzare un indice IVF
La regolazione dei valori impostati per i parametri lists
, ivf.probes
e quantizer
potrebbe
contribuire a ottimizzare il rendimento dell'applicazione:
Parametro di ottimizzazione | Descrizione | Tipo di parametro |
---|---|---|
lists |
Il numero di elenchi creati durante la creazione dell'indice. Il punto di partenza per impostare questo valore è (rows)/1000 per un massimo di un milione di righe e sqrt(rows) per più di un milione di righe. |
Creazione dell'indice |
quantizer |
Il tipo di quantizzatore che vuoi utilizzare per l'albero K-means. Il valore predefinito è SQ8 per migliorare il rendimento delle query. Imposta il valore su FLAT per un migliore ricordo. |
Creazione dell'indice |
ivf.probes |
il numero di elenchi più vicini da esplorare durante la ricerca. Il punto di partenza per questo valore è sqrt(lists) . |
Tempo di esecuzione della query |
Considera l'esempio seguente che mostra un indice IVF
con i parametri di ottimizzazione impostati:
SET LOCAL ivf.probes = 10;
CREATE INDEX my-ivf-index ON my-table
USING ivf (vector_column cosine)
WITH (lists = 100, quantizer = 'SQ8');
Ottimizzare un indice IVFFlat
La regolazione dei valori impostati per i parametri lists
e ivfflat.probes
può
contribuire a ottimizzare il rendimento dell'applicazione:
Parametro di ottimizzazione | Descrizione | Tipo di parametro |
---|---|---|
lists |
Il numero di elenchi creati durante la creazione dell'indice. Il punto di partenza per impostare questo valore è (rows)/1000 per un massimo di un milione di righe e sqrt(rows) per più di un milione di righe. |
Creazione dell'indice |
ivfflat.probes |
Il numero di elenchi più vicini da esplorare durante la ricerca. Il punto di partenza per questo valore è sqrt(lists) . |
Tempo di esecuzione della query |
Prima di creare un indice IVFFlat
, assicurati che il flag max_parallel_maintenance_workers
del tuo database sia impostato su un valore sufficiente ad accelerare la creazione dell'indice nelle tabelle di grandi dimensioni.
Considera l'esempio seguente che mostra un indice IVFFlat
con i parametri di ottimizzazione impostati:
SET LOCAL ivfflat.probes = 10;
CREATE INDEX my-ivfflat-index ON my-table
USING ivfflat (vector_column cosine)
WITH (lists = 100);
Ottimizzare un indice HNSW
La regolazione dei valori impostati per i parametri m
, ef_construction
e hnsw.ef_search
può
contribuire a ottimizzare il rendimento dell'applicazione.
Parametro di ottimizzazione | Descrizione | Tipo di parametro |
---|---|---|
m |
Il numero massimo di connessioni per nodo nel grafico. Puoi iniziare con il valore predefinito 16 (impostazione predefinita) e sperimentare con valori più alti in base alle dimensioni del set di dati. |
Creazione dell'indice |
ef_construction |
La dimensione dell'elenco dinamico di candidati mantenuto durante la costruzione del grafico, che aggiorna costantemente i migliori candidati attuali per i vicini più prossimi di un nodo. Imposta questo valore su un valore superiore al doppio del valore di m , ad esempio 64 (valore predefinito). |
Creazione dell'indice |
ef_search |
La dimensione dell'elenco dinamico di candidati utilizzato durante la ricerca. Puoi iniziare a impostare questo valore su m o ef_construction e poi modificarlo osservando il richiamo. Il valore predefinito è 40 . |
Tempo di esecuzione della query |
Considera l'esempio seguente che mostra un indice hnsw
con i parametri di ottimizzazione impostati:
SET LOCAL hnsw.ef_search = 40;
CREATE INDEX my-hnsw-index ON my-table
USING hnsw (vector_column cosine)
WITH (m = 16, ef_construction = 200);
Analizzare le query
Utilizza il comando EXPLAIN ANALYZE
per analizzare gli approfondimenti sulle query come mostrato nella seguente query SQL di esempio.
EXPLAIN ANALYZE SELECT result-column FROM my-table
ORDER BY EMBEDDING_COLUMN ::vector
USING INDEX my-scann-index
<-> embedding('textembedding-gecko@003', 'What is a database?')
LIMIT 1;
La risposta di esempio QUERY PLAN
include informazioni quali il tempo impiegato, il numero di righe scansionate o restituite e le risorse utilizzate.
Limit (cost=0.42..15.27 rows=1 width=32) (actual time=0.106..0.132 rows=1 loops=1)
-> Index Scan using my-scann-index on my-table (cost=0.42..858027.93 rows=100000 width=32) (actual time=0.105..0.129 rows=1 loops=1)
Order By: (embedding_column <-> embedding('textgecko@003', 'What is a database?')::vector(768))
Limit value: 1
Planning Time: 0.354 ms
Execution Time: 0.141 ms
Visualizzare le metriche dell'indice vettoriale
Puoi utilizzare le metriche dell'indice vettoriale per esaminare il rendimento dell'indice vettoriale, identificare le aree da migliorare e ottimizzare l'indice in base alle metriche, se necessario.
Per visualizzare tutte le metriche dell'indice vettoriale, esegui la seguente query SQL, che utilizza la vista pg_stat_ann_indexes
:
SELECT * FROM pg_stat_ann_indexes;
Per saperne di più sull'elenco completo delle metriche, consulta Metriche dell'indice vettoriale.