Erste Schritte mit der hybriden semantischen / Volltextsuche mit Milvus 2.5
In diesem Artikel zeigen wir Ihnen, wie Sie die neue Volltextsuche schnell einsetzen und mit der herkömmlichen semantischen Suche auf Basis von Vektoreinbettungen kombinieren können.
Voraussetzung
Stellen Sie zunächst sicher, dass Sie Milvus 2.5 installiert haben:
pip install -U pymilvus[model]
und eine laufende Instanz von Milvus Standalone (z.B. auf Ihrem lokalen Rechner) unter Verwendung der Installationsanweisungen in den Milvus-Dokumenten.
Erstellen des Datenschemas und der Suchindizes
Wir importieren die benötigten Klassen und Funktionen:
from pymilvus import MilvusClient, DataType, Function, FunctionType, model
Vielleicht sind Ihnen zwei neue Einträge für Milvus 2.5 aufgefallen, Function
und FunctionType
, die wir gleich erläutern werden.
Als nächstes öffnen wir die Datenbank mit Milvus Standalone, d.h. lokal, und erstellen das Datenschema. Das Schema besteht aus einem Integer-Primärschlüssel, einem Text-String, einem Dense-Vektor der Dimension 384 und einem Sparse-Vektor (mit unbegrenzter Dimensionalität). Beachten Sie, dass Milvus Lite derzeit keine Volltextsuche unterstützt, sondern nur Milvus Standalone und Milvus Distributed.
client = MilvusClient(uri="http://localhost:19530")
schema = client.create_schema()
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, auto_id=True)
schema.add_field(field_name="text", datatype=DataType.VARCHAR, max_length=1000, enable_analyzer=True)
schema.add_field(field_name="dense", datatype=DataType.FLOAT_VECTOR, dim=768),
schema.add_field(field_name="sparse", datatype=DataType.SPARSE_FLOAT_VECTOR)
{'auto_id': False, 'description': '', 'fields': [{'name': 'id', 'description': '', 'type': <DataType.INT64: 5>, 'is_primary': True, 'auto_id': True}, {'name': 'text', 'description': '', 'type': <DataType.VARCHAR: 21>, 'params': {'max_length': 1000, 'enable_analyzer': True}}, {'name': 'dense', 'description': '', 'type': <DataType.FLOAT_VECTOR: 101>, 'params': {'dim': 768}}, {'name': 'sparse', 'description': '', 'type': <DataType.SPARSE_FLOAT_VECTOR: 104>}], 'enable_dynamic_field': False}
Sie haben vielleicht den Parameter enable_analyzer=True
bemerkt. Dieser weist Milvus 2.5 an, den lexikalischen Parser für dieses Feld zu aktivieren und eine Liste von Token und Tokenhäufigkeiten zu erstellen, die für die Volltextsuche erforderlich sind. Das Feld sparse
enthält eine Vektordarstellung der Dokumentation als Bag-of-Words, die aus dem Parser text
erzeugt wird.
Aber wie verbinden wir die Felder text
und sparse
und teilen Milvus mit, wie sparse
aus text
berechnet werden soll? An dieser Stelle müssen wir das Objekt Function
aufrufen und dem Schema hinzufügen:
bm25_function = Function(
name="text_bm25_emb", # Function name
input_field_names=["text"], # Name of the VARCHAR field containing raw text data
output_field_names=["sparse"], # Name of the SPARSE_FLOAT_VECTOR field reserved to store generated embeddings
function_type=FunctionType.BM25,
)
schema.add_function(bm25_function)
{'auto_id': False, 'description': '', 'fields': [{'name': 'id', 'description': '', 'type': <DataType.INT64: 5>, 'is_primary': True, 'auto_id': True}, {'name': 'text', 'description': '', 'type': <DataType.VARCHAR: 21>, 'params': {'max_length': 1000, 'enable_analyzer': True}}, {'name': 'dense', 'description': '', 'type': <DataType.FLOAT_VECTOR: 101>, 'params': {'dim': 768}}, {'name': 'sparse', 'description': '', 'type': <DataType.SPARSE_FLOAT_VECTOR: 104>, 'is_function_output': True}], 'enable_dynamic_field': False, 'functions': [{'name': 'text_bm25_emb', 'description': '', 'type': <FunctionType.BM25: 1>, 'input_field_names': ['text'], 'output_field_names': ['sparse'], 'params': {}}]}
Die Abstraktion des Function
Objekts ist allgemeiner als die Anwendung der Volltextsuche. In Zukunft kann es auch für andere Fälle verwendet werden, in denen ein Feld eine Funktion eines anderen Feldes sein muss. In unserem Fall geben wir an, dass sparse
eine Funktion von text
ist, und zwar über die Funktion FunctionType.BM25
. BM25
bezieht sich auf eine im Information Retrieval übliche Metrik zur Berechnung der Ähnlichkeit einer Anfrage mit einem Dokument (relativ zu einer Sammlung von Dokumenten).
Wir verwenden das Standard-Einbettungsmodell in Milvus, nämlich paraphrase-albert-small-v2:
embedding_fn = model.DefaultEmbeddingFunction()
Der nächste Schritt besteht darin, unsere Suchindizes hinzuzufügen. Wir haben einen für den dichten Vektor und einen separaten für den spärlichen Vektor. Der Index-Typ ist SPARSE_INVERTED_INDEX
mit BM25
, da die Volltextsuche eine andere Suchmethode erfordert als die für dichte Standard-Vektoren.
index_params = client.prepare_index_params()
index_params.add_index(
field_name="dense",
index_type="AUTOINDEX",
metric_type="COSINE"
)
index_params.add_index(
field_name="sparse",
index_type="SPARSE_INVERTED_INDEX",
metric_type="BM25"
)
Schließlich erstellen wir unsere Sammlung:
client.drop_collection('demo')
client.list_collections()
[]
client.create_collection(
collection_name='demo',
schema=schema,
index_params=index_params
)
client.list_collections()
['demo']
Damit haben wir eine leere Datenbank, die für die Aufnahme von Textdokumenten und die Durchführung von semantischen und Volltextsuchen eingerichtet ist!
Einfügen von Daten und Durchführen einer Volltextsuche
Das Einfügen von Daten ist nicht anders als in früheren Versionen von Milvus:
docs = [
'information retrieval is a field of study.',
'information retrieval focuses on finding relevant information in large datasets.',
'data mining and information retrieval overlap in research.'
]
embeddings = embedding_fn(docs)
client.insert('demo', [
{'text': doc, 'dense': vec} for doc, vec in zip(docs, embeddings)
])
{'insert_count': 3, 'ids': [454387371651630485, 454387371651630486, 454387371651630487], 'cost': 0}
Lassen Sie uns zunächst eine Volltextsuche veranschaulichen, bevor wir mit der hybriden Suche fortfahren:
search_params = {
'params': {'drop_ratio_search': 0.2},
}
results = client.search(
collection_name='demo',
data=['whats the focus of information retrieval?'],
output_fields=['text'],
anns_field='sparse',
limit=3,
search_params=search_params
)
Der Suchparameter drop_ratio_search
bezieht sich auf den Anteil der Dokumente mit niedrigerer Punktzahl, die während des Suchalgorithmus verworfen werden.
Schauen wir uns die Ergebnisse an:
for hit in results[0]:
print(hit)
{'id': 454387371651630485, 'distance': 1.3352930545806885, 'entity': {'text': 'information retrieval is a field of study.'}}
{'id': 454387371651630486, 'distance': 0.29726022481918335, 'entity': {'text': 'information retrieval focuses on finding relevant information in large datasets.'}}
{'id': 454387371651630487, 'distance': 0.2715056240558624, 'entity': {'text': 'data mining and information retrieval overlap in research.'}}
Hybride semantische Suche und Volltextsuche durchführen
Kombinieren wir nun, was wir gelernt haben, um eine hybride Suche durchzuführen, die separate semantische und Volltextsuchen mit einem Reranker kombiniert:
from pymilvus import AnnSearchRequest, RRFRanker
query = 'whats the focus of information retrieval?'
query_dense_vector = embedding_fn([query])
search_param_1 = {
"data": query_dense_vector,
"anns_field": "dense",
"param": {
"metric_type": "COSINE",
},
"limit": 3
}
request_1 = AnnSearchRequest(**search_param_1)
search_param_2 = {
"data": [query],
"anns_field": "sparse",
"param": {
"metric_type": "BM25",
"params": {"drop_ratio_build": 0.0}
},
"limit": 3
}
request_2 = AnnSearchRequest(**search_param_2)
reqs = [request_1, request_2]
ranker = RRFRanker()
res = client.hybrid_search(
collection_name="demo",
output_fields=['text'],
reqs=reqs,
ranker=ranker,
limit=3
)
for hit in res[0]:
print(hit)
{'id': 454387371651630485, 'distance': 0.032786883413791656, 'entity': {'text': 'information retrieval is a field of study.'}}
{'id': 454387371651630486, 'distance': 0.032258063554763794, 'entity': {'text': 'information retrieval focuses on finding relevant information in large datasets.'}}
{'id': 454387371651630487, 'distance': 0.0317460335791111, 'entity': {'text': 'data mining and information retrieval overlap in research.'}}
Wie Sie vielleicht bemerkt haben, unterscheidet sich dies nicht von einer hybriden Suche mit zwei separaten semantischen Feldern (verfügbar seit Milvus 2.4). Die Ergebnisse sind in diesem einfachen Beispiel identisch mit der Volltextsuche, aber bei größeren Datenbanken und stichwortspezifischen Suchen hat die hybride Suche in der Regel eine höhere Trefferquote.
Zusammenfassung
Sie sind nun mit allen Kenntnissen ausgestattet, die Sie benötigen, um mit Milvus 2.5 eine Volltextsuche und eine hybride semantische/volltextliche Suche durchzuführen. In den folgenden Artikeln erfahren Sie mehr darüber, wie die Volltextsuche funktioniert und warum sie eine Ergänzung zur semantischen Suche ist:
- Voraussetzung
- Erstellen des Datenschemas und der Suchindizes
- Einfügen von Daten und Durchführen einer Volltextsuche
- Hybride semantische Suche und Volltextsuche durchführen
- Zusammenfassung
On This Page
Try Managed Milvus for Free
Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.
Get StartedLike the article? Spread the word