# Hybride Suche
HINWEIS
Dieser Leitfaden gilt nur für die DB-Version 1.5.0 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 für grundlegende Stichwortsuche und Textabgleich, während die Vektorsuche sich durch die semantische Übereinstimmung zwischen Dokumenten und ein tiefes Verständnis der Semantik auszeichnet, aber möglicherweise bei kurzen Textabfragen an Effizienz verliert. Um die Vorteile beider Ansätze zu nutzen, wurde die hybride Suche entwickelt. Durch die Kombination von Volltextindizierung und Vektorsuche kann sie verschiedene Anforderungen an die Textsuche effektiv erfüllen, die Genauigkeit und Geschwindigkeit bei der Suche nach Texten verbessern und die Erwartungen der Benutzer an präzise Ergebnisse effizient erfüllen.
# Übersicht über das Tutorial
Dieses Dokument führt Sie durch drei Suchexperimente:
✅ Vektorsuche in MyScale durchführen
Alle Dokument- und Abfragetexte verwenden das all-MiniLM-L6-v2 (opens new window)-Modell zur Vektorengenerierung und den Kosinusabstand zur Ähnlichkeitsmessung.
✅ Textsuche in MyScale durchführen
MyScale integriert die Tantivy (opens new window)-Bibliothek, um die BM25-Indizierung für die Volltextsuche (FTS) zu ermöglichen. Durch die Indizierung aller Textdaten in der Tabelle ermöglicht die FTS-Fähigkeit von MyScale, Suchergebnisse basierend auf BM25-Werten zu rangieren und so relevantere und genauere Suchergebnisse zu liefern.
✅ Verschmelzen von Vektor- und Textsuchergebnissen mit der RRF-Strategie
Wir verwenden die weit verbreitete Python-Bibliothek ranx (opens new window), um Vektor- und Textsuchergebnisse zu kombinieren. Diese Fusion verbessert die Anpassungsfähigkeit von Textsuchen in verschiedenen Szenarien und letztendlich die Suchgenauigkeit.
Bevor Sie beginnen, stellen Sie sicher, dass Sie einen MyScale-Cluster eingerichtet haben. Für Anweisungen zur Einrichtung verweisen wir auf 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. Der Text wurde mit dem all-MiniLM-L6-v2 (opens new window)-Modell verarbeitet, um 384-dimensionale Vektoren zu erstellen, die in der Spalte body_vector
gespeichert sind. Die Ähnlichkeit zwischen den Vektoren wurde mit dem Kosinusabstand berechnet.
TIP
Weitere Informationen zur Verwendung von all-MiniLM-L6-v2 finden Sie in der Dokumentation von HuggingFace.
Der Datensatz wiki_abstract_with_vector.parquet (opens new window) hat eine Größe von 8,2 GB. Sie können den Inhalt unten vorab anzeigen, ohne ihn lokal herunterladen zu müssen, da wir ihn in den nachfolgenden Experimenten direkt über S3 in MyScale importieren werden.
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] |
... | ... | ... | ... | ... |
# Erstellung der Tabelle und Import der Daten
Um die Tabelle wiki_abstract_5m
im SQL-Arbeitsbereich von MyScale zu erstellen, führen Sie den folgenden SQL-Befehl aus:
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;
Importieren Sie die Daten aus S3 in die Tabelle. Bitte haben Sie Geduld während des Datenimportprozesses.
INSERT INTO default.wiki_abstract_5m
SELECT * FROM s3('https://myscale-datasets.s3.ap-southeast-1.amazonaws.com/wiki_abstract_with_vector.parquet', 'Parquet');
Hinweis
Die geschätzte Zeit für den Datenimport beträgt etwa 10 Minuten.
Überprüfen Sie, ob es 5.622.309 Zeilen Daten in der Tabelle gibt, indem Sie diese Abfrage ausführen:
SELECT count(*) FROM default.wiki_abstract_5m;
Ausgabe:
count() |
---|
5622309 |
Um die Tabelle zu optimieren und die Leistung der Vektorsuche zu verbessern, indem die Daten in einen Teil zusammengeführt werden (optional), führen Sie diesen SQL-Befehl in Ihrem SQL-Arbeitsbereich aus:
OPTIMIZE TABLE default.wiki_abstract_5m FINAL;
Dieser Optimierungsschritt kann einige Zeit in Anspruch nehmen.
Überprüfen Sie mit dieser Abfrage, ob die Datenteile dieser Tabelle zu einem einzigen Teil komprimiert wurden:
SELECT COUNT(*) FROM system.parts WHERE table='wiki_abstract_5m' AND active=1;
Wenn erfolgreich, sehen Sie:
count() |
---|
1 |
# Index erstellen
# FTS-Index erstellen
TIP
Weitere Informationen zum Erstellen eines FTS-Index finden Sie in der Dokumentation zum FTS-Index.
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 stop words
verwendet. Der stem
-Tokenizer kann Wortformen im Text übersehen, um präzisere Suchergebnisse zu erzielen. Durch die Verwendung von stop words
werden häufige Wörter wie "a", "an", "of" und "in" herausgefiltert, um die Suchgenauigkeit zu verbessern.
ALTER TABLE default.wiki_abstract_5m
ADD INDEX body_idx (body)
TYPE fts('{"body":{"tokenizer":{"type":"stem", "stop_word_filters":["english"]}}}');
Materialisieren Sie den Index:
ALTER TABLE default.wiki_abstract_5m MATERIALIZE INDEX body_idx;
# Vektorindex erstellen
TIP
Erfahren Sie mehr über den MSTG-Vektorindex in der Dokumentation zur Vektorsuche.
Um den MSTG
-Vektorindex mit Kosinus als Berechnungsmethode für den body_vec_idx
in der Tabelle default.wiki_abstract_5m
zu erstellen, führen Sie diesen SQL-Befehl aus:
ALTER TABLE default.wiki_abstract_5m
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 diese SQL-Abfrage aus. Wenn die Spalte "status" "Built" anzeigt, bedeutet dies, dass der Index erfolgreich erstellt wurde. Während des Fortschritts sollte "InProgress" angezeigt werden.
SELECT * FROM system.vector_indices;
# Hybride Suche durchführen
# Vorbereitungen
Um den Abfragetext in Vektoren umzuwandeln, verwenden wir das all-MiniLM-L6-v2 (opens new window)-Modell.
Installieren Sie zunächst die Bibliothek sentence-transformers
, indem Sie Folgendes ausführen:
pip install -U sentence-transformers
Für die Fusion verwenden wir die Bibliothek ranx (opens new window). Installieren Sie sie mit:
pip install -U ranx
Die hybride Suche wird in einer Python-Datei implementiert. Bevor Sie mit dieser Übung fortfahren, stellen Sie sicher, dass Sie Ihre MyScale-Cluster-Informationen in den bereitgestellten Beispielcode eingeben.
TIP
Die Verbindungsdetails für einen MyScale-Cluster finden Sie in der Webkonsole.
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)
# Verwenden Sie das Modell all-MiniLM-L6-v2
model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
# MyScale-Informationen
host = "Ihr Cluster-Endpunkt"
port = 443
username = "Ihr Benutzername"
password = "Ihr Passwort"
database = "default"
table = "wiki_abstract_5m"
# Initialisieren Sie den MyScale-Client
client = clickhouse_connect.get_client(host=host, port=port,
username=username, password=password)
# Verwenden Sie eine Tabelle, um Ihren Inhalt auszugeben
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)
# Vektorsuche durchführen
TIP
Die British Graham Land Expedition (BGLE) war eine britische Expedition. Detaillierte Informationen finden Sie in Wikipedia (opens new window).
Unser Ziel ist es, die von der BGLE-Expedition in diesem Datensatz besuchten und kartierten Orte zu identifizieren. Dazu verwenden wir "Charted by BGLE"
als Suchzeichenfolge bei einer Vektorsuchabfrage.
TIP
Fügen Sie den in dieser Nachricht bereitgestellten Beispielcode in die zuvor erstellte Python-Datei ein, um eine reibungslose Ausführung des Programms zu gewährleisten. Stellen Sie außerdem sicher, dass Sie die anderen Schritte in ähnlicher Weise behandeln.
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("\nErgebnisse der Vektorsuche:")
print_results(vector_search_res.result_rows[:10], ["ID", "Titel", "Text", "Abstand"])
Die über die Vektorsuche abgerufenen Dokumente enthalten keine Informationen zu "Charted by BGLE" in den ersten 10 Ergebnissen, da die Vektorsuche für kurze Textabfragen tendenziell schlecht abschneidet.
ID | Titel | Text | Abstand |
---|---|---|---|
1177089 | B.G. discography | Dies ist die Diskografie von B.G. | 0.44516414403915405 |
2710950 | Ruy Blas and the Blasé Roué | Ruy Blas and the Blasé Roué ist eine Burleske von A. C. | 0.4736078381538391 |
4571962 | BLL | BLL kann sich beziehen auf: | 0.48070353269577026 |
3797998 | Bles | Bles kann sich beziehen auf: | 0.4849556088447571 |
4558187 | The Complete Blam Blam Blam | The Complete Blam Blam Bam ist eine Kompilation LP von Blam Blam Blam. Sie wurde im November 1992 veröffentlicht. | 0.4863016605377197 |
5556733 | BLG | BLG kann sich beziehen auf: | 0.49544525146484375 |
4591273 | Blagg | Blagg kann sich beziehen auf: | 0.5007722973823547 |
3087541 | Paul Bley discography | Dies ist die Diskografie des kanadischen Jazzmusikers Paul Bley. | 0.5030192136764526 |
3389086 | Blot (album) | Blot ist das vierte Studioalbum der norwegischen Black-/Viking-Metal-Band Einherjer. Es wurde am 21. November 2003 von Tabu Recordings veröffentlicht. | 0.5040180087089539 |
1876940 | Blåljus! | Blåljus! ist eine sechsbändige Taschenbuchserie von Romanen von Margit Sandemo und wurde von der schwedischen Tochtergesellschaft Boknöje AB der norwegischen Veröffentlichung Bladkompaniet im Jahr 2004 veröffentlicht. | 0.5080643892288208 |
# Textsuche durchführen
Wir verwenden die TextSearch()
-Funktion von MyScale, um eine Reihe relevanter Ergebnisse zusammen mit BM25-Werten abzurufen. Um die spätere Ergebnisfusion zu erleichtern, müssen wir diese Dokumentendaten vorübergehend speichern.
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)
# Suchergebnisse vorübergehend speichern.
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]}
# Verwenden der RRF-Strategie zur Verschmelzung von Vektor- und Textsuchergebnissen
Wir verwenden die ranx (opens new window)-Bibliothek, um Vektor- und Textsuchergebnisse 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.
# ID und Score aus den Abfrageergebnissen 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}}
# Score der Abfrageergebnisse normalisieren.
vector_run = rank_norm(Run(vector_dict, name="vector"))
bm25_run = rank_norm(Run(bm25_dict, name="bm25"))
# Fusion der Abfrageergebnisse mit RRF.
combined_run = fuse(
runs=[vector_run, bm25_run],
method="rrf",
params={'k': 10}
)
print("\nFusions-Ergebnisse:")
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", "Titel", "Text", "Score"])
Die Ergebnisse der Fusionsabfrage lauten wie folgt: Die hybride Suche hat fünf Artikel genau den Orten zugeordnet, die von der BGLE-Expedition kartiert wurden, und zeigt damit die Vorteile der hybriden Suche bei der Verarbeitung von kurzen Textabfragen.
ID | Title | Body | Score |
---|---|---|---|
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 |
# Fazit
Dieses Dokument gibt Einblicke in die Verwendung der hybriden Suche von MyScale in Szenarien der Textsuche 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 hybriden Suche ist mit den fortschrittlichen Volltext- und Vektorsuchfunktionen von MyScale einfach und liefert durch die Kombination von Stichwort- und semantischen Informationen genauere Ergebnisse.