Realizar una búsqueda de vectores de similitud en Spanner buscando los vecinos K más cercanos

Esta página describe cómo realizar una búsqueda de vectores de similitud en Spanner usando la distancia coseno, la distancia euclidiana y el punto funciones de vector de producto para encontrar K-vecinos más cercanos. Antes de leer esta página, es importante que comprendas los siguientes conceptos:

  • Distancia euclidiana: mide la distancia más corta entre dos vectores.
  • Distancia de coseno: mide el coseno del ángulo entre dos vectores.
  • Dot product: calcula la coseno del ángulo multiplicado por el producto del vector correspondiente magnitudes reales. Si sabes que todas las incorporaciones vectoriales en tu conjunto de datos normalizado, puedes usar DOT_PRODUCT() como función de distancia.
  • Vecinos más cercanos (KNN): un algoritmo de aprendizaje automático supervisado que se usa para resolver problemas de problemas de regresión.

Puedes usar funciones de distancia vectorial para determinar los vecinos K-más cercanos (KNN) búsqueda de vectores para casos de uso como la búsqueda de similitud o la recuperación generación. Spanner admite COSINE_DISTANCE(), las funciones EUCLIDEAN_DISTANCE() y DOT_PRODUCT(), que operan en un vector lo que te permite encontrar el KNN de la incorporación de entrada.

Por ejemplo, después de generar y guardar tu Spanner como incorporaciones vectoriales, puedes estas incorporaciones vectoriales como parámetro de entrada en tu consulta para encontrar la vectores más cercanos en el espacio n-dimensional para buscar vectores semánticamente similares o elementos relacionados.

Las tres funciones de distancia toman los argumentos vector1 y vector2, que son del tipo array<> y deben tener las mismas dimensiones y contener la la misma duración. Para obtener más detalles sobre estas funciones, consulta:

Ejemplos

Los siguientes ejemplos muestran la búsqueda KNN y la búsqueda KNN en datos particionados, y usando un índice secundario con KNN.

Todos los ejemplos usan EUCLIDEAN_DISTANCE(). También puedes usar COSINE_DISTANCE(). Además, si todas las incorporaciones vectoriales de tu conjunto de datos están normalizados, puedes usar DOT_PRODUCT() como una función de distancia.

Considera una tabla Documents que tiene una columna (DocEmbedding) de procesamiento previo de texto de la columna DocContents bytes.

GoogleSQL

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

PostgreSQL

CREATE TABLE Documents (
UserId       bigint primary key,
DocId        bigint primary key,
Author       varchar(1024),
DocContents  bytea,
DocEmbedding float4[]
);

Suponer que una incorporación de entrada para “béisbol, pero no béisbol profesional” es el array [0.3, 0.3, 0.7, 0.7], puedes encontrar los cinco documentos más cercanos que coincidan con la siguiente 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;

Estos son los resultados esperados de este ejemplo:

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

Ejemplo 2: Búsqueda de KNN en datos particionados

La consulta del ejemplo anterior puede modificarse agregando condiciones a la WHERE para limitar la búsqueda vectorial a un subconjunto de tus datos. Un problema común su aplicación es buscar datos particionados, como filas que pertenecen a un 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;

Estos son los resultados esperados de este ejemplo:

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

Ejemplo 3: Búsqueda de KNN en rangos de índices secundarios

Si el filtro de la cláusula WHERE que usas no forma parte de la clave primaria de la tabla, puedes crear un índice secundario para acelerar la operación con una análisis de solo índices.

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;

Estos son los resultados esperados de este ejemplo:

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, ...]        |
+------------+-----------------+-----------------+

¿Qué sigue?