Ativar e usar a extensão DiskANN no Base de Dados do Azure para PostgreSQL flexible server

O DiskANN é um algoritmo escalável para busca de vizinho mais próximo aproximada, permitindo uma busca vetorial eficiente em qualquer escala. Ele oferece alta recuperação, altas consultas por segundo e baixa latência de consulta, mesmo para conjuntos de dados de bilhões de pontos. Essas características o tornam uma ferramenta poderosa para lidar com grandes volumes de dados.

Para saber mais sobre o DiskANN, consulte DiskANN: Pesquisa Vetorial para Pesquisa e Recomendação em Escala Web.

A pg_diskann extensão adiciona suporte para o uso do DiskANN para indexação vetorial e pesquisa eficientes.

Ativar pg_diskann

Para usar a extensão pg_diskann no seu servidor flexível do Base de Dados do Azure para PostgreSQL, tem de permitir a extensão ao nível do servidor. Em seguida, você precisa criar a extensão em cada banco de dados no qual você deseja usar a funcionalidade fornecida pela extensão.

Como o pg_diskann tem uma dependência da extensão vector, deve permitir e criar a extensão na mesma base de dados e deve executar o seguinte comando:

CREATE EXTENSION IF NOT EXISTS pg_diskann;

Ou você pode ignorar explicitamente a permissão e a criação da vector extensão e, em vez disso, executar o comando anterior anexando a CASCADE cláusula. A cláusula faz com que o PostgreSQL execute implicitamente CREATE EXTENSION na extensão de que depende. Para tal, execute o seguinte comando:

CREATE EXTENSION IF NOT EXISTS pg_diskann CASCADE;

Para soltar a extensão do banco de dados ao qual você está conectado no momento, execute o seguinte comando:

DROP EXTENSION IF EXISTS pg_diskann;

Usar o método de acesso ao índice DiskANN

Depois de instalar a extensão, pode criar um diskann índice numa coluna de tabela que contenha dados vetoriais. Por exemplo, para criar um índice na embedding coluna da demo tabela, use o seguinte comando:

CREATE TABLE demo (
 id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
 embedding public.vector(3)
 -- other columns
);

-- insert dummy data
INSERT INTO demo (embedding) VALUES
('[1.0, 2.0, 3.0]'),
('[4.0, 5.0, 6.0]'),
('[7.0, 8.0, 9.0]');

-- create a diskann index by using Cosine distance operator
CREATE INDEX demo_embedding_diskann_idx ON demo USING diskann (embedding vector_cosine_ops)

Depois de criar o índice, pode fazer consultas para encontrar os vizinhos mais próximos.

A consulta seguinte encontra os cinco vizinhos mais próximos do vetor [2.0, 3.0, 4.0]:

SELECT id, embedding
FROM demo
ORDER BY embedding <=> '[2.0, 3.0, 4.0]'
LIMIT 5;

O Postgres decide automaticamente quando usar o índice DiskANN. Se optar por não usar o índice num cenário em que pretende que o utilize, execute o seguinte comando:

-- Explicit Transcation block to force use for DiskANN index.

BEGIN;
SET LOCAL enable_seqscan TO OFF;
-- Similarity search queries
COMMIT;

Importante

Definir enable_seqscan como desligado desencoraja o planeador de usar o plano de varrimento sequencial do planeador de consultas se existirem outros métodos disponíveis. Como está desativado ao usar o SET LOCAL comando, a definição só se aplica para a transação atual. Após um COMMIT ou ROLLBACK, a configuração de nível de sessão entra em vigor novamente. Se a consulta envolver outras tabelas, a definição também desencoraja o uso de varreduras sequenciais em todas elas.

Dimensione-se eficientemente com a quantização (Pré-visualização)

O DiskANN usa a quantização do produto (PQ) para reduzir drasticamente o espaço ocupado pela memória dos vetores. Ao contrário de outras técnicas de quantização, o algoritmo PQ pode comprimir vetores de forma mais eficaz, melhorando significativamente o desempenho.  Ao usar PQ, o DiskANN pode manter mais dados na memória, reduzir a necessidade de aceder a armazenamento mais lento e usar menos computação ao comparar vetores comprimidos. Isso resulta em melhor desempenho e economia de custos significativa ao trabalhar com grandes quantidades de dados (>1 milhão de linhas).

Importante

O suporte à quantização de produtos no DiskANN está disponível a partir de pg_diskann v0.6 e superior.

Para reduzir o tamanho do seu índice e caber mais dados na memória, use PQ:

CREATE INDEX demo_embedding_diskann_idx ON demo USING diskann(embedding vector_cosine_ops) 
WITH(
    product_quantized=true
    );    

Melhore a precisão ao usar PQ com reclassificação vetorial

A reclassificação com vetores completos é uma técnica usada em sistemas de pesquisa de vizinhos mais próximos aproximados (ANN), como o DiskANN com Quantização de Produto (PQ), para melhorar a precisão dos resultados, reordenando os candidatos recuperados do top-N usando os vetores originais, não compactados (precisão total). Esta técnica de reclassificação baseia-se puramente em métricas exatas de similaridade vetorial (por exemplo, similaridade cosseno ou distância euclidiana). Esta técnica não é a mesma que reclassificar usando um modelo de classificação.

Para equilibrar velocidade e precisão na pesquisa por similaridade vetorial, implemente uma estratégia de reclassificação em dois passos ao consultar com DiskANN e quantização de produtos para melhorar a precisão.

  1. Pesquisa aproximada inicial: a consulta interna usa o DiskANN para recuperar os 50 principais vizinhos aproximados mais próximos com base na distância cosseno entre as incorporações armazenadas e o vetor de consulta. Esta etapa é rápida e eficiente, aproveitando os recursos de indexação do DiskANN.

  2. Reclassificação precisa: A consulta externa reordena esses 50 resultados pela distância real calculada e retorna as 10 principais correspondências mais relevantes:

Aqui está um exemplo de reclassificação usando esta abordagem em dois passos:

SELECT id
FROM (
    SELECT id, embedding <=> %s::vector AS distance
    FROM demo
    ORDER BY embedding <=> %s::vector asc
    LIMIT 50
) AS t
ORDER BY t.distance
LIMIT 10;

Observação

Substitua%s pelo vetor de consulta. Você pode usar azure_ai para criar um vetor de consulta diretamente no Postgres.

Esta abordagem equilibra a velocidade (através da pesquisa aproximada) e a precisão (através da reclassificação completa do vetor), garantindo resultados de alta qualidade sem analisar todo o conjunto de dados.

Suporte para incorporações de alta dimensão

As aplicações avançadas de IA generativa geralmente dependem de modelos de representação de alta dimensão, como text-embedding-3-large, para alcançar uma precisão superior. No entanto, métodos tradicionais de indexação como HNSW em pgvector são limitados a vetores com até 2.000 dimensões, o que restringe o uso desses modelos poderosos.

A partir de pg_diskann v0.6 e posteriores, o DiskANN suporta vetores de indexação com até 16.000 dimensões, expandindo significativamente o âmbito para cargas de trabalho de IA de alta precisão.

Importante

Ativa a Quantização de Produto para aproveitar suporte de alta dimensão.

Configurações recomendadas:

  • product_quantized: Configurar para verdadeiro
  • pq_param_num_chunks: Defina para um terço da dimensão de incorporação para um desempenho ideal.
  • pq_param_training_samples: Determinado automaticamente com base no tamanho da tabela, a menos que explicitamente definido.

Esse aprimoramento permite uma pesquisa escalável e eficiente em grandes conjuntos de dados vetoriais, mantendo alta recuperação e precisão.

Acelere a criação do índice

Para melhorar os tempos de construção do seu índice, experimente as seguintes recomendações.

Usar mais memória

Para acelerar a criação do índice, aumente a memória alocada no seu servidor PostgreSQL para a construção do índice. Especifique o uso de memória através do maintenance_work_mem parâmetro.

-- Set the parameters
SET maintenance_work_mem = '8GB'; -- Depending on your resources

O CREATE INDEX comando utiliza a memória de trabalho especificada, dependendo dos recursos disponíveis, para construir o índice.

CREATE INDEX demo_embedding_diskann_idx ON demo USING diskann (embedding vector_cosine_ops)

Sugestão

Aumente os seus recursos de memória durante a construção do índice para melhorar a velocidade de indexação, depois reduza novamente quando a indexação estiver concluída.

Usando paralelização

Para acelerar a criação do índice, use trabalhadores paralelos. Especifique o número de trabalhadores através do parallel_workers parâmetro de armazenamento da CREATE TABLE instrução ao criar a tabela. Pode ajustar este número mais tarde usando a SET cláusula da ALTER TABLE declaração.

CREATE TABLE demo (
	id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
	embedding public.vector(3)
) WITH (parallel_workers = 4);
ALTER TABLE demo SET (parallel_workers = 8);

O CREATE INDEX comando utiliza o número especificado de trabalhadores paralelos, dependendo dos recursos disponíveis, para construir o índice.

CREATE INDEX demo_embedding_diskann_idx ON demo USING diskann (embedding vector_cosine_ops)

Importante

O processo líder não pode participar em construções paralelas de índices.

Se quiser criar o índice usando trabalhadores paralelos, defina os max_parallel_workers, max_worker_processes, e max_parallel_maintenance_workers os parâmetros em conformidade. Para obter mais informações sobre esses parâmetros, consulte parâmetros que controlam o uso de recursos e o comportamento assíncrono.

Defina estes parâmetros em diferentes níveis de granularidade. Por exemplo, para os definir ao nível da sessão, execute as seguintes instruções:

-- Set the parameters
SET max_parallel_workers = 8;
SET max_worker_processes = 8; -- Note: Requires server restart
SET max_parallel_maintenance_workers = 4;

Para obter mais informações sobre outras opções para configurar estes parâmetros no Servidor Flexível do Base de Dados do Azure para PostgreSQL, consulte Configurar parâmetros.

Observação

O max_worker_processes parâmetro requer um reinício do servidor para ter efeito.

Se a configuração desses parâmetros e os recursos disponíveis no servidor não permitirem iniciar os trabalhadores paralelos, o PostgreSQL retornará automaticamente para criar o índice no modo não paralelo.

Parâmetros de configuração

Quando criar um diskann índice, especifique vários parâmetros para controlar o seu comportamento.

Parâmetros de índice

  • max_neighbors: Número máximo de arestas por nó no grafo. O valor padrão é 32. Um valor mais alto pode melhorar o recall até um certo ponto.
  • l_value_ib: Tamanho da lista de pesquisa durante a construção do índice. O valor padrão é 100. Um valor mais alto torna a construção mais lenta, mas o índice é de maior qualidade.
  • product_quantized: Permite a quantização de produtos para uma pesquisa mais eficiente. O valor predefinido é false.
  • pq_param_num_chunks: Número de blocos para quantização de produto. O valor padrão é 0, o que significa que o sistema determina automaticamente o valor com base nas dimensões de embedding. Utilize um terço das dimensões originais da incorporação.
  • pq_param_training_samples: Número de vetores com que treinar a tabela de pivôs PQ. O valor padrão é 0, o que significa que o sistema determina automaticamente o valor com base no tamanho da tabela.
CREATE INDEX demo_embedding_diskann_custom_idx ON demo USING diskann (embedding vector_cosine_ops)
WITH (
 max_neighbors = 48,
 l_value_ib = 100,
 product_quantized=true, 
 pq_param_num_chunks = 0,
 pq_param_training_samples = 0
 );

Parâmetros de extensão

  • diskann.iterative_search: Controla o comportamento de pesquisa.

    Configurações para diskann.iterative_search:

    • relaxed_order (padrão): Permite que o diskann pesquise iterativamente o gráfico em lotes de diskann.l_value_is, até que o número desejado de tuplas, possivelmente limitado pela cláusula LIMIT, seja produzido. Esta opção pode causar desordem nos resultados.

    • strict_order: Semelhante a relaxed_order, mas garante que os resultados são devolvidos por ordem estrita, ordenados por distância.

    • off: Utiliza funcionalidade de pesquisa não iterativa. Tenta obter diskann.l_value_is tuplas numa única etapa. A pesquisa não iterativa só pode retornar um máximo de diskann.l_value_is vetores para uma consulta, independentemente da cláusula ou do número de LIMIT tuplas que correspondam à consulta.

    Para alterar o comportamento de pesquisa para strict_order para todas as consultas executadas na sessão atual, execute a seguinte instrução:

    SET diskann.iterative_search TO 'strict_order';
    

    Para alterá-lo para que afete apenas todas as consultas executadas na transação atual, execute a seguinte instrução:

    BEGIN;
    SET LOCAL diskann.iterative_search TO 'strict_order';
    -- All your queries
    COMMIT;
    
  • diskann.l_value_is: Valor L para varrimento do índice (predefinido: 100). Aumentar o valor aumenta a capacidade de recuperação de dados, mas pode tornar as consultas mais demoradas.

    Para alterar o valor L da varredura de índice para 20 para todas as consultas executadas na sessão atual, execute a seguinte instrução:

    SET diskann.l_value_is TO 20;
    

    Para alterá-lo para que afete apenas todas as consultas executadas na transação atual, execute a seguinte instrução:

    BEGIN;
    SET LOCAL diskann.l_value_is TO 20;
    -- All your queries
    COMMIT;
    
Tamanho do conjunto de dados (linhas) Tipo de parâmetro Nome Valor recomendado
<1 milhão Compilação de índice l_value_ib 100
<1 milhão Compilação de índice max_neighbors 32
<1 milhão Tempo de consulta diskann.l_value_is 100
 
1M-50M Compilação de índice l_value_ib 100
1M-50M Compilação de índice max_neighbors 64
1M-50M Compilação de índice product_quantized true
1M-50M Tempo de consulta diskann.l_value_is 100
 
>50 milhões Compilação de índice l_value_ib 100
>50 milhões Compilação de índice max_neighbors 96
>50 milhões Compilação de índice product_quantized true
>50 milhões Tempo de consulta diskann.l_value_is 100

Observação

Esses parâmetros podem variar dependendo do conjunto de dados específico e do caso de uso. Podes precisar de experimentar diferentes valores de parâmetros para encontrar as definições ótimas para o teu cenário particular.

Progresso de CREATE INDEX e REINDEX

A partir do PostgreSQL 12, pode utilizar pg_stat_progress_create_index para verificar o progresso das operações CREATE INDEX ou REINDEX.

SELECT phase, round(100.0 * blocks_done / nullif(blocks_total, 0), 1) AS "%" FROM pg_stat_progress_create_index;

Para saber mais sobre as possíveis fases pelas quais decorre uma operação CREATE INDEX ou REINDEX, veja fases CREATE INDEX.

Selecionando a função de acesso ao índice

O tipo de vetor suporta três tipos de pesquisas nos vetores armazenados. Selecione a função de acesso correta para o seu índice para que a base de dados possa considerar o seu índice ao executar as suas consultas.

pg_diskann suporta os seguintes operadores de distância:

  • vector_l2_ops: <-> Distância euclidiana
  • vector_cosine_ops: <=> Distância cossina
  • vector_ip_ops: <#> Produto interno

Solução de problemas

Erro: assertion left == right failed left: 40 right: 0:

  • A versão do DiskANN GA, v0.6.x introduz alterações significativas no formato de metadados do índice. Índices criados com v0.5.x não são compatíveis para a frente com operações de inserção v0.6.x. Se tentar inserir numa tabela com um índice desatualizado, recebe um erro, mesmo que o índice pareça válido.

  • Quando encontrar este erro, resolva-o assim:

    • Opção 1: Executar a instrução REINDEX ou REDINDEX CONCURRENTLY no índice.

    • Opção 2: Reconstruir o índice.

      DROP INDEX your_index_name;
      CREATE INDEX your_index_name ON your_table USING diskann(your_vector_column vector_cosine_ops);
      
      

Erro: diskann index needs to be upgraded to version 2...:

  • Quando encontrar este erro, resolva-o assim:
    • Opção 1: Executar a instrução REINDEX ou REDINDEX CONCURRENTLY no índice.

    • Opção 2: Como REINDEX pode levar muito tempo, a extensão também fornece uma função definida pelo usuário chamada upgrade_diskann_index(), que atualiza seu índice mais rapidamente, quando possível.

      Para atualizar o índice, execute a seguinte instrução:

      SELECT upgrade_diskann_index('demo_embedding_diskann_custom_idx');
      

      Para atualizar todos os índices diskann no banco de dados para a versão atual, execute a seguinte instrução:

      SELECT upgrade_diskann_index(pg_class.oid)
      FROM pg_class
      JOIN pg_am ON (pg_class.relam = pg_am.oid)
      WHERE pg_am.amname = 'diskann';