# Hybride Suche

HINWEIS

Dieser Leitfaden gilt nur für die DB-Version 1.6.2 oder höher.

Dieser Leitfaden erläutert, wie man eine hybride Volltext- und Vektorsuche in MyScale durchführt.

Sowohl die Volltextsuche als auch die Vektorsuche haben ihre eigenen Stärken und Schwächen. Die Volltextsuche eignet sich hervorragend für die grundlegende Schlüsselwortabfrage und Textübereinstimmung, während die Vektorsuche bei der semantischen Übereinstimmung und dem tiefen Verständnis von Semantik zwischen Dokumenten hervorragende Ergebnisse erzielt, jedoch möglicherweise bei kurzen Textabfragen an Effizienz verliert. Die hybride Suche kombiniert die Vorteile beider Ansätze und verbessert die Genauigkeit und Geschwindigkeit von Textsuchen, um den Erwartungen der Benutzer an präzise Ergebnisse effizient gerecht zu werden.

# Übersicht über das Tutorial

Dieser Leitfaden behandelt:

Die Funktion HybridSearch() kombiniert die Ergebnisse von Vektor- und Textsuchen, verbessert die Anpassungsfähigkeit in verschiedenen Szenarien und erhöht die Suchgenauigkeit.

Veranschaulichung der hybriden Suche in MyScale

Bevor Sie beginnen, stellen Sie sicher, dass Sie einen MyScale-Cluster eingerichtet haben. Für Anweisungen zur Einrichtung lesen Sie unseren Schnellstart-Leitfaden (opens new window).

# Datensatz

Für das Experiment wurde der Wikipedia-Abstract-Datensatz (opens new window) von RediSearch verwendet, der 5.622.309 Dokumenteinträge umfasst. Wir haben die ersten 100.000 Einträge ausgewählt und sie mit dem Modell multilingual-e5-large (opens new window) in 1024-dimensionale Vektoren umgewandelt, die in der Spalte body_vector gespeichert sind. Die Ähnlichkeit zwischen den Vektoren wurde mit dem Kosinusabstand berechnet.

TIP

Weitere Informationen zur Verwendung von multilingual-e5-large finden Sie in der Dokumentation von HuggingFace (opens new window).

Der Datensatz wiki_abstract_100000_1024D.parquet (opens new window) hat eine Größe von 668 MB und enthält 100.000 Einträge. Sie können den Inhalt unten einsehen, ohne ihn lokal herunterladen zu müssen, da wir ihn in den folgenden Experimenten direkt über S3 in MyScale importieren werden.

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

# Tabellenerstellung und Datenimport

Um die Tabelle wiki_abstract_mini im SQL-Arbeitsbereich von MyScale zu erstellen, führen Sie die folgende SQL-Anweisung aus:

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;

Importieren Sie die Daten aus S3 in die Tabelle. Bitte haben Sie Geduld während des Datenimportprozesses.

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

Hinweis

Die geschätzte Zeit für den Datenimport beträgt etwa 10 Minuten.

Überprüfen Sie, ob 100.000 Zeilen Daten in der Tabelle vorhanden sind, indem Sie die folgende Abfrage ausführen:

SELECT count(*) FROM default.wiki_abstract_mini;

Ausgabe:

count()
100000

# Index erstellen

# FTS-Index erstellen

TIP

Weitere Informationen zur Erstellung eines FTS-Index finden Sie in der Dokumentation zur Textsuche.

Bei der Einrichtung eines FTS-Index haben Benutzer die Möglichkeit, den Tokenizer anzupassen. In diesem Beispiel wird der stem-Tokenizer zusammen mit der Anwendung von Stoppwörtern verwendet. Der stem-Tokenizer kann Wortformen in Texten übersehen, um präzisere Suchergebnisse zu erzielen. Durch die Verwendung von Stoppwörtern werden häufige Wörter wie "ein", "eine", "von" und "in" herausgefiltert, um die Suchgenauigkeit zu verbessern.

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

Führen Sie die Materialisierung des Index aus:

ALTER TABLE default.wiki_abstract_mini MATERIALIZE INDEX body_idx;

# Vektorindex erstellen

TIP

Weitere Informationen zum MSTG-Vektorindex finden Sie in der Dokumentation zur Vektorsuche.

Um den MSTG-Vektorindex mit Kosinusabstand für den body_vec_idx in der Tabelle default.wiki_abstract_mini zu erstellen, führen Sie die folgende SQL-Anweisung aus:

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

Der Aufbau eines Vektorindex kann zeitaufwändig sein. Um den Fortschritt zu überwachen, führen Sie die folgende SQL-Abfrage aus. Wenn die Spalte "status" "Built" anzeigt, wurde der Index erfolgreich erstellt. Wenn "InProgress" angezeigt wird, ist der Vorgang noch nicht abgeschlossen.

SELECT * FROM system.vector_indices;

# HybridSearch-Funktion

Die HybridSearch()-Funktion in MyScale führt hybride Suchen durch, indem sie die Ergebnisse von Vektor- und Textsuchen kombiniert und die besten Kandidaten zurückgibt. Die grundlegende Syntax lautet:

HybridSearch('dense_param1 = value1', 'param2 = value2')(vector_column, text_column, query_vector, query_text)
  • params: Suchspezifische Parameter. Parameter, die mit dense_ beginnen, sind für die Vektorsuche. Zum Beispiel setzt dense_alpha den Parameter alpha für den MSTG-Vektorindex.
  • vector_column: Spalte, die die zu durchsuchenden Vektordaten enthält.
  • text_column: Spalte, die die zu durchsuchenden Textdaten enthält.
  • query_vector: Zu durchsuchender Vektor.
  • query_text: Zu durchsuchender Text.

Verwenden Sie die HybridSearch-Funktion mit einer ORDER BY-Klausel und einer LIMIT-Klausel, um die besten Kandidaten abzurufen. Die Sortierrichtung für Spalten in der ORDER BY-Klausel muss auf DESC gesetzt sein.

# Erläuterung der HybridSearch-Parameter

Nachfolgend finden Sie eine detaillierte Beschreibung der HybridSearch()-Parameter:

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.

# Fusionstypen

Die hybride Suche kombiniert den BM25-Score aus Textsuchen (bezeichnet als für lexikalisch) mit der Distanzmetrik aus Vektorsuchen (bezeichnet als für semantisch). MyScale unterstützt derzeit zwei Fusionstypen:

  1. Relative Score Fusion (RSF): Bei RSF werden die Scores aus Vektor- und Textsuchen zwischen 0 und 1 normalisiert. Der höchste Rohscore wird auf 1 gesetzt, während der niedrigste auf 0 gesetzt wird und alle anderen Werte proportional in diesem Bereich eingestuft werden. Der endgültige Score ist eine gewichtete Summe dieser normalisierten Scores:

Die verwendete Normalisierungsformel lautet:

  1. Reciprocal Rank Fusion (RRF): RRF erfordert keine Score-Normalisierung. Stattdessen werden die Ergebnisse basierend auf ihrer Position in jedem Ergebnissatz mit der folgenden Formel gerankt, wobei eine beliebige Konstante ist, die die Bedeutung niedriger gerankter Ergebnisse anpasst.

# Vektor-, Text- und hybride Suche durchführen

# Eine Einbettungsfunktion erstellen

Um Abfragetext in Vektoren umzuwandeln, verwenden wir das Modell multilingual-e5-large (opens new window).

Dank der Einbettungsfunktionen von MyScale ist die Online-Umwandlung von Text in Vektoren einfach. Wir werden eine Einbettungsfunktion MultilingualE5Large für diesen Zweck erstellen.

TIP

Sie benötigen einen kostenlosen Schlüssel von HuggingFace, um eine Einbettungsfunktion zu erstellen.

CREATE FUNCTION MultilingualE5Large
ON CLUSTER '{cluster}' AS (x) -> EmbedText (
  concat('query: ', x),
  'HuggingFace',
  'https://api-inference.huggingface.co/models/intfloat/multilingual-e5-large',
  '<Ihr HuggingFace-Schlüssel, beginnt mit `hf_`>',
  ''
);

# Vektorsuche durchführen

TIP

Die British Graham Land Expedition (BGLE) war eine britische Expedition. Weitere Informationen über sie finden Sie in der Wikipedia (opens new window).

Die Vektorsuche funktioniert im Allgemeinen gut im Bereich langer Texte, aber ihre Effektivität kann im Bereich kurzer Texte abnehmen. Um die Suchleistung für verschiedene Textlängen zu veranschaulichen, werden wir zwei Beispiele für Vektorsuchen präsentieren. Der Inhalt, den wir suchen, bezieht sich auf Orte, die vom BGLE-Expeditionsteam markiert wurden, wobei der Unterschied zwischen den beiden Sätzen darin besteht, ob die Abkürzung des Teamnamens verwendet wird.

  • Beispiel 1: langer Text: 'Vermessen von der British Graham Land Expedition'
SELECT
    id,
    title,
    body,
    distance('alpha=3')(body_vector, MultilingualE5Large('Vermessen von der British Graham Land Expedition')) AS score
FROM default.wiki_abstract_mini
ORDER BY score ASC
LIMIT 5;

Aus den folgenden Suchergebnissen wird deutlich, dass die Vektorsuche bei der Übereinstimmung langer Texte hervorragende Ergebnisse erzielt, da vier der fünf besten Suchergebnisse unseren Kriterien entsprechen.

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
  • Beispiel 2: kurzer Text: 'Vermessen von der BGLE'
SELECT
    id,
    title,
    body,
    distance('alpha=3')(body_vector, MultilingualE5Large('Vermessen von der BGLE')) AS score
FROM default.wiki_abstract_mini
ORDER BY score ASC
LIMIT 5;

Bei der Betrachtung der Suchergebnisse für kurze Texte wird jedoch deutlich, dass die Vektorsuche in diesem Bereich weniger effektiv ist, da keines der fünf besten Dokumente Informationen über BGLE enthält.

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

# Textsuche durchführen

BM25, ein weit verbreiteter Textsuchalgorithmus, ist sehr ausgereift und besonders für die Übereinstimmung kurzer Texte geeignet. Wenn es jedoch darum geht, die Semantik langer Texte zu verstehen, ist BM25 nicht so effektiv wie die Vektorsuche. Das Folgende zeigt die leistungsstarke Suchfähigkeit von TextSearch() im Bereich kurzer Texte.

  • Beispiel: kurzer Text: 'Vermessen von der BGLE'
SELECT
    id,
    title,
    body,
    TextSearch(body, 'Vermessen von der 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

# Hybride Suche durchführen

MyScale bietet die HybridSearch()-Funktion, eine Suchmethode, die die Stärken der Vektorsuche und der Textsuche kombiniert. Dieser Ansatz verbessert nicht nur das Verständnis der Semantik langer Texte, sondern behebt auch die semantischen Mängel der Vektorsuche im Bereich kurzer Texte.

  • Beispiel: kurzer Text: Vermessen von der BGLE
SELECT
    id,
    title,
    body,
    HybridSearch('fusion_type=RSF', 'fusion_weight=0.6')(body_vector, body, MultilingualE5Large('Vermessen von der BGLE'), ' BGLE') AS score
FROM default.wiki_abstract_mini
ORDER BY score DESC
LIMIT 5;

Basierend auf den Ergebnissen der HybridSearch()-Funktion können wir auch bei der Suche nach kurzen Texten hervorragende Suchergebnisse erzielen und die Genauigkeit erheblich verbessern.

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

Ab der DB-Version v1.8 oder höher ist es im HybridSearch()-Funktionsmodell möglich, die Textsuchspalte aus einem mehrspaltigen FTS-Index zu verwenden.

# Hybride Suche außerhalb der Datenbank

Wir können auch die Python-Bibliothek ranx (opens new window) verwenden, um die Ergebnisse von Vektor- und Textsuchen außerhalb der Datenbank zu kombinieren und die RRF-Fusionsstrategie (Reciprocal Rank Fusion) zur Verbesserung der Suchgenauigkeit zu implementieren. Für alternative Fusionsstrategien können Sie ranx/fusion (opens new window) konsultieren.

Verwendung von ranx zur Fusion

Bevor Sie den unten stehenden Democode ausführen, sollten Sie ranx installieren:

pip install -U ranx

Beispielcode in 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)
# MyScale-Informationen
host = "Ihr Cluster-Endpunkt"
port = 443
username = "Ihr Benutzername"
password = "Ihr Passwort"
database = "default"
table = "wiki_abstract_mini"
# MyScale-Client initialisieren
client = clickhouse_connect.get_client(host=host, port=port, username=username, password=password)
# Eine Tabelle zur Ausgabe der Ergebnisse erstellen
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)
# Wir möchten nach einem kurzen Text suchen.
terms = "Vermessen von der BGLE"
# VektorSearch ausführen.
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)
# TextSearch ausführen.
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)
# VektorSearch- und TextSearch-Ergebnisse extrahieren.
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]}
# Ergebnisse extrahieren.
bm25_dict = {"query-0": {str(row[0]): float(row[3]) for row in text_search_res.result_rows}}
# Für die ranx-Bibliothek wird erwartet, dass ein höherer Score eine größere Relevanz anzeigt,
# daher ist eine Vorverarbeitung für Vektordistanzberechnungsmethoden wie Kosinus und L2 erforderlich.
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}}
# Normalisierte Ergebnisse.
vector_run = rank_norm(Run(vector_dict, name="vector"))
bm25_run = rank_norm(Run(bm25_dict, name="bm25"))
# Fusion der Ergebnisse mit RRF.
combined_run = fuse(
    runs=[vector_run, bm25_run],
    method="rrf",
    params={'k': 10}
)
print("\nFusionsergebnisse:")
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", "Titel", "Inhalt", "Score"])

Die fusionierten Suchergebnisse lauten wie folgt: Die hybride Suche hat fünf Artikel genau den Orten zugeordnet, die von der BGLE-Expedition vermessen wurden, und zeigt die Vorteile der hybriden Suche bei der Verarbeitung von Kurztextabfragen.

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=

# Fazit

Dieses Dokument gibt Einblicke in die Verwendung der MyScale Hybrid-Suche und konzentriert sich auf Methoden und Techniken zur Suche in unstrukturierten Textdaten. In der praktischen Übung haben wir ein Beispiel mit Wikipedia-Abstracts entwickelt. Die Durchführung einer Hybrid-Suche ist mit den fortschrittlichen Volltext- und Vektorsuchfunktionen von MyScale einfach und liefert genauere Ergebnisse, indem sowohl Schlüsselwort- als auch semantische Informationen kombiniert werden.

Last Updated: Tue Oct 08 2024 07:35:58 GMT+0000