Encuentra los vecinos más cercanos para indexar y consultar incorporaciones de vectores en Spanner

En esta página, se describe cómo crear un índice vectorial y consultar incorporaciones vectoriales usando la distancia aproximada de coseno, la distancia euclidiana aproximada y funciones del vector de producto puntual aproximados. Puedes usar estas para encontrar los vecinos más cercanos (ANN) en Spanner. Cuando un conjunto de datos es pequeño, puedes usar vecinos K-más cercanos (KNN) para encontrar los vectores k-más cercanos exactos. Sin embargo, a medida que tu conjunto de datos crece, la latencia y el costo de una búsqueda en KNN también aumentan. Puedes usar la ANN para conocer la tasa aproximada k-vecinos más cercanos con latencia y costos significativamente reducidos.

Vecinos k-más cercanos aproximados

En una búsqueda de ANN, los vectores que muestra k no son el verdadero k superior más cercano vecinos. En ocasiones, algunos vectores que no se encuentran entre los k-más cercanos vecinos. Esto se conoce como pérdida de recuperación. ¿Cuánta pérdida de recuperación es aceptable para ti depende del caso de uso, pero, en la mayoría de los casos, perder a cambio de un mejor rendimiento de la base de datos es un compensación.

Para obtener más detalles sobre las funciones de distancia aproximada de Spanner, consulta:

Índice vectorial

Spanner acelera las búsquedas de vectores ANN a través de una interfaz índice vectorial. Este índice aprovecha el módulo Más cercana y escalable de Google Research Vecino (ScaNN), un algoritmo de vecino más cercano muy eficiente.

El índice vectorial usa una estructura basada en árboles para particionar datos y facilitar búsquedas más rápidas. Spanner ofrece dos y tres niveles del árbol de configuraciones:

  • Configuración de árbol de dos niveles: los nodos de hoja (num_leaves) contienen grupos de vectores estrechamente relacionados junto con su centroide correspondiente. La raíz consta de los centroides de todos los nodos hoja.
  • Configuración de árbol de tres niveles: un concepto similar al de un árbol de dos niveles, introduciendo una capa de rama adicional (num_branches) a partir de la cual un nodo de hoja los centroides se particionan aún más para formar el nivel raíz (num_leaves).

Además, debes crear tu índice vectorial con una métrica de distancia específica. Puedes elegir la métrica de distancia más adecuada para tu caso de uso configurando distance_type por COSINE, DOT_PRODUCT o EUCLIDEAN.

Para obtener más información, consulta las sentencias VECTOR INDEX.

Limitaciones

El índice vectorial de Spanner tiene las siguientes limitaciones:

  • ALTER VECTOR INDEX no es compatible.

Crear índice vectorial

Para optimizar el índice vectorial a fin de lograr una recuperación y un rendimiento óptimos, recomendamos que crees tu índice vectorial después de que la mayoría de las filas con incorporaciones estén se escribe en tu base de datos. También es posible que debas hacer ajustes vuelve a compilar el índice vectorial después de insertar nuevos datos. Para obtener más información, consulta Vuelve a compilar el índice vectorial.

Para crear un índice vectorial con un árbol de dos niveles y 1,000 nodos hoja en una Tabla Documents con una columna de incorporación DocEmbedding que usa el coseno distancia:

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

Para crear un índice vectorial con un árbol de tres niveles y 1000000 nodos hoja:

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);

Si tu columna de incorporación es anulable, debes declararla con un 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);

Consulta embeddings de vectores

Para consultar un índice vectorial, utiliza una de las tres funciones de distancia aproximada:

  • APPROX_COSINE_DISTANCE
  • APPROX_EUCLIDEAN_DISTANCE
  • APPROX_DOT_PRODUCT

Las restricciones para el uso de las funciones de distancia aproximada incluyen la lo siguiente:

  • Debes indicar una sugerencia de consulta para usar el índice vectorial.
  • Debes usar una expresión constante como argumento de la función de distancia (por ejemplo, un parámetro o un literal).
  • La consulta o subconsulta en la que se usa la función de distancia aproximada debe tomar una forma específica: la función de distancia debe ser la única clave ORDER BY, y se debe especificar un límite.

Para obtener una lista detallada de las limitaciones, consulta el página de referencia de la función de distancia aproximada.

Ejemplo

Para buscar los 100 vectores más cercanos a [1.0, 2.0, 3.0], haz lo siguiente:

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

Si la columna de incorporación es anulable:

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ácticas recomendadas

Sigue estas prácticas recomendadas para optimizar tus índices vectoriales y mejorar las consultas resultados.

Ajusta las opciones de búsqueda vectorial

El valor óptimo de búsqueda vectorial depende del caso de uso, la regla conjunto de datos y los vectores de consulta. Es posible que debas realizar un ajuste iterativo para a encontrar los mejores valores para tu carga de trabajo específica.

Estos son algunos lineamientos útiles que puedes seguir cuando elijas los valores adecuados:

  • tree_depth (a nivel de árbol): Si la tabla que se indexa tiene menos de 10. millones de filas, usa un tree_depth de 2. De lo contrario, una tree_depth de 3. admite tablas de hasta 10,000 millones de filas.

  • num_leaves: Usa la raíz cuadrada de la cantidad de filas en el conjunto de datos. R un valor mayor puede aumentar el tiempo de compilación del índice vectorial. Evita configurar num_leaves mayor que table_row_count/1000, ya que esto da como resultado hojas demasiado pequeñas y un rendimiento deficiente.

  • num_leaves_to_search: Esta opción especifica cuántos nodos de hoja del índice. los usuarios. Aumentar el num_leaves_to_search mejora la recuperación, pero también aumenta la latencia y el costo. Te recomendamos usar un número que equivalga al 1% del total la cantidad de hojas definidas en la sentencia CREATE VECTOR INDEX como el valor para num_leaves_to_search. Si usas una cláusula de filtro, aumenta este valor para ampliar la búsqueda.

Si se logra una recuperación aceptable, pero el costo de la consulta es demasiado alto, lo que da como resultado un máximo bajo de QPS. Para aumentar num_leaves, sigue estos pasos pasos:

  1. Establece num_leaves en varios k de su valor original (por ejemplo, 2 * sqrt(table_row_count)).
  2. Configura num_leaves_to_search para que sea el mismo múltiplo k de su valor original.
  3. Experimenta con la reducción de num_leaves_to_search para mejorar el costo y las QPS y, al mismo tiempo, mantener la recuperación.

Mejora la recuperación

Existen varias posibilidades de que empeore la recuperación, incluidas las siguientes:

  • num_leaves_to_search es demasiado pequeño, así que es posible que te resulte más difícil encontrar los vecinos más cercanos para algunos vectores de consulta, así que aumentar num_leaves_to_search para buscar más hojas puede ayudar a mejorar la recuperación. Reciente podrían haber cambiado para contener más de estos vectores desafiantes.

  • El índice vectorial debe volver a compilarse: la estructura de árbol del índice vectorial es optimizado para el conjunto de datos al momento de la creación y, posteriormente, es estático. Por lo tanto, si se agregan vectores significativamente diferentes después de crear la índice vectorial inicial, entonces la estructura de árbol podría no ser óptima, lo que generaría o problemas de recuperación.

Vuelve a compilar el índice vectorial

Para volver a compilar tu índice vectorial sin tiempo de inactividad, haz lo siguiente:

  1. Crea un índice vectorial nuevo en la misma columna de incorporación que el vector actual índice y actualizará los parámetros (por ejemplo, OPTIONS) según corresponda.
  2. Cuando se complete la creación del índice, cambia la sugerencia FORCE_INDEX. para apuntar al índice nuevo para actualizar la búsqueda vectorial. Esto garantiza que la consulta usa el nuevo índice vectorial. (Es posible que también debas volver a ajustar num_leaves_to_search en tu nueva consulta).
  3. Se descarta el índice vectorial desactualizado.

¿Qué sigue?