# Búsqueda Híbrida

NOTA

Esta guía solo es aplicable a la versión de DB 1.6.2 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 excelente para la recuperación básica de palabras clave y la coincidencia de texto, mientras que la búsqueda vectorial sobresale 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. La búsqueda híbrida combina los beneficios de ambos enfoques, mejorando la precisión y velocidad en las búsquedas de texto para satisfacer las expectativas de los usuarios de obtener resultados precisos de manera eficiente.

# Resumen del Tutorial

Esta guía cubre:

La función HybridSearch() combina los resultados de las búsquedas vectoriales y de texto, mejorando la adaptabilidad en diferentes escenarios y mejorando la precisión de la búsqueda.

Ilustración de 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 (opens new window) proporcionado por RediSearch, que consta de 5,622,309 entradas de documentos. Se seleccionaron las primeras 100,000 entradas y se procesaron utilizando el modelo multilingual-e5-large (opens new window) para crear vectores de 1024 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 multilingual-e5-large, consulte la documentación de HuggingFace (opens new window).

El conjunto de datos wiki_abstract_100000_1024D.parquet (opens new window) tiene un tamaño de 668MB y contiene 100,000 entradas. 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
... ... ... ... ...
78 A total solar ... the Sun for a viewer on Earth. Solar eclipse of November 12, 1985 https://en.wikipedia.org/wiki/Solar_eclipse_of_November_12,_1985 (opens new window) [1.4270141,...,-1.2265089]
79 Dhamangaon Badhe is a town ... Aurangabad districts. Dhamangaon Badhe https://en.wikipedia.org/wiki/Dhamangaon_Badhe (opens new window) [0.6736672,....,0.12504958]
... ... ... ... ...

# Creación de Tablas e Importación de Datos

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

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

Importe los datos de S3 a la tabla. Por favor, tenga paciencia durante el proceso de importación de datos.

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

Nota

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

Verifique si hay 100,000 filas de datos en la tabla ejecutando esta consulta:

SELECT count(*) FROM default.wiki_abstract_mini;

Salida:

count()
100000

# Construir Índice

# Crear Índice FTS

TIP

Para aprender cómo crear un índice FTS, consulte la documentación de búsqueda de texto.

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_mini
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_mini 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 crear el índice vectorial MSTG utilizando la distancia del coseno para el body_vec_idx en la tabla default.wiki_abstract_mini, ejecute esta declaración SQL:

ALTER TABLE default.wiki_abstract_mini
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, el índice se ha creado correctamente. Si muestra InProgress, el proceso aún está en curso.

SELECT * FROM system.vector_indices;

# Función HybridSearch

La función HybridSearch en MyScale realiza búsquedas híbridas combinando los resultados de las búsquedas vectoriales y de texto, devolviendo los principales candidatos. La sintaxis básica es:

HybridSearch('dense_param1 = value1', 'param2 = value2')(vector_column, text_column, query_vector, query_text)
  • params: Parámetros específicos de la búsqueda. Los parámetros que comienzan con dense_ son para la búsqueda vectorial. Por ejemplo, dense_alpha establece el parámetro alpha para el índice vectorial MSTG.
  • vector_column: Columna que contiene los datos vectoriales a buscar.
  • text_column: Columna que contiene los datos de texto a buscar.
  • query_vector: Vector a buscar.
  • query_text: Texto a buscar.

Utilice la función HybridSearch con una cláusula ORDER BY y una cláusula LIMIT para recuperar los principales candidatos. La dirección de ordenación de las columnas en la cláusula ORDER BY debe establecerse en DESC.

# Parámetros de HybridSearch Explicados

A continuación se muestra una descripción detallada de los parámetros de HybridSearch():

Parameter Default Value Candidate Values Description
fusion_type N/A rsf, rrf Determines the combination method in hybrid search. rsf stands for Relative Score Fusion, and rrf stands for Reciprocal Rank Fusion. This parameter is required.
fusion_weight 0.5 Floating point number between 0 - 1 Specifies the weight of the BM25 score in text search, applicable with RSF fusion.
fusion_k 60 Positive integer no less than 1 Specifies the sorting constant value in RRF fusion.
enable_nlq true true, false Indicates whether to use natural language queries in text search.
operator OR OR, AND Specifies the logical operator used to combine terms in text search.

# Tipos de Fusión

La búsqueda híbrida combina la puntuación BM25 de las búsquedas de texto (denotada como para léxica) con la métrica de distancia de las búsquedas vectoriales (denotada como para semántica). MyScale actualmente admite dos tipos de fusión:

  1. Fusión de Puntuación Relativa (RSF): En RSF, las puntuaciones de las búsquedas vectoriales y de texto se normalizan entre 0 y 1. La puntuación más alta se establece en 1, mientras que la más baja se establece en 0, y todos los demás valores se clasifican proporcionalmente dentro de este rango. La puntuación final es una suma ponderada de estas puntuaciones normalizadas:

La fórmula de normalización utilizada es:

  1. Fusión de Rango Recíproco (RRF): RRF no requiere normalización de puntuaciones. En su lugar, clasifica los resultados en función de sus posiciones en cada conjunto de resultados utilizando la siguiente fórmula, donde es una constante arbitraria que ajusta la importancia de los resultados de menor rango.

# Realizar Búsqueda Vectorial, de Texto y Híbrida

# Crear una Función de Incrustación

Para convertir el texto de consulta en vectores, utilizaremos el modelo multilingual-e5-large (opens new window).

Gracias a las funciones de incrustación de MyScale, convertir el texto en vectores en línea es sencillo. Crearemos una función de incrustación, MultilingualE5Large, con este propósito.

TIP

Necesitará una clave gratuita de HuggingFace para crear una función de incrustación.

CREATE FUNCTION MultilingualE5Large
ON CLUSTER '{cluster}' AS (x) -> EmbedText (
  concat('query: ', x),
  'HuggingFace',
  'https://api-inference.huggingface.co/models/intfloat/multilingual-e5-large',
  '<your huggingface key, starts with `hf_`>',
  ''
);

# 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).

La búsqueda vectorial generalmente funciona bien en el dominio de textos largos, pero su efectividad puede disminuir en el ámbito de textos cortos. Para ilustrar el rendimiento de la búsqueda en diferentes longitudes de texto, presentaremos dos ejemplos de búsquedas vectoriales. El contenido que estamos buscando se refiere a ubicaciones marcadas por el equipo de la expedición BGLE, siendo la diferencia entre las dos oraciones si se utiliza o no la abreviatura del nombre del equipo.

  • Ejemplo 1. consulta de texto largo: 'Cartografiado por la Expedición Británica a Graham Land'
SELECT
    id,
    title,
    body,
    distance('alpha=3')(body_vector, MultilingualE5Large('Cartografiado por la Expedición Británica a Graham Land')) AS score
FROM default.wiki_abstract_mini
ORDER BY score ASC
LIMIT 5;

A partir de los resultados de búsqueda a continuación, es evidente que la búsqueda vectorial sobresale en la coincidencia de textos largos, con cuatro de los cinco mejores resultados de búsqueda cumpliendo con nuestros criterios.

id title body score
15145 Paragon Point Paragon Point () is a small but prominent point on the southwest side of Leroux Bay, 3 nautical miles (6 km) west-southwest of Eijkman Point on the west coast of Graham Land. Charted by the British Graham Land Expedition (BGLE) under Rymill, 1934-37. 0.17197883
16459 Link Stack Link Stack () is a rocky pillar at the northwest end of Chavez Island, off the west coast of Graham Land, Antarctica. It was charted by the British Graham Land Expedition under John Rymill, 1934–37. 0.17324567
47359 Huitfeldt Point Huitfeldt Point is a point southeast of Vorweg Point on the southwest side of Barilari Bay, on the west coast of Graham Land, Antarctica. It was charted by the British Graham Land Expedition under John Rymill, 1934–37, and was named by the UK Antarctic Place-Names Committee in 1959 for Fritz R. 0.17347288
48138 Santos Peak Santos Peak () is a peak lying south of Murray Island, on the west coast of Graham Land. Charted by the Belgian Antarctic Expedition under Gerlache, 1897-99. 0.17546016
15482 Parvenu Point Parvenu Point () is a low but prominent point forming the north extremity of Pourquoi Pas Island, off the west coast of Graham Land. First surveyed in 1936 by the British Graham Land Expedition (BGLE) under Rymill. 0.17611909
  • Ejemplo 2. consulta de texto corto: 'Cartografiado por la BGLE'
SELECT
    id,
    title,
    body,
    distance('alpha=3')(body_vector, MultilingualE5Large('Cartografiado por la BGLE')) AS score
FROM default.wiki_abstract_mini
ORDER BY score ASC
LIMIT 5;

Sin embargo, al examinar los resultados de búsqueda para textos cortos, queda claro que la búsqueda vectorial es menos efectiva en este dominio, ya que ninguno de los cinco primeros documentos contiene información sobre BGLE.

id title body score
17693 Têtes Raides | current_members = Christian OlivierGrégoire SimonPascal OlivierAnne-Gaëlle BisquaySerge BégoutÉdith BégoutPierre GauthéJean-Luc MillotPhilippe Guarracino 0.19922233
92351 Badr al-Din Lu'lu' right|thumb|250px|Badr al-Din Lu'lu', manuscript illustration from the Kitāb al-Aghānī of [[Abu al-Faraj al-Isfahani (Feyzullah Library No. 1566, Istanbul). 0.19949186
45934 Singing All Along |show_name_2=|simplified=|pinyin=Xiùlì Jiāngshān Zhī Cháng Gē Xíng|translation=Splendid and Beautiful Rivers and Mountains: Long Journey of Songs}} 0.2003029
44708 LinQ | current_members =Yumi TakakiSakura ArakiAyano YamakiMYUChiaki Sara YoshikawaRana KaizukiAsaka SakaiKana FukuyamaManami SakuraMaina KohinataChisa Ando 0.20089924
43706 Shorty (crater) | diameter = 110 mShorty, Gazetteer of Planetary Nomenclature, International Astronomical Union (IAU) Working Group for Planetary System Nomenclature (WGPSN) 0.20098251

# Ejecutar Búsqueda de Texto

BM25, un algoritmo de búsqueda de texto ampliamente utilizado, es muy maduro y especialmente adecuado para la coincidencia de texto corto. Sin embargo, cuando se trata de comprender la semántica de textos largos, BM25 no es tan efectivo como la búsqueda vectorial. Lo siguiente demuestra las poderosas capacidades de búsqueda de TextSearch() en el campo de texto corto.

  • Ejemplo. consulta de texto corto: 'Cartografiado por la BGLE'
SELECT
    id,
    title,
    body,
    TextSearch(body, 'Cartografiado por la BGLE') AS bm25_score
FROM default.wiki_abstract_mini
ORDER BY bm25_score DESC
LIMIT 5;
id title body bm25_score
48165 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. 15.392099
47415 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. 15.126007
48775 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. 15.126007
14327 Trout Island Trout Island () is an island just east of Salmon Island in the Fish Islands, off the west coast of Graham Land. Charted by the British Graham Land Expedition (BGLE) under Rymill, 1934-37. 14.620504
49006 Somers Glacier Somers Glacier () is a glacier flowing northwest into Trooz Glacier on Kiev Peninsula, the west coast of Graham Land. First charted by the British Graham Land Expedition (BGLE) under Rymill, 1934-37. 14.620504

# Ejecutar Búsqueda Híbrida

MyScale proporciona la función HybridSearch(), un método de búsqueda que combina las fortalezas de la búsqueda vectorial y la búsqueda de texto. Este enfoque no solo mejora la comprensión de la semántica de textos largos, sino que también aborda las deficiencias semánticas de la búsqueda vectorial en el dominio de textos cortos.

  • Ejemplo. consulta de texto corto: Cartografiado por la BGLE
SELECT
    id,
    title,
    body,
    HybridSearch('fusion_type=RSF', 'fusion_weight=0.6')(body_vector, body, MultilingualE5Large('Cartografiado por la BGLE'), ' BGLE') AS score
FROM default.wiki_abstract_mini
ORDER BY score DESC
LIMIT 5;

Según los resultados obtenidos de la función HybridSearch(), podemos obtener excelentes resultados de búsqueda incluso al buscar textos cortos, con una precisión significativamente mejorada.

id title body score
48165 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.6
47415 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.5404912
48775 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.5404912
49000 Sooty Rock Sooty Rock () is a rock midway between Lumus Rock and Betheder Islands in Wilhelm Archipelago. Discovered and named "Black Reef" by the British Graham Land Expedition (BGLE), 1934-37. 0.5404912
14327 Trout Island Trout Island () is an island just east of Salmon Island in the Fish Islands, off the west coast of Graham Land. Charted by the British Graham Land Expedition (BGLE) under Rymill, 1934-37. 0.4274415

# Búsqueda Híbrida Fuera de la Base de Datos

También podemos utilizar la biblioteca ranx (opens new window) en Python para combinar los resultados de búsqueda vectorial y de texto fuera de la base de datos, 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).

Uso de ranx para fusionar

Antes de ejecutar el código de demostración a continuación, debe instalar ranx:

pip install -U ranx

Código de ejemplo en Python:

import clickhouse_connect
from numba import NumbaTypeSafetyWarning
from prettytable import PrettyTable
from ranx import Run, fuse
from ranx.normalization import rank_norm
import warnings
warnings.filterwarnings('ignore', category=NumbaTypeSafetyWarning)
# 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_mini"
# 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)
# Queremos buscar un texto corto.
terms = "Cartografiado por BGLE"
# Ejecutar VectorSearch.
vector_search = f"SELECT id, title, body, distance('alpha=3')" \
                f"(body_vector, MultilingualE5Large('{terms}')) AS distance FROM {database}.{table} " \
                f"ORDER BY distance ASC LIMIT 100"
vector_search_res = client.query(query=vector_search)
# Ejecutar TextSearch.
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)
# Extraer resultados de VectorSearch y TextSearch.
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]}
# Extraer id y puntuación de los resultados.
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 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 puntuación de resultados de consulta.
vector_run = rank_norm(Run(vector_dict, name="vector"))
bm25_run = rank_norm(Run(bm25_dict, name="bm25"))
# Fusionar resultados de 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[:5], ["ID", "Título", "Cuerpo", "Puntuación"])

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

ID Title Body Score
47415 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.06432246998284734
15145 Paragon Point Paragon Point () is a small but prominent point on the southwest side of Leroux Bay, 3 nautical miles (6 km) west-southwest of Eijkman Point on the west coast of Graham Land. Charted by the British Graham Land Expedition (BGLE) under Rymill, 1934-37. 0.049188640973630834
48165 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.047619047619047616
64566 Want You Back (Haim song) format=Digital download recorded=
45934 Singing All Along show_name_2=

# Conclusión

Este documento proporciona información sobre el uso de la búsqueda híbrida de MyScale, 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: Sun Jun 30 2024 09:15:57 GMT+0000