Questo documento illustra come ottimizzare gli indici per ottenere prestazioni di query più rapide e una migliore capacità di recupero.
Sintonizzare 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 potare lo spazio di ricerca, mentre la quantizzazione viene utilizzata per comprimere le dimensioni dell'indice. Questa potatura accelera il calcolo del punteggio della somiglianza (ovvero della distanza) tra il vettore della query e i vettori del database.
Per ottenere sia un numero elevato di query al secondo (QPS)
che un'elevata percentuale di recall con le query del vicino più vicino, devi suddividere
la struttura ad albero dell'indice ScaNN
nel modo più appropriato per i tuoi dati
e le tue query.
Prima di creare un indice ScaNN
, completa quanto segue:
- Assicurati che sia già stata creata una tabella con i tuoi dati.
- Assicurati che il valore impostato per i 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 dell'indice e i flag del database vengono utilizzati insieme per trovare il giusto equilibrio tra il richiamo e la QPS. Tutti i parametri si applicano a entrambi i tipi di indici 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 durante la creazione influisce sulle prestazioni dell'indice. Aumentando le partizioni per un numero predefinito di vettori, crei un indice più granulare, che migliora il recupero 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 num_leaves_value quando crei un indice ad albero a tre livelli per ottenere prestazioni migliori.
|
Creazione di indici |
quantizer |
Il tipo di quantizzatore da utilizzare per l'albero K-means. Il valore predefinito è SQ8 per migliorare le prestazioni delle query.Impostalo su FLAT per migliorare il recupero. |
Creazione di indici |
enable_pca |
Attiva l'analisi delle componenti principali (PCA), una tecnica di riduzione delle dimensioni utilizzata per ridurre automaticamente le dimensioni dell'embedding, se possibile. Questa opzione è attiva per impostazione predefinita. Imposta su false se noti un peggioramento del recupero. |
Creazione di indici |
scann.num_leaves_to_search |
Il flag del database controlla il compromesso tra il richiamo e le QPS. Il valore predefinito è l'1% del valore impostato in num_leaves . Maggiore è il valore impostato, migliore è il richiamo, ma il 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 un ranking ai candidati vicini sottoposti a scansione in memoria anziché sul disco. Il valore predefinito è 20000 . Maggiore è il valore impostato, migliore è il QPS nelle query filtrate, ma aumenta l'utilizzo della memoria e viceversa. |
Tempo di esecuzione della query |
scann.pre_reordering_num_neighbors |
Se impostato, il flag del database specifica il numero di vicini candidati da considerare durante le fasi di riordinamento dopo che la ricerca iniziale ha identificato un insieme di candidati. Imposta questo valore su un valore superiore al numero di vicini che vuoi che la query restituisca. Gli insiemi di valori più elevati generano 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 di indici |
Sintonizzare un indice ScaNN
Considera i seguenti esempi di 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 in una tabella in cui è già stato generato un indice ScaNN
influisce sul modo in cui l'albero appreso ottimizza l'indice. Se la tabella è soggetta a aggiornamenti o inserimenti frequenti, ti consigliamo di eseguire periodicamente la reindicizzazione dell'indice ScaNN
esistente per migliorare l'accuratezza del recupero.
Puoi monitorare le metriche dell'indice per determinare il numero di mutazioni create dall'inizializzazione dell'indice e poi eseguire nuovamente l'indicizzazione di conseguenza. Per maggiori informazioni sulle metriche, consulta Metriche dell'indice vettoriale.
Best practice per la messa a punto
A seconda del tipo di indice ScaNN
che prevedi di utilizzare, i consigli per l'ottimizzazione dell'indice variano. Questa sezione fornisce consigli su come ottimizzare i parametri dell'indice per un equilibrio ottimale tra il recupero e le 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:
- 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
, fino a raggiungere l'intervallo di recupero target, ad esempio il 95%. Per ulteriori informazioni sull'analisi delle query, consulta 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 recupero target.
Se utilizzi vettori di dimensioni elevate (500 dimensioni o più) e vuoi migliorare il recupero, prova a ottimizzare 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 QPS è troppo basso dopo che le query hanno raggiunto un recupero 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 nell'indicenum_leaves
è impostato sulla radice quadrata del numero di righe, prova a impostarlo sul doppio della radice quadrata. Se il valore è già raddoppiato, prova a impostarlo sul triplo della radice quadrata. - Aumenta
scann.num_leaves_to_search
in base alle esigenze 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 il QPS mantenendo alto il recupero. Prova valori diversi perscann.num_leaves_to_search
senza ricostruire l'indice.
- Ricrea l'indice aumentando il valore di
- Ripeti il passaggio 4 finché sia la QPS sia l'intervallo di recupero non hanno raggiunto valori accettabili.
Indice ad albero a tre livelli
Oltre ai consigli per l'indice ad albero a due livelli ScaNN
, segui le indicazioni e i passaggi riportati di seguito per ottimizzare l'indice:
- L'aumento del valore
max_num_levels
da1
per un albero a due livelli a2
per un albero a tre livelli riduce notevolmente il tempo necessario per creare un indice, ma a spese 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 del vettore è compreso tra 10 milioni e 100 milioni, in base al bilanciamento del tempo di creazione dell'indice e alla precisione del recupero necessaria.
- 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:- Vettori di righe superiori a 100 milioni di righe: imposta
max_num_levels
su2
enum_leaves
supower(rows, ⅔)
. - Righe di vettori inferiori a 100 milioni: imposta
max_num_levels
su1
enum_leaves
susqrt(rows)
. - Vettori di righe compresi tra 10 e 100 milioni di righe: inizia impostando
max_num_levels
come1
enum_leaves
comesqrt(rows)
.
- Vettori di righe superiori a 100 milioni di righe: imposta
Esegui le query di test. Per ulteriori informazioni sull'analisi delle query, consulta Analizzare le query.
Se il tempo di creazione dell'indice è soddisfacente, mantieni il valore
max_num_levels
e prova il valorenum_leaves
per un'accuratezza del recupero ottimale.Se il tempo di creazione dell'indice non ti soddisfa, procedi nel seguente modo:
Se il valore
max_num_levels
è1
, elimina l'indice. Ricostruisci l'indice con il valoremax_num_levels
impostato su2
.Esegui le query e ottimizza il valore
num_leaves
per un'accuratezza del recupero ottimale.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 della tua applicazione:
Parametro di ottimizzazione | Descrizione | Tipo di parametro |
---|---|---|
lists |
Il numero di elenchi creati durante la creazione dell'indice. Il punto di partenza per l'impostazione di questo valore è (rows)/1000 per un massimo di un milione di righe e sqrt(rows) per più di un milione di righe. |
Creazione di indici |
quantizer |
Il tipo di quantizzatore da utilizzare per l'albero K-means. Il valore predefinito è SQ8 per un rendimento migliore delle query. Impostala su FLAT per un ricordo migliore. |
Creazione di indici |
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 |
Prendi in considerazione 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 l'impostazione di questo valore è (rows)/1000 per un massimo di un milione di righe e sqrt(rows) per più di un milione di righe. |
Creazione di indici |
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 database sia impostato su un valore sufficiente per velocizzare la creazione dell'indice in tabelle di grandi dimensioni.
Prendi in considerazione 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 da un nodo del grafo. Puoi iniziare con il valore predefinito 16 (predefinito) e provare valori più elevati in base alle dimensioni del set di dati. |
Creazione di indici |
ef_construction |
La dimensione dell'elenco di candidati dinamici mantenuto durante la costruzione del grafo, che aggiorna costantemente i candidati migliori attuali per i vicini più vicini di un nodo. Imposta questo valore su un valore superiore al doppio del valore m , ad esempio 64 (valore predefinito). |
Creazione di indici |
ef_search |
Le dimensioni dell'elenco di candidati dinamici utilizzato durante la ricerca. Puoi iniziare impostando questo valore su m o ef_construction , per poi modificarlo mentre osservi il recupero. Il valore predefinito è 40 . |
Tempo di esecuzione della query |
Prendi in considerazione 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);
Analizza le query
Utilizza il comando EXPLAIN ANALYZE
per analizzare gli approfondimenti sulle query, come mostrato nell'esempio di query SQL seguente.
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 analizzate 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 di vettori
Puoi utilizzare le metriche dell'indice di vettori per esaminare il rendimento dell'indice, identificare le aree di miglioramento e, se necessario, ottimizzare l'indice in base alle metriche.
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 ulteriori informazioni sull'elenco completo delle metriche, consulta Metriche dell'indice vettoriale.