Encontrar vizinhos mais próximos para indexar e consultar embeddings de vetores no Spanner

Esta página descreve como criar um índice de vetores e consultar embeddings de vetores usando a distância aproximada do cosseno, a distância euclidiana aproximada e de vetor aproximado de produto escalar. Você pode usar essas para encontrar vizinhos mais próximos (ANN, na sigla em inglês) aproximados no Spanner. Quando um conjunto de dados é pequeno, é possível usar vizinhos K-mais próximos (KNN, na sigla em inglês). para encontrar os vetores k mais próximos. No entanto, conforme o conjunto de dados aumenta, a latência e o custo de uma pesquisa KNN também aumentam. É possível usar a ANN para encontrar mais próximos k-próximos com latência e custo significativamente reduzidos.

Aproximadamente k vizinhos mais próximos

Em uma pesquisa de ANN, os vetores k-retornados não são o verdadeiro k-top mais próximo vizinhos. Ocasionalmente, alguns vetores que não estão entre o k-top mais próximo vizinhos são retornados. Isso é conhecido como perda de recall. Qual é a perda de recall aceitáveis para você depende do caso de uso, mas, na maioria dos casos, perder um pouco de em troca de um melhor desempenho do banco de dados é uma maneira aceitável compensação.

Para mais detalhes sobre as funções de distância aproximada do Spanner, consulte:

Índice vetorial

O Spanner acelera as pesquisas de vetores ANN usando um índice de vetor. Esse índice usa o recurso Escalonável mais próximo Vizinho (ScaNN), um algoritmo de vizinho mais próximo altamente eficiente.

O índice vetorial usa uma estrutura baseada em árvore para particionar dados e facilitar pesquisas mais rápidas. O Spanner oferece dois níveis e três níveis configurações de árvore:

  • Configuração de árvore de dois níveis: os nós de folha (num_leaves) contêm grupos de vetores relacionados intimamente, junto com seu centroide correspondente. A raiz consiste nos centroides de todos os nós de folha.
  • Configuração de árvore de três níveis: semelhante em conceito a uma árvore de dois níveis, enquanto introduzindo uma camada de ramificação adicional (num_branches), de qual nó folha os centroides são ainda mais particionados para formar o nível raiz (num_leaves).

Além disso, você precisa criar seu índice vetorial com uma métrica de distância específica. Para escolher a métrica de distância mais adequada para seu caso de uso, o distance_type como COSINE, DOT_PRODUCT ou EUCLIDEAN.

Para mais informações, consulte as instruções VECTOR INDEX.

Limitações

O índice de vetor do Spanner tem as seguintes limitações:

  • ALTER VECTOR INDEX não é compatível.

Criar índice de vetor

Para otimizar melhor o índice de vetor e ter um bom recall e desempenho, recomendamos que você crie seu índice vetorial depois que a maioria das linhas com embeddings estiver gravados no banco de dados. Também pode ser necessário recriar o índice de vetor depois de inserir novos dados. Para mais informações, consulte Recrie o índice de vetor.

Para criar um índice vetorial com uma árvore de dois níveis e 1.000 nós de folha em um Tabela Documents com uma coluna incorporada DocEmbedding usando o cosseno distância:

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

Para criar um índice vetorial com uma árvore de três níveis e 1000000 nós de folha:

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 a coluna incorporada for anulável, ela precisa ser declarada com um Cláusula 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);

Consultar embeddings de vetor

Para consultar um índice vetorial, use uma das três funções de distância aproximada:

  • APPROX_COSINE_DISTANCE
  • APPROX_EUCLIDEAN_DISTANCE
  • APPROX_DOT_PRODUCT

Restrições ao usar as funções de distância aproximada incluem o seguintes:

  • Forneça uma dica de consulta para usar o índice vetorial.
  • Use uma expressão constante como argumento da função de distância (por exemplo, um parâmetro ou um literal).
  • A consulta ou subconsulta em que a função de distância aproximada é usada precisa ter uma forma específica: a função de distância precisa ser a única tecla ORDER BY, e um limite precisa ser especificado.

Para uma lista detalhada das limitações, consulte a página de referência da função de distância aproximada.

Exemplo

Para pesquisar os 100 vetores mais próximos de [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 a coluna de embedding for anulável:

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

Práticas recomendadas

Siga estas práticas recomendadas para otimizar seus índices vetoriais e melhorar a consulta resultados.

Ajustar as opções de pesquisa vetorial

O valor ideal da pesquisa de vetor depende do caso de uso, o vetor conjunto de dados e vetores de consulta. Talvez seja necessário fazer ajustes iterativos para a encontrar os melhores valores para sua carga de trabalho específica.

Veja algumas diretrizes úteis a serem seguidas ao escolher valores apropriados:

  • tree_depth (nível da árvore): se a tabela que está sendo indexada tiver menos de 10 milhões de linhas, use um tree_depth de 2. Caso contrário, um tree_depth de 3 oferece suporte a tabelas de até 10 bilhões de linhas.

  • num_leaves: use a raiz quadrada do número de linhas no conjunto de dados. Um um valor maior pode aumentar o tempo de criação do índice vetorial. Evite definir num_leaves maior do que table_row_count/1000, porque isso resulta em folhas excessivamente pequenas e desempenho ruim.

  • num_leaves_to_search: esta opção especifica quantos nós folha do índice são pesquisados. Aumentar num_leaves_to_search melhora o recall, mas também aumenta a latência e o custo. Recomendamos usar um número que seja 1% do total número de folhas definidas na instrução CREATE VECTOR INDEX como o valor. para num_leaves_to_search. Se você estiver usando uma cláusula de filtro, aumente esse valor para ampliar a pesquisa.

Se o recall aceitável for alcançado, mas o custo da consulta for alto demais, resultando em um QPS máximo baixo, tente aumentar num_leaves seguindo estas etapas:

  1. Defina num_leaves como alguns vários k do valor original (por exemplo, 2 * sqrt(table_row_count)).
  2. Defina num_leaves_to_search como o mesmo múltiplo k do valor original.
  3. Teste a redução de num_leaves_to_search para melhorar o custo e o QPS. mantendo o recall.

Melhorar o recall

Há várias possibilidades de piora no recall, incluindo as seguintes:

  • num_leaves_to_search é muito pequeno: pode ser mais difícil encontrar os vizinhos mais próximos para alguns vetores de consulta, de modo que, num_leaves_to_search para pesquisar mais folhas pode ajudar a melhorar o recall. Recentes consultas podem ter mudado para conter mais desses vetores desafiadores.

  • O índice vetorial precisa ser recriado: a estrutura de árvore do índice vetorial é é otimizada para o conjunto de dados no momento da criação e é estática depois. Portanto, se forem adicionados vetores significativamente diferentes depois da criação do índice de vetor inicial, a estrutura de árvore pode não ser o ideal, levando a têm um recall menor.

Recriar o índice de vetor

Para reconstruir seu índice vetorial sem inatividade:

  1. Criar um novo índice de vetor na mesma coluna de embedding que o vetor atual índice, atualizando parâmetros (por exemplo, OPTIONS) conforme apropriado.
  2. Após a conclusão da criação do índice, mude a dica FORCE_INDEX. para apontar para o novo índice e atualizar a consulta de pesquisa de vetor. Isso garante que a consulta use o novo índice de vetor. (Você também pode precisar ajustar novamente num_leaves_to_search na nova consulta).
  3. Remover o índice de vetor desatualizado.

A seguir