# Búsqueda Híbrida

NOTA

Esta guía solo es aplicable a la versión de DB 1.5.0 o superior.

Esta guía explica cómo realizar una búsqueda híbrida de texto completo y vectorial en MyScale.

La búsqueda de texto completo y la búsqueda vectorial tienen sus propias fortalezas y debilidades. La búsqueda de texto completo es adecuada para la recuperación básica de palabras clave y la coincidencia de texto, mientras que la búsqueda vectorial se destaca en la coincidencia semántica entre documentos y la comprensión profunda de la semántica, pero puede carecer de eficiencia en consultas de texto corto. Para aprovechar los beneficios de ambos enfoques, se desarrolló la búsqueda híbrida. Al combinar la indexación de texto completo y las características de búsqueda vectorial, se pueden abordar de manera efectiva diversos requisitos de búsqueda de texto, mejorar la precisión y velocidad en la búsqueda de textos y cumplir con las expectativas de los usuarios para obtener resultados precisos de manera eficiente.

# Resumen del Tutorial

Este documento lo guiará a través de tres experimentos de búsqueda:

Búsqueda vectorial en MyScale

Todos los textos de documentos y consultas utilizan el modelo all-MiniLM-L6-v2 (opens new window) para la generación de vectores y la distancia del coseno para la medición de similitud.

Búsqueda de texto en MyScale

MyScale integra la biblioteca Tantivy (opens new window) para habilitar la indexación BM25 para la búsqueda de texto completo (FTS). Al indexar todos los datos de texto en la tabla, la capacidad de FTS de MyScale permite que los resultados de búsqueda se clasifiquen según las puntuaciones BM25, proporcionando experiencias de búsqueda más relevantes y precisas.

Fusión de resultados de búsqueda vectorial y de texto utilizando la estrategia RRF

Utilizamos la biblioteca ampliamente utilizada en Python ranx (opens new window) para combinar los resultados de búsqueda vectorial y de texto. Esta fusión mejora la adaptabilidad de las búsquedas de texto en diversos escenarios, mejorando así la precisión de la búsqueda.

Ilustración de la Búsqueda Híbrida en MyScale

Antes de comenzar, asegúrese de tener configurado un clúster de MyScale. Para obtener instrucciones de configuración, consulte nuestra Guía de inicio rápido (opens new window).

# Conjunto de datos

El experimento utilizó el conjunto de datos de resúmenes de Wikipedia proporcionado por RediSearch, que consta de 5,622,309 entradas de documentos. El texto se procesó utilizando el modelo all-MiniLM-L6-v2 (opens new window) para crear vectores de 384 dimensiones almacenados en la columna body_vector. La similitud entre los vectores se calculó utilizando la distancia del coseno.

TIP

Para obtener más información sobre cómo utilizar all-MiniLM-L6-v2, consulte la documentación de HuggingFace (opens new window).

El conjunto de datos wiki_abstract_with_vector.parquet (opens new window) tiene un tamaño de 8.2GB. Puede obtener una vista previa de su contenido a continuación sin necesidad de descargarlo localmente, ya que lo importaremos directamente en MyScale a través de S3 en los experimentos posteriores.

id body title url body_vector
... ... ... ... ...
77 Jake Rodkin is an American .... and Puzzle Agent. Jake Rodkin https://en.wikipedia.org/wiki/Jake_Rodkin (opens new window) [-0.081793934,....,-0.01105572]
78 Friedlandpreis der Heimkehrer is ... of Germany. Friedlandpreis der Heimkehrer https://en.wikipedia.org/wiki/Friedlandpreis_der_Heimkehrer (opens new window) [0.018285718,...,0.03049711]
... ... ... ... ...

# Creación de la Tabla e Importación de Datos

Para crear la tabla wiki_abstract_5m en el espacio de trabajo SQL de MyScale, ejecute la siguiente declaración SQL:

CREATE TABLE default.wiki_abstract_5m(
    `id` UInt64,
    `body` String,
    `title` String,
    `url` String,
    `body_vector` Array(Float32),
    CONSTRAINT check_length CHECK length(body_vector) = 384
)
ENGINE = MergeTree
ORDER BY id
SETTINGS index_granularity = 128;

Importe los datos de S3 a la tabla. Tenga paciencia durante el proceso de importación de datos.

INSERT INTO default.wiki_abstract_5m
SELECT * FROM s3('https://myscale-datasets.s3.ap-southeast-1.amazonaws.com/wiki_abstract_with_vector.parquet', 'Parquet');

Nota

El tiempo estimado para la importación de datos es de aproximadamente 10 minutos.

Verifique si hay 5,622,309 filas de datos en la tabla ejecutando esta consulta:

SELECT count(*) FROM default.wiki_abstract_5m;

Salida:

count()
5622309

Para optimizar la tabla y mejorar el rendimiento de la búsqueda vectorial fusionando sus partes de datos en una sola parte (opcional), ejecute este comando SQL en su espacio de trabajo SQL:

OPTIMIZE TABLE default.wiki_abstract_5m FINAL;

Este paso de optimización puede llevar algún tiempo para completarse.

Verifique si las partes de datos de esta tabla se han comprimido en una sola parte con esta consulta:

SELECT COUNT(*) FROM system.parts WHERE table='wiki_abstract_5m' AND active=1;

Si tiene éxito, verá:

count()
1

# Crear Índice

# Crear Índice FTS

TIP

Para aprender cómo crear un índice FTS, consulte la documentación del índice FTS.

Al configurar un índice FTS, los usuarios tienen la opción de personalizar el tokenizador. En este ejemplo, se utiliza el tokenizador stem junto con la aplicación de stop words. El tokenizador stem puede pasar por alto los tiempos de las palabras en el texto para obtener resultados de búsqueda más precisos. Al utilizar stop words, se filtran palabras comunes como "a", "an", "of" e "in" para mejorar la precisión de la búsqueda.

ALTER TABLE default.wiki_abstract_5m
ADD INDEX body_idx (body)
TYPE fts('{"body":{"tokenizer":{"type":"stem", "stop_word_filters":["english"]}}}');

Ejecute la materialización del índice:

ALTER TABLE default.wiki_abstract_5m MATERIALIZE INDEX body_idx;

# Crear Índice Vectorial

TIP

Obtenga más información sobre el índice vectorial MSTG en la documentación de búsqueda vectorial.

Para construir el índice vectorial MSTG utilizando el cálculo de distancia del coseno para el body_vec_idx en la tabla default.wiki_abstract_5m, ejecute esta declaración SQL:

ALTER TABLE default.wiki_abstract_5m
ADD VECTOR INDEX body_vec_idx body_vector
TYPE MSTG('metric_type=Cosine');

La construcción de un índice vectorial puede llevar mucho tiempo. Para monitorear su progreso, ejecute esta consulta SQL. Si la columna de estado muestra "Built", significa que el índice se ha creado correctamente. Mientras aún esté en progreso, debería mostrar "InProgress".

SELECT * FROM system.vector_indices;

# Realizar Búsqueda Híbrida

# Preparativos Preliminares

Para convertir el texto de la consulta en vectores, utilizaremos el modelo all-MiniLM-L6-v2 (opens new window).

En primer lugar, instale la biblioteca sentence-transformers ejecutando:

pip install -U sentence-transformers

Para la etapa de fusión, utilizaremos la biblioteca ranx (opens new window). Instálela utilizando:

pip install -U ranx

La práctica de búsqueda híbrida se implementará en un archivo Python. Antes de continuar con esta práctica, asegúrese de ingresar la información de su clúster de MyScale en el código de ejemplo proporcionado.

TIP

Puede encontrar los detalles de conexión para un clúster de MyScale en la consola web.

import clickhouse_connect
from numba import NumbaTypeSafetyWarning
from prettytable import PrettyTable
from ranx import Run, fuse
from ranx.normalization import rank_norm
from sentence_transformers import SentenceTransformer
import warnings
warnings.filterwarnings('ignore', category=NumbaTypeSafetyWarning)
# Utilice el modelo transfromer all-MiniLM-L6-v2
model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
# Información de MyScale
host = "su punto final de clúster"
port = 443
username = "su nombre de usuario"
password = "su contraseña"
database = "default"
table = "wiki_abstract_5m"
# Inicializar cliente de MyScale
client = clickhouse_connect.get_client(host=host, port=port,
                                       username=username, password=password)
# Utilice una tabla para mostrar su contenido
def print_results(result_rows, field_names):
    x = PrettyTable()
    x.field_names = field_names
    for row in result_rows:
        x.add_row(row)
    print(x)

# Ejecutar Búsqueda Vectorial

TIP

La expedición británica a Graham Land (BGLE) fue una expedición británica. Para obtener información detallada sobre ellos, consulte Wikipedia (opens new window).

Nuestro objetivo es identificar los lugares visitados y cartografiados por la expedición BGLE en este conjunto de datos. Para hacerlo, utilizaremos "Charted by BGLE" como cadena de búsqueda al realizar una consulta de búsqueda vectorial.

TIP

Asegúrese de incluir el código de ejemplo proporcionado en este mensaje en el archivo Python que se creó durante el trabajo de preparación anterior para garantizar una ejecución fluida del programa. Además, asegúrese de manejar los demás pasos de manera similar.

terms = "Charted by BGLE"
terms_embedding = model.encode([terms])[0]
vector_search = f"SELECT id, title, body, distance('alpha=3')" \
                f"(body_vector,{list(terms_embedding)}) AS distance FROM {database}.{table} " \
                f"ORDER BY distance ASC LIMIT 100"
vector_search_res = client.query(query=vector_search)
print("\nResultados de Búsqueda Vectorial:")
print_results(vector_search_res.result_rows[:10], ["ID", "Título", "Cuerpo", "Distancia"])

Los documentos recuperados a través de la búsqueda vectorial no contienen ninguna información relacionada con "Charted by BGLE" en los 10 primeros resultados, ya que la búsqueda vectorial tiende a tener un rendimiento deficiente para consultas de texto corto.

ID Título Cuerpo Distancia
1177089 B.G. discography This is the discography of B.G. 0.44516414403915405
2710950 Ruy Blas and the Blasé Roué Ruy Blas and the Blasé Roué is a burlesque written by A. C. 0.4736078381538391
4571962 BLL BLL may refer to: 0.48070353269577026
3797998 Bles Bles may refer to: 0.4849556088447571
4558187 The Complete Blam Blam Blam The Complete Blam Blam Bam is a compilation LP by Blam Blam Blam. It was released on November, 1992. 0.4863016605377197
5556733 BLG BLG may refer to: 0.49544525146484375
4591273 Blagg Blagg may refer to: 0.5007722973823547
3087541 Paul Bley discography This is the discography for Canadian jazz musician Paul Bley. 0.5030192136764526
3389086 Blot (album) Blot is the fourth full-length album by the Norwegian black/Viking metal band Einherjer. It was released on 21 November 2003 by Tabu Recordings. 0.5040180087089539
1876940 Blåljus! Blåljus! is a six-volume light pocket series of novels by Margit Sandemo and published by the Swedish subsidiade Boknöje AB of the Norwegian publication Bladkompaniet in year 2004. 0.5080643892288208

# Ejecutar Búsqueda de Texto

Utilizamos la función TextSearch() de MyScale para recuperar un conjunto de resultados relevantes junto con las puntuaciones BM25. Para facilitar la fusión de resultados más adelante, primero debemos almacenar temporalmente estos datos de documentos.

text_search = f"SELECT id, title, body, TextSearch(body, '{terms}') AS score " \
              f"FROM {database}.{table} " \
              f"ORDER BY score DESC LIMIT 100"
text_search_res = client.query(query=text_search)
# Almacenar temporalmente los resultados de búsqueda.
stored_data = {}
for row in vector_search_res.result_rows:
    stored_data[str(row[0])] = {"title": row[1], "body": row[2]}
for row in text_search_res.result_rows:
    if str(row[0]) not in stored_data:
        stored_data[str(row[0])] = {"title": row[1], "body": row[2]}

# Utilizar la Fusión de Rango Recíproco para Fusionar los Resultados de Búsqueda Vectorial y de Texto

Utilizamos la biblioteca ranx (opens new window) para combinar los resultados de búsqueda vectorial y de texto, implementando la estrategia de fusión RRF (Reciprocal Rank Fusion) para mejorar la precisión de la búsqueda. Para obtener estrategias de fusión alternativas, consulte ranx/fusion (opens new window).

# Extraer id y puntuación de los resultados de la consulta.
bm25_dict = {"query-0": {str(row[0]): float(row[3]) for row in text_search_res.result_rows}}
# Para la biblioteca ranx, se espera que una puntuación más alta indique una mayor relevancia,
# por lo tanto, se requiere un preprocesamiento para los métodos de cálculo de distancia vectorial como el coseno y L2.
max_value = max(float(row[3]) for row in vector_search_res.result_rows)
vector_dict = {"query-0": {str(row[0]): max_value - float(row[3]) for row in vector_search_res.result_rows}}
# Normalizar la puntuación de los resultados de la consulta.
vector_run = rank_norm(Run(vector_dict, name="vector"))
bm25_run = rank_norm(Run(bm25_dict, name="bm25"))
# Fusionar los resultados de la consulta utilizando RRF.
combined_run = fuse(
    runs=[vector_run, bm25_run],
    method="rrf",
    params={'k': 10}
)
print("\nResultados de Fusión:")
pretty_results = []
for id_, score in combined_run.get_doc_ids_and_scores()[0].items():
    if id_ in stored_data:
        pretty_results.append([id_, stored_data[id_]["title"], stored_data[id_]["body"], score])
print_results(pretty_results[:10], ["ID", "Título", "Cuerpo", "Puntuación"])

Los resultados de la consulta de fusión son los siguientes: la búsqueda híbrida coincidió de manera precisa con cinco artículos relacionados con los lugares cartografiados por la expedición BGLE, mostrando los beneficios de la búsqueda híbrida para procesar consultas de texto corto.

ID Título Cuerpo Puntuación
200245 Salmon Island Salmon Island () is the westernmost of the Fish Islands, lying off the west coast of Graham Land. Charted by the British Graham Land Expedition (BGLE) under Rymill, 1934-37. 0.09090909090909091
1177089 B.G. discography This is the discography of B.G. 0.09090909090909091
5024941 Woozle Hill Woozle Hill () is a hill near the center of Galindez Island, in the Argentine Islands in the Wilhelm Archipelago. First charted by the British Graham Land Expedition (BGLE) under Rymill, 1934-37. 0.08333333333333333
2710950 Ruy Blas and the Blasé Roué Ruy Blas and the Blasé Roué is a burlesque written by A. C. 0.08333333333333333
4571962 BLL BLL may refer to: 0.07692307692307693
4426976 Symington Islands Symington Islands () is a group of small islands lying west-northwest of Lahille Island, in the Biscoe Islands. Charted by the British Graham Land Expedition (BGLE) under Rymill, 1934-37. 0.07692307692307693
3797998 Bles Bles may refer to: 0.07142857142857142
197443 Tadpole Island Tadpole Island () is an island just north of Ferin Head, off the west coast of Graham Land. Charted by the British Graham Land Expedition (BGLE) under Rymill, 1934-37. 0.07142857142857142
202128 Sohm Glacier Sohm Glacier () is a glacier flowing into Bilgeri Glacier on Velingrad Peninsula, the west coast of Graham Land. Charted by the British Graham Land Expedition (BGLE) under Rymill, 1934-37. 0.06666666666666667
4558187 The Complete Blam Blam Blam The Complete Blam Blam Bam is a compilation LP by Blam Blam Blam. It was released on November, 1992. 0.06666666666666667

# Conclusión

Este documento proporciona información sobre el uso de la búsqueda híbrida de MyScale en escenarios de búsqueda de texto, centrándose en métodos y técnicas para buscar datos de texto no estructurados. En el ejercicio práctico, desarrollamos un ejemplo utilizando resúmenes de Wikipedia. Realizar una búsqueda híbrida es fácil con las capacidades avanzadas de búsqueda de texto completo y vectorial de MyScale, y produce resultados más precisos al combinar información de palabras clave y semántica.

Last Updated: Tue May 07 2024 02:28:12 GMT+0000