Este documento mostra como ajustar seus índices para melhorar a performance da consulta e a recuperação.
Ajustar um índice ScaNN
O índice ScaNN usa indexação baseada em quantização de árvore. Em técnicas de quantização em árvore, os índices aprendem uma árvore de pesquisa com uma função de quantização (ou hash). Quando você executa uma consulta, a árvore de pesquisa é usada para podar o espaço de pesquisa, enquanto a quantização é usada para compactar o tamanho do índice. Essa poda acelera a pontuação da similaridade (ou seja, distância) entre o vetor de consulta e os vetores do banco de dados.
Para alcançar uma alta taxa de consultas por segundo (QPS)
e uma alta recuperação com as consultas de vizinho mais próximo, é necessário particionar
a árvore do índice ScaNN
de uma forma mais adequada aos seus dados
e consultas.
Antes de criar um índice ScaNN
, faça o seguinte:
- Verifique se uma tabela com seus dados já foi criada.
- Verifique se o valor definido para a flag
maintenance_work_mem
e ashared_buffers
é menor do que a memória total da máquina para evitar problemas ao gerar o índice.
Parâmetros de ajuste
Os parâmetros de índice e as flags do banco de dados a seguir são usados juntos para encontrar o equilíbrio certo de recuperação e QPS. Todos os parâmetros se aplicam aos dois tipos de índice ScaNN
.
Parâmetro de ajuste | Descrição | Tipo de parâmetro |
---|---|---|
num_leaves |
O número de partições a serem aplicadas a este índice. O número de partições em que você aplica ao criar um índice afeta a performance do índice. Ao aumentar as partições para um número definido de vetores, você cria um índice mais refinado, o que melhora a recuperação e a performance da consulta. No entanto, isso tem o custo de tempos mais longos de criação de índices. Como as árvores de três níveis são criadas mais rapidamente do que as de dois níveis, é possível aumentar o num_leaves_value ao criar um índice de árvore de três níveis para ter um desempenho melhor.
|
Criação de índice |
quantizer |
O tipo de quantizador que você quer usar para a árvore K-means. O valor padrão é SQ8 para melhorar o desempenho da consulta.Defina como FLAT para melhorar a recuperação. |
Criação de índice |
enable_pca |
Ativa a análise de componentes principais (PCA, na sigla em inglês), que é uma técnica de redução de dimensão usada para reduzir automaticamente
o tamanho da incorporação quando possível. Essa opção é ativada por padrão. Defina como false se você notar uma deterioração na recuperação. |
Criação de índice |
scann.num_leaves_to_search |
O sinalizador do banco de dados controla a compensação entre o recall e o QPS. O valor padrão é 1% do valor definido em num_leaves . Quanto maior o valor definido, melhor é o recall, mas isso resulta em QPS menor e vice-versa. |
Tempo de execução da consulta |
scann.max_top_neighbors_buffer_size |
A flag do banco de dados especifica o tamanho do cache usado para melhorar a performance das consultas filtradas ao pontuar ou classificar os vizinhos candidatos verificados na memória em vez do disco. O valor padrão é 20000 . Quanto maior o valor definido, melhor é o QPS em consultas filtradas, mas isso resulta em maior uso de memória e vice-versa. |
Tempo de execução da consulta |
scann.pre_reordering_num_neighbors |
A flag do banco de dados, quando definida, especifica o número de vizinhos candidatos a serem considerados durante as fases de reordenação depois que a pesquisa inicial identifica um conjunto de candidatos. Defina um valor maior do que o número de vizinhos que você quer que a consulta retorne. Conjuntos de valores mais altos resultam em um recall melhor, mas essa abordagem resulta em QPS mais baixo. |
Tempo de execução da consulta |
max_num_levels |
O número máximo de níveis da árvore de clusterização K-means.
|
Criação de índice |
Ajustar um índice ScaNN
Confira os exemplos a seguir de índices ScaNN
de dois e três níveis que mostram como os parâmetros de ajuste são definidos:
Índice de dois níveis
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)]);
Índice de três níveis
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);
Qualquer operação de inserção ou atualização em uma tabela em que um índice ScaNN
já foi
gerado afeta a forma como a árvore aprendida otimiza o índice. Se
a tabela for propensa a atualizações ou inserções frequentes, recomendamos
reindexar periodicamente o índice ScaNN
para melhorar a precisão da recuperação.
É possível monitorar as métricas de índice para determinar a quantidade de mutações criadas desde a criação do índice e, em seguida, reindexar de acordo. Para mais informações sobre métricas, consulte Métricas de índice vetorial.
Práticas recomendadas para ajuste
Com base no tipo de índice ScaNN
que você pretende usar, as recomendações para ajustar o índice variam. Esta seção fornece recomendações sobre como ajustar os parâmetros de índice para um equilíbrio ideal entre recuperação e QPS.
Índice de árvore de dois níveis
Para aplicar recomendações e encontrar os valores ideais de num_leaves
e num_leaves_to_search
para seu conjunto de dados,
siga estas etapas:
- Crie o índice
ScaNN
comnum_leaves
definido como a raiz quadrada da contagem de linhas da tabela indexada. - Execute as consultas de teste, aumentando o valor de
scann.num_of_leaves_to_search
, até atingir o intervalo de recuperação desejado, por exemplo, 95%. Para mais informações sobre como analisar suas consultas, consulte Analisar suas consultas. - Anote a proporção entre
scann.num_leaves_to_search
enum_leaves
que será usada nas próximas etapas. Essa proporção fornece uma aproximação do conjunto de dados que vai ajudar você a alcançar a recuperação desejada.
Se você estiver trabalhando com vetores de alta dimensão (500 ou mais) e quiser melhorar a recuperação, tente ajustar o valor descann.pre_reordering_num_neighbors
. Como ponto de partida, defina o valor como100 * sqrt(K)
, em queK
é o limite definido na consulta. - Se a QPS estiver muito baixa depois que as consultas atingirem uma recuperação desejada, siga estas etapas:
- Recrie o índice, aumentando o valor de
num_leaves
escann.num_leaves_to_search
de acordo com as seguintes orientações:- Defina
num_leaves
como um fator maior da raiz quadrada da contagem de linhas. Por exemplo, se o índice tivernum_leaves
definido como a raiz quadrada da contagem de linhas, tente definir o dobro da raiz quadrada. Se o valor já for o dobro, tente definir o valor para triplicar a raiz quadrada. - Aumente
scann.num_leaves_to_search
conforme necessário para manter a proporção comnum_leaves
, que você anotou na etapa 3. - Defina
num_leaves
como um valor menor ou igual à contagem de linhas dividida por 100.
- Defina
- Execute as consultas de teste novamente.
Enquanto executa as consultas de teste, tente reduzir
scann.num_leaves_to_search
, encontrando um valor que aumente a QPS mantendo o recall alto. Tente valores diferentes descann.num_leaves_to_search
sem reconstruir o índice.
- Recrie o índice, aumentando o valor de
- Repita a etapa 4 até que a QPS e o intervalo de recuperação atinjam valores aceitáveis.
Índice de árvore de três níveis
Além das recomendações para o índice ScaNN
de árvore de dois níveis, use as orientações e as etapas a seguir para ajustar o índice:
- Aumentar o
max_num_levels
de1
para uma árvore de dois níveis para2
para uma árvore de três níveis reduz significativamente o tempo de criação de um índice, mas à custa da precisão de recuperação. Definamax_num_levels
usando a seguinte recomendação:- Defina o valor como
2
se o número de linhas do vetor exceder 100 milhões. - Defina o valor como
1
se o número de linhas do vetor for inferior a 10 milhões. - Defina como
1
ou2
se o número de linhas do vetor estiver entre 10 milhões e 100 milhões, com base no equilíbrio do tempo de criação do índice e na precisão de recuperação necessária.
- Defina o valor como
Para aplicar recomendações e encontrar o valor ideal dos parâmetros de índice num_leaves
e max_num_levels
, siga estas etapas:
Crie o índice
ScaNN
com as seguintes combinações denum_leaves
emax_num_levels
com base no seu conjunto de dados:- Linhas de vetor maiores que 100 milhões: defina
max_num_levels
como2
enum_leaves
comopower(rows, ⅔)
. - Linhas de vetor com menos de 100 milhões de linhas: defina
max_num_levels
como1
enum_leaves
comosqrt(rows)
. - Linhas de vetor entre 10 milhões e 100 milhões: comece definindo
max_num_levels
como1
enum_leaves
comosqrt(rows)
.
- Linhas de vetor maiores que 100 milhões: defina
Execute as consultas de teste. Para mais informações sobre como analisar consultas, consulte Analisar suas consultas.
Se o tempo de criação do índice for satisfatório, mantenha o valor
max_num_levels
e teste o valornum_leaves
para uma precisão de recuperação ideal.Se você não estiver satisfeito com o tempo de criação do índice, faça o seguinte:
Se o valor
max_num_levels
for1
, exclua o índice. Recrie o índice com o valormax_num_levels
definido como2
.Execute as consultas e ajuste o valor de
num_leaves
para ter a precisão de recuperação ideal.Se o valor de
max_num_levels
for2
, exclua o índice. Recrie o índice com o mesmo valor demax_num_levels
e ajuste o valor denum_leaves
para uma precisão de recuperação ideal.
Ajustar um índice IVF
Ajustar os valores definidos para os parâmetros lists
, ivf.probes
e quantizer
pode
ajudar a otimizar o desempenho do seu aplicativo:
Parâmetro de ajuste | Descrição | Tipo de parâmetro |
---|---|---|
lists |
O número de listas criadas durante a criação do índice. O ponto de partida para definir esse valor é (rows)/1000 para até um milhão de linhas e sqrt(rows) para mais de um milhão de linhas. |
Criação de índice |
quantizer |
O tipo de quantizador que você quer usar para a árvore K-means. O valor padrão é SQ8 para melhorar a performance da consulta. Defina como FLAT para melhorar a recuperação. |
Criação de índice |
ivf.probes |
o número de listas mais próximas para explorar durante a pesquisa. O ponto de partida desse valor é sqrt(lists) . |
Tempo de execução da consulta |
Considere o exemplo a seguir, que mostra um índice IVF
com os parâmetros de ajuste definidos:
SET LOCAL ivf.probes = 10;
CREATE INDEX my-ivf-index ON my-table
USING ivf (vector_column cosine)
WITH (lists = 100, quantizer = 'SQ8');
Ajustar um índice IVFFlat
Ajustar os valores definidos para os parâmetros lists
e ivfflat.probes
pode
ajudar a otimizar o desempenho do aplicativo:
Parâmetro de ajuste | Descrição | Tipo de parâmetro |
---|---|---|
lists |
O número de listas criadas durante a criação do índice. O ponto de partida para definir esse valor é (rows)/1000 para até um milhão de linhas e sqrt(rows) para mais de um milhão de linhas. |
Criação de índice |
ivfflat.probes |
O número de listas mais próximas para explorar durante a pesquisa. O ponto de partida desse valor é sqrt(lists) . |
Tempo de execução da consulta |
Antes de criar um índice IVFFlat
, verifique se a flag
max_parallel_maintenance_workers
do seu banco de dados está definida com um valor suficiente para agilizar
a criação de índices em tabelas grandes.
Considere o exemplo a seguir, que mostra um índice IVFFlat
com os parâmetros de ajuste definidos:
SET LOCAL ivfflat.probes = 10;
CREATE INDEX my-ivfflat-index ON my-table
USING ivfflat (vector_column cosine)
WITH (lists = 100);
Ajustar um índice HNSW
Ajustar os valores definidos para os parâmetros m
, ef_construction
e hnsw.ef_search
pode
ajudar a otimizar o desempenho do aplicativo.
Parâmetro de ajuste | Descrição | Tipo de parâmetro |
---|---|---|
m |
O número máximo de conexões por nó no gráfico. Você pode começar com o valor padrão 16 (padrão) e testar valores mais altos com base no tamanho do conjunto de dados. |
Criação de índice |
ef_construction |
O tamanho da lista de candidatos dinâmicos mantida durante a construção do gráfico, que atualiza constantemente os melhores candidatos atuais para vizinhos mais próximos de um nó. Defina esse valor como qualquer valor maior que o dobro do valor de m . Por exemplo, 64 (padrão). |
Criação de índice |
ef_search |
O tamanho da lista dinâmica de candidatos usada durante a pesquisa. Você pode começar a definir esse valor como m ou ef_construction e, em seguida, mudar enquanto observa a recuperação. O valor padrão é 40 . |
Tempo de execução da consulta |
Considere o exemplo a seguir, que mostra um índice hnsw
com os parâmetros de ajuste definidos:
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);
Analisar suas consultas
Use o comando EXPLAIN ANALYZE
para analisar os insights da consulta, conforme mostrado no exemplo de consulta SQL a seguir.
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;
O exemplo de resposta QUERY PLAN
inclui informações como o tempo gasto, o número de linhas digitalizadas ou retornadas e os recursos usados.
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
Conferir métricas do índice vetorial
É possível usar as métricas do índice de vetor para analisar a performance do índice, identificar áreas para melhoria e ajustar o índice com base nas métricas, se necessário.
Para conferir todas as métricas do índice de vetor, execute a consulta SQL abaixo, que usa a visualização pg_stat_ann_indexes
:
SELECT * FROM pg_stat_ann_indexes;
Para mais informações sobre a lista completa de métricas, consulte Métricas de índice vetorial.