Efetue uma pesquisa de similaridade vetorial no Spanner encontrando os K vizinhos mais próximos

Esta página descreve como realizar uma pesquisa de similaridade vetorial no Spanner usando as funções vetoriais de distância de cossenos, distância euclidiana e produto escalar para encontrar os K vizinhos mais próximos. Estas informações aplicam-se a bases de dados com dialeto GoogleSQL e bases de dados com dialeto PostgreSQL. Antes de ler esta página, é importante que compreenda os seguintes conceitos:

  • Distância euclidiana: mede a distância mais curta entre dois vetores.
  • Distância do cosseno: mede o cosseno do ângulo entre dois vetores.
  • Produto escalar: calcula o cosseno do ângulo multiplicado pelo produto das magnitudes dos vetores correspondentes. Se souber que todas as incorporações vetoriais no seu conjunto de dados estão normalizadas, pode usar DOT_PRODUCT() como função de distância.
  • K-nearest neighbors (KNN): um algoritmo de aprendizagem automática supervisionada usado para resolver problemas de classificação ou regressão.

Pode usar funções de distância vetorial para realizar uma pesquisa vetorial de K-vizinhos mais próximos (KNN) para exemplos de utilização como a pesquisa de semelhanças ou a geração aumentada de recuperação. O Spanner suporta as funções COSINE_DISTANCE(), EUCLIDEAN_DISTANCE() e DOT_PRODUCT(), que operam em incorporações de vetores, o que lhe permite encontrar o KNN da incorporação de entrada.

Por exemplo, depois de gerar e guardar os seus dados operacionais do Spanner como incorporações de vetores, pode fornecer estas incorporações de vetores como um parâmetro de entrada na sua consulta para encontrar os vetores mais próximos no espaço N-dimensional para pesquisar itens semanticamente semelhantes ou relacionados.

Todas as três funções de distância recebem os argumentos vector1 e vector2, que são do tipo array<> e têm de consistir nas mesmas dimensões e ter o mesmo comprimento. Para mais detalhes sobre estas funções, consulte:

Exemplos

Os exemplos seguintes mostram a pesquisa KNN, a pesquisa KNN sobre dados particionados e a utilização de um índice secundário com KNN.

Todos os exemplos usam EUCLIDEAN_DISTANCE(). Também pode usar COSINE_DISTANCE(). Além disso, se todas as incorporações vetoriais no seu conjunto de dados forem normalizadas, pode usar DOT_PRODUCT() como uma função de distância.

Considere uma tabela Documents que tenha uma coluna (DocEmbedding) de incorporações de texto pré-calculadas a partir da coluna de bytes DocContents.

GoogleSQL

CREATE TABLE Documents (
UserId       INT64 NOT NULL,
DocId        INT64 NOT NULL,
Author       STRING(1024),
DocContents  BYTES(MAX),
DocEmbedding ARRAY<FLOAT32>
) PRIMARY KEY (UserId, DocId);

PostgreSQL

CREATE TABLE Documents (
UserId       bigint NOT NULL,
DocId        bigint NOT NULL,
Author       varchar(1024),
DocContents  bytea,
DocEmbedding float4[],
PRIMARY KEY  (UserId, DocId)
);

Partindo do princípio de que uma incorporação de entrada para "basebol, mas não basebol profissional" é a matriz [0.3, 0.3, 0.7, 0.7], pode encontrar os cinco documentos mais próximos que correspondem com a seguinte consulta:

GoogleSQL

SELECT DocId, DocEmbedding FROM Documents
ORDER BY EUCLIDEAN_DISTANCE(DocEmbedding,
ARRAY<FLOAT32>[0.3, 0.3, 0.7, 0.8])
LIMIT 5;

PostgreSQL

SELECT DocId, DocEmbedding FROM Documents
ORDER BY spanner.euclidean_distance(DocEmbedding,
'{0.3, 0.3, 0.7, 0.8}'::float4[])
LIMIT 5;

Os resultados esperados deste exemplo:

Documents
+---------------------------+-----------------+
| DocId                     | DocEmbedding    |
+---------------------------+-----------------+
| 24                        | [8, ...]        |
+---------------------------+-----------------+
| 25                        | [6, ...]        |
+---------------------------+-----------------+
| 26                        | [3.2, ...]      |
+---------------------------+-----------------+
| 27                        | [38, ...]       |
+---------------------------+-----------------+
| 14229                     | [1.6, ...]      |
+---------------------------+-----------------+

Exemplo 2: pesquisa KNN em dados particionados

A consulta no exemplo anterior pode ser modificada adicionando condições à cláusula WHERE para limitar a pesquisa vetorial a um subconjunto dos seus dados. Uma aplicação comum desta funcionalidade é pesquisar dados particionados, como linhas que pertencem a um UserId específico.

GoogleSQL

SELECT UserId, DocId, DocEmbedding FROM Documents
WHERE UserId=18
ORDER BY EUCLIDEAN_DISTANCE(DocEmbedding,
ARRAY<FLOAT32>[0.3, 0.3, 0.7, 0.8])
LIMIT 5;

PostgreSQL

SELECT UserId, DocId, DocEmbedding FROM Documents
WHERE UserId=18
ORDER BY spanner.euclidean_distance(DocEmbedding,
'{0.3, 0.3, 0.7, 0.8}'::float4[])
LIMIT 5;

Os resultados esperados deste exemplo:

Documents
+-----------+-----------------+-----------------+
| UserId    | DocId           | DocEmbedding    |
+-----------+-----------------+-----------------+
| 18        | 234             | [12, ...]       |
+-----------+-----------------+-----------------+
| 18        | 12              | [1.6, ...]      |
+-----------+-----------------+-----------------+
| 18        | 321             | [22, ...]       |
+-----------+-----------------+-----------------+
| 18        | 432             | [3, ...]        |
+-----------+-----------------+-----------------+

Exemplo 3: pesquisa KNN em intervalos de índice secundário

Se a cláusula WHERE filter que está a usar não fizer parte da chave principal da tabela, pode criar um índice secundário para acelerar a operação com uma análise apenas de índice.

GoogleSQL

CREATE INDEX DocsByAuthor
ON Documents(Author)
STORING (DocEmbedding);

SELECT Author, DocId, DocEmbedding FROM Documents
WHERE Author="Mark Twain"
ORDER BY EUCLIDEAN_DISTANCE(DocEmbedding,
   <embeddings for "book about the time traveling American">)
LIMIT 5;

PostgreSQL

CREATE INDEX DocsByAuthor
ON Documents(Author)
INCLUDE (DocEmbedding);

SELECT Author, DocId, DocEmbedding FROM Documents
WHERE Author="Mark Twain"
ORDER BY spanner.euclidean_distance(DocEmbedding,
   <embeddings for "that book about the time traveling American">)
LIMIT 5;

Os resultados esperados deste exemplo:

Documents
+------------+-----------------+-----------------+
| Author     | DocId           | DocEmbedding    |
+------------+-----------------+-----------------+
| Mark Twain | 234             | [12, ...]       |
+------------+-----------------+-----------------+
| Mark Twain | 12              | [1.6, ...]      |
+------------+-----------------+-----------------+
| Mark Twain | 321             | [22, ...]       |
+------------+-----------------+-----------------+
| Mark Twain | 432             | [3, ...]        |
+------------+-----------------+-----------------+
| Mark Twain | 375             | [9, ...]        |
+------------+-----------------+-----------------+

O que se segue?