Patrones de búsqueda híbrida de texto completo y de vectores

En esta página, se describe cómo realizar búsquedas híbridas de texto completo y vectoriales en Spanner. La búsqueda híbrida combina la precisión de la concordancia de palabras clave (búsqueda de texto completo, FTS) con la recuperación de la concordancia semántica (búsqueda de vectores) para producir resultados de búsqueda muy relevantes.

Spanner admite los siguientes patrones de búsqueda híbrida, que se dividen en tres categorías principales:

Categoría Descripción Objetivo principal
Fusion Fusion recupera y clasifica documentos de forma independiente con la búsqueda por palabras clave y la búsqueda de vectores, y, luego, combina (fusiona) los resultados. Combina varios indicadores de puntuación para lograr la máxima recuperación y relevancia.
Filtrado Las palabras clave filtran o definen mejor el espacio de búsqueda. Asegúrate de que la coincidencia de palabras clave sea un requisito mientras aprovechas la relevancia semántica.
Clasificación basada en AA Un modelo de aprendizaje automático refina un conjunto inicial de candidatos para obtener una clasificación final más precisa. Lograr la mayor precisión posible para un pequeño conjunto final de resultados

La búsqueda combinada implica ejecutar la FTS y la búsqueda vectorial de forma independiente en el mismo corpus de datos. Luego, combina los resultados para crear una lista clasificada única, unificada y muy pertinente.

Si bien puedes ejecutar consultas independientes del lado del cliente, la búsqueda híbrida en Spanner ofrece las siguientes ventajas:

  • Simplifica la lógica de la aplicación administrando las solicitudes paralelas y la combinación de resultados en el servidor.
  • Evita transferir al cliente conjuntos de resultados intermedios potencialmente grandes.

Puedes usar SQL para crear métodos de fusión en Spanner. En esta sección, se proporcionan ejemplos de la fusión de clasificación recíproca y la fusión de puntuación relativa. Sin embargo, te recomendamos que evalúes diferentes estrategias de fusión para determinar cuál se adapta mejor a los requisitos de tu aplicación.

Fusión basada en el ranking

Usa la fusión basada en el ranking cuando las puntuaciones de relevancia de diferentes métodos de recuperación (como las puntuaciones de FTS y las distancias vectoriales) sean difíciles de comparar o normalizar porque se miden en diferentes espacios. Este método usa la posición de clasificación de cada documento de cada recuperador para generar una puntuación y una clasificación finales.

La fusión de clasificación recíproca (RRF) es una función de fusión basada en la clasificación. La puntuación del RRF para un documento es la suma de los recíprocos de sus rangos de múltiples recuperadores y se calcula de la siguiente manera:

\[ score\ (d\epsilon D)\ =\ \sum\limits_{r\epsilon R}^{}(1\ /\ (\ 𝑘\ +\ ran{k}_{r}\ (𝑑)\ )\ )\ \]

Aquí:

  • d es el documento.
  • R es el conjunto de recuperadores (búsqueda de texto completo y búsqueda de vectores).
  • k es una constante (a menudo establecida en 60) que se usa para moderar la influencia de los documentos con una clasificación muy alta.
  • w es la clasificación del documento del recuperador r.

Implementa el RR en una consulta de Spanner

Las métricas de vectores (como APPROX_DOT_PRODUCT) y las puntuaciones de búsqueda de texto (como SCORE_NGRAMS) operan en escalas incompatibles. Para resolver este problema, en el siguiente ejemplo, se implementa el RR para normalizar los datos según la posición del ranking en lugar de las puntuaciones sin procesar.

La consulta usa UNNEST(ARRAY(...) WITH OFFSET para asignar una clasificación a los 100 candidatos principales de cada método. Luego, calcula una puntuación estandarizada con la inversa de esas clasificaciones y agrega los resultados para devolver las cinco coincidencias principales.

SELECT SUM(1 / (60 + rank)) AS rrf_score, key
FROM (
  (
    SELECT rank, x AS key
    FROM UNNEST(ARRAY(
      SELECT key
      FROM hybrid_search
      WHERE embedding IS NOT NULL
      ORDER BY APPROX_DOT_PRODUCT(@vector, embedding,
        OPTIONS => JSON '{"num_leaves_to_search": 50}') DESC
      LIMIT 100)) AS x WITH OFFSET AS rank
  )
  UNION ALL
  (
    SELECT rank, x AS key
    FROM UNNEST(ARRAY(
      SELECT key
      FROM hybrid_search
      WHERE SEARCH_NGRAMS(text_tokens_ngrams, 'foo')
      ORDER BY SCORE_NGRAMS(text_tokens_ngrams, 'foo') DESC
      LIMIT 100)) AS x WITH OFFSET AS rank
  )
)
GROUP BY key
ORDER BY rrf_score DESC
LIMIT 5;

Fusión basada en la puntuación

La fusión basada en la puntuación es eficaz cuando las puntuaciones de relevancia de diferentes métodos son comparables o se pueden normalizar, lo que podría permitir una clasificación más precisa que incorpore el peso de relevancia real de cada método.

La fusión de puntuación relativa (RSF) es un método basado en la puntuación que normaliza las puntuaciones de diferentes métodos en relación con las puntuaciones más altas y más bajas dentro de cada método, por lo general, con las funciones MIN() y MAX(). La puntuación de RSF de un documento recuperado por un conjunto de recuperadores se calcula de la siguiente manera:

\[ score(d\epsilon D)\ =\ \sum\limits_{r\epsilon R}^{}({w}_{r}*(scor{e}_{r}(d)\ -\ mi{n}_{r})\ /\ (ma{x}_{r\ }-mi{n}_{r})\ ) \]

Aquí:

  • d es el documento.
  • R es el conjunto de recuperadores (búsqueda de texto completo y búsqueda de vectores).
  • w es el peso asignado a un recuperador específico.

Implementa RSF en una consulta de Spanner

Para implementar el RSF, debes normalizar las puntuaciones del vector y del FTS en una escala común. En el siguiente ejemplo, se calculan las puntuaciones mínima y máxima en cláusulas WITH separadas para derivar los factores de normalización. Luego, combina los resultados con un FULL OUTER JOIN, sumando las puntuaciones normalizadas de la búsqueda de vecino más cercano aproximado (ANN) (convertida de cosine_distance) y la FTS.

WITH ann AS (
  SELECT key, APPROX_COSINE_DISTANCE(@vector, embedding,
    OPTIONS => JSON '{"num_leaves_to_search": 50}') AS cosine_distance,
  FROM hybrid_search
  WHERE embedding IS NOT NULL
  ORDER BY cosine_distance
  LIMIT 100
),
fts AS (
  SELECT key, SCORE_NGRAMS(text_tokens_ngrams, 'Green') AS score,
  FROM hybrid_search
    WHERE SEARCH_NGRAMS(text_tokens_ngrams, 'Green')
    ORDER BY score DESC
    LIMIT 100
),
ann_min AS (
  SELECT MIN(1 - cosine_distance) AS min
  FROM ann
),
ann_max AS (
  SELECT MAX(1 - cosine_distance) AS max
  FROM ann
),
fts_min AS (
  SELECT MIN(score) AS min
  FROM fts
),
fts_max AS (
  SELECT MAX(score) AS max
  FROM fts
)
SELECT IFNULL(ann.key, fts.key),
       IFNULL(((1 - ann.cosine_distance) - ann_min.min) /
               (ann_max.max - ann_min.min), 0) +
       IFNULL((fts.score - fts_min.min) /
               (fts_max.max - fts_min.min), 0) AS score
FROM ann
FULL OUTER JOIN fts
ON ann.key = fts.key
CROSS JOIN ann_min
CROSS JOIN ann_max
CROSS JOIN fts_min
CROSS JOIN fts_max
ORDER BY score DESC
LIMIT 5;

Las búsquedas filtradas usan FTS para crear un filtro que reduce el conjunto de documentos considerados para una búsqueda vectorial de k-vecinos más cercanos (KNN). De manera opcional, puedes usar una clasificación previa para limitar el tamaño del conjunto de resultados.

La búsqueda de ejemplo en esta sección sigue los siguientes pasos para reducir el espacio de búsqueda de vectores al subconjunto de datos que coinciden con las palabras clave:

  • Usa SEARCH (text_tokens, 'Green') para encontrar filas en las que la columna text_tokens contiene el texto Green. Las primeras 1,000 filas se muestran en un orden de clasificación definido por el índice de búsqueda.
  • Usa una función de vector, DOT_PRODUCT(@vector, embedding), para calcular la similitud entre el vector de búsqueda (@vector) y el vector de documento almacenado (embedding). Luego, ordena los resultados y muestra las 10 coincidencias principales finales.
SELECT key
FROM (
  SELECT key, embedding
  FROM hybrid_search
  WHERE SEARCH (text_tokens, 'Green')
  ORDER BY presort
  LIMIT 1000)
ORDER BY DOT_PRODUCT(@vector, embedding) DESC
LIMIT 10;

Clasificación con AA

El nuevo ranking basado en AA es un enfoque preciso, pero que requiere una gran cantidad de procesamiento. Aplica un modelo de aprendizaje automático a un pequeño conjunto de candidatos que se redujo con la FTS, la búsqueda de vectores o una combinación de ambas. Para obtener más información sobre la integración de Vertex AI en Spanner, consulta la descripción general de la integración de Vertex AI en Spanner.

Puedes integrar la clasificación basada en AA con la función ML.PREDICT de Spanner y un modelo de Vertex AI implementado.

Implementa la clasificación basada en AA

  1. Implementa un modelo de reranking (por ejemplo, de HuggingFace) en un extremo de Vertex AI.
  2. Crea un objeto MODEL de Spanner que apunte al extremo de Vertex AI. Por ejemplo, en el siguiente ejemplo de modelo Reranker:

    • text ARRAY<string(max)> son los documentos.
    • text_pair ARRAY<string(max)> es el texto de la búsqueda en el ejemplo.
    • score son las puntuaciones de relevancia que asigna el modelo de AA a los pares de textos de entrada.
    CREATE MODEL Reranker
    INPUT (text ARRAY<string(max)>, text_pair ARRAY<string(max)>)
    OUTPUT (score FLOAT32)
    REMOTE
    OPTIONS (
    endpoint = '...'
    );
    
  3. Usa una subconsulta para recuperar los candidatos iniciales (como los 100 resultados principales de una búsqueda de ANN) y pasarlos a ML.PREDICT. La función devuelve una nueva columna de puntuación para la ordenación final.

    SELECT key
    FROM ML.PREDICT(
        MODEL Reranker, (
          SELECT key, text, "gift for 8-year-old" AS text_pair
          FROM hybrid_search
          WHERE embedding IS NOT NULL
          ORDER BY APPROX_DOT_PRODUCT(@vector, embedding, options=>JSON '{"num_leaves_to_search": 50}') DESC
          LIMIT 100)
    )
    ORDER BY score DESC
    LIMIT 3;
    

¿Qué sigue?