milvus-logo
LFAI
Home
  • Anleitungen

Hybride Suche mit Milvus

Open In Colab GitHub Repository

In diesem Tutorium wird gezeigt, wie man eine hybride Suche mit Milvus und dem BGE-M3-Modell durchführt. Das BGE-M3-Modell kann Text in dichte und spärliche Vektoren umwandeln. Milvus unterstützt die Speicherung beider Arten von Vektoren in einer Sammlung und ermöglicht so eine hybride Suche, die die Relevanz der Ergebnisse erhöht.

Milvus unterstützt dichte, spärliche und hybride Retrievalmethoden:

  • Dichtes Retrieval: Nutzt den semantischen Kontext, um die Bedeutung hinter den Abfragen zu verstehen.
  • Sparse Retrieval: Konzentriert sich auf den Abgleich von Schlüsselwörtern, um Ergebnisse auf der Grundlage bestimmter Begriffe zu finden, was einer Volltextsuche entspricht.
  • Hybrides Retrieval: Kombiniert sowohl Dense- als auch Sparse-Ansätze und erfasst den vollständigen Kontext und spezifische Schlüsselwörter für umfassende Suchergebnisse.

Durch die Integration dieser Methoden gleicht die Milvus-Hybridsuche semantische und lexikalische Ähnlichkeiten aus und verbessert so die Gesamtrelevanz der Suchergebnisse. Dieses Notebook führt durch den Prozess der Einrichtung und Verwendung dieser Suchstrategien und zeigt ihre Effektivität in verschiedenen Suchszenarien auf.

Abhängigkeiten und Umgebung

$ pip install --upgrade pymilvus "pymilvus[model]"

Datensatz herunterladen

Um die Suche zu demonstrieren, benötigen wir einen Korpus von Dokumenten. Wir verwenden das Quora Duplicate Questions Dataset und legen es im lokalen Verzeichnis ab.

Quelle des Datensatzes: Erste Veröffentlichung des Quora-Datensatzes: Frage-Paare

# Run this cell to download the dataset
$ wget http://qim.fs.quoracdn.net/quora_duplicate_questions.tsv

Laden und Aufbereiten der Daten

Wir werden den Datensatz laden und einen kleinen Korpus für die Suche vorbereiten.

import pandas as pd

file_path = "quora_duplicate_questions.tsv"
df = pd.read_csv(file_path, sep="\t")
questions = set()
for _, row in df.iterrows():
    obj = row.to_dict()
    questions.add(obj["question1"][:512])
    questions.add(obj["question2"][:512])
    if len(questions) > 500:  # Skip this if you want to use the full dataset
        break

docs = list(questions)

# example question
print(docs[0])
What is the strongest Kevlar cord?

BGE-M3 Modell für Einbettungen verwenden

Das BGE-M3-Modell kann Texte als dichte und spärliche Vektoren einbetten.

from milvus_model.hybrid import BGEM3EmbeddingFunction

ef = BGEM3EmbeddingFunction(use_fp16=False, device="cpu")
dense_dim = ef.dim["dense"]

# Generate embeddings using BGE-M3 model
docs_embeddings = ef(docs)
Fetching 30 files: 100%|██████████| 30/30 [00:00<00:00, 302473.85it/s]
Inference Embeddings: 100%|██████████| 32/32 [01:59<00:00,  3.74s/it]

Milvus-Sammlung und -Index einrichten

Wir werden die Milvus-Sammlung einrichten und Indizes für die Vektorfelder erstellen.

  • Die Uri als lokale Datei zu setzen, z.B. "./milvus.db", ist die bequemste Methode, da sie automatisch Milvus Lite nutzt, um alle Daten in dieser Datei zu speichern.
  • Wenn Sie große Datenmengen haben, z. B. mehr als eine Million Vektoren, können Sie einen leistungsfähigeren Milvus-Server auf Docker oder Kubernetes einrichten. In diesem Fall verwenden Sie bitte die Server-Uri, z. B. http://localhost:19530, als Ihre Uri.
  • Wenn Sie Zilliz Cloud, den vollständig verwalteten Cloud-Service für Milvus, nutzen möchten, passen Sie die uri und das Token an, die dem öffentlichen Endpunkt und dem API-Schlüssel in Zilliz Cloud entsprechen.
from pymilvus import (
    connections,
    utility,
    FieldSchema,
    CollectionSchema,
    DataType,
    Collection,
)

# Connect to Milvus given URI
connections.connect(uri="./milvus.db")

# Specify the data schema for the new Collection
fields = [
    # Use auto generated id as primary key
    FieldSchema(
        name="pk", dtype=DataType.VARCHAR, is_primary=True, auto_id=True, max_length=100
    ),
    # Store the original text to retrieve based on semantically distance
    FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=512),
    # Milvus now supports both sparse and dense vectors,
    # we can store each in a separate field to conduct hybrid search on both vectors
    FieldSchema(name="sparse_vector", dtype=DataType.SPARSE_FLOAT_VECTOR),
    FieldSchema(name="dense_vector", dtype=DataType.FLOAT_VECTOR, dim=dense_dim),
]
schema = CollectionSchema(fields)

# Create collection (drop the old one if exists)
col_name = "hybrid_demo"
if utility.has_collection(col_name):
    Collection(col_name).drop()
col = Collection(col_name, schema, consistency_level="Strong")

# To make vector search efficient, we need to create indices for the vector fields
sparse_index = {"index_type": "SPARSE_INVERTED_INDEX", "metric_type": "IP"}
col.create_index("sparse_vector", sparse_index)
dense_index = {"index_type": "AUTOINDEX", "metric_type": "IP"}
col.create_index("dense_vector", dense_index)
col.load()

Daten in die Milvus-Sammlung einfügen

Fügen Sie Dokumente und ihre Einbettungen in die Sammlung ein.

# For efficiency, we insert 50 records in each small batch
for i in range(0, len(docs), 50):
    batched_entities = [
        docs[i : i + 50],
        docs_embeddings["sparse"][i : i + 50],
        docs_embeddings["dense"][i : i + 50],
    ]
    col.insert(batched_entities)
print("Number of entities inserted:", col.num_entities)
Number of entities inserted: 502

Geben Sie Ihre Suchabfrage ein

# Enter your search query
query = input("Enter your search query: ")
print(query)

# Generate embeddings for the query
query_embeddings = ef([query])
# print(query_embeddings)
How to start learning programming?

Wir werden zunächst einige hilfreiche Funktionen vorbereiten, um die Suche auszuführen:

  • dense_search: nur im dichten Vektorfeld suchen
  • sparse_search: nur im spärlichen Vektorfeld suchen
  • hybrid_searchSuche über dichte und dünne Vektorfelder mit einem gewichteten Reranker
from pymilvus import (
    AnnSearchRequest,
    WeightedRanker,
)


def dense_search(col, query_dense_embedding, limit=10):
    search_params = {"metric_type": "IP", "params": {}}
    res = col.search(
        [query_dense_embedding],
        anns_field="dense_vector",
        limit=limit,
        output_fields=["text"],
        param=search_params,
    )[0]
    return [hit.get("text") for hit in res]


def sparse_search(col, query_sparse_embedding, limit=10):
    search_params = {
        "metric_type": "IP",
        "params": {},
    }
    res = col.search(
        [query_sparse_embedding],
        anns_field="sparse_vector",
        limit=limit,
        output_fields=["text"],
        param=search_params,
    )[0]
    return [hit.get("text") for hit in res]


def hybrid_search(
    col,
    query_dense_embedding,
    query_sparse_embedding,
    sparse_weight=1.0,
    dense_weight=1.0,
    limit=10,
):
    dense_search_params = {"metric_type": "IP", "params": {}}
    dense_req = AnnSearchRequest(
        [query_dense_embedding], "dense_vector", dense_search_params, limit=limit
    )
    sparse_search_params = {"metric_type": "IP", "params": {}}
    sparse_req = AnnSearchRequest(
        [query_sparse_embedding], "sparse_vector", sparse_search_params, limit=limit
    )
    rerank = WeightedRanker(sparse_weight, dense_weight)
    res = col.hybrid_search(
        [sparse_req, dense_req], rerank=rerank, limit=limit, output_fields=["text"]
    )[0]
    return [hit.get("text") for hit in res]

Lassen Sie uns drei verschiedene Suchen mit den definierten Funktionen durchführen:

dense_results = dense_search(col, query_embeddings["dense"][0])
sparse_results = sparse_search(col, query_embeddings["sparse"]._getrow(0))
hybrid_results = hybrid_search(
    col,
    query_embeddings["dense"][0],
    query_embeddings["sparse"]._getrow(0),
    sparse_weight=0.7,
    dense_weight=1.0,
)

Suchergebnisse anzeigen

Um die Ergebnisse der Dense-, Sparse- und Hybrid-Suche anzuzeigen, benötigen wir einige Hilfsmittel, um die Ergebnisse zu formatieren.

def doc_text_formatting(ef, query, docs):
    tokenizer = ef.model.tokenizer
    query_tokens_ids = tokenizer.encode(query, return_offsets_mapping=True)
    query_tokens = tokenizer.convert_ids_to_tokens(query_tokens_ids)
    formatted_texts = []

    for doc in docs:
        ldx = 0
        landmarks = []
        encoding = tokenizer.encode_plus(doc, return_offsets_mapping=True)
        tokens = tokenizer.convert_ids_to_tokens(encoding["input_ids"])[1:-1]
        offsets = encoding["offset_mapping"][1:-1]
        for token, (start, end) in zip(tokens, offsets):
            if token in query_tokens:
                if len(landmarks) != 0 and start == landmarks[-1]:
                    landmarks[-1] = end
                else:
                    landmarks.append(start)
                    landmarks.append(end)
        close = False
        formatted_text = ""
        for i, c in enumerate(doc):
            if ldx == len(landmarks):
                pass
            elif i == landmarks[ldx]:
                if close:
                    formatted_text += "</span>"
                else:
                    formatted_text += "<span style='color:red'>"
                close = not close
                ldx = ldx + 1
            formatted_text += c
        if close is True:
            formatted_text += "</span>"
        formatted_texts.append(formatted_text)
    return formatted_texts

Dann können wir die Suchergebnisse als Text mit Hervorhebungen anzeigen:

from IPython.display import Markdown, display

# Dense search results
display(Markdown("**Dense Search Results:**"))
formatted_results = doc_text_formatting(ef, query, dense_results)
for result in dense_results:
    display(Markdown(result))

# Sparse search results
display(Markdown("\n**Sparse Search Results:**"))
formatted_results = doc_text_formatting(ef, query, sparse_results)
for result in formatted_results:
    display(Markdown(result))

# Hybrid search results
display(Markdown("\n**Hybrid Search Results:**"))
formatted_results = doc_text_formatting(ef, query, hybrid_results)
for result in formatted_results:
    display(Markdown(result))

Dichte Suchergebnisse:

Wie fange ich am besten an, Robotik zu lernen?

Wie lerne ich eine Computersprache wie Java?

Wie kann ich anfangen, Informationssicherheit zu lernen?

Was ist Java-Programmierung? Wie lernt man die Programmiersprache Java?

Wie kann ich Computersicherheit lernen?

Wie kann ich am besten mit der Robotik beginnen? Welches ist die beste Entwicklungsplatine, mit der ich anfangen kann zu arbeiten?

Wie kann ich lernen, fließend Englisch zu sprechen?

Wie kann ich am besten Französisch lernen?

Wie kann man Physik leicht erlernen?

Wie bereiten wir uns auf UPSC vor?

Sparsame Suchergebnisse:

Was ist Java-Programmierung? Wie lernt man die Programmiersprache Java?

Wie fängt man am besten an, Robotik zu lernen?

Was ist die Alternative zum maschinellen Lernen?

Wie erstelle ich ein neues Terminal und eine neue Shell in Linux mit C-Programmierung?

Wie erstelle ich eine neue Shell in einem neuen Terminal mit C-Programmierung (Linux-Terminal)?

Welches Unternehmen ist in Hyderabad besser zu gründen?

Welches Unternehmen ist ein guter Start in Hyderabad?

Was ist der beste Weg, um mit der Robotik zu beginnen? Welches ist die beste Entwicklungsplatine, mit der ich anfangen kann zu arbeiten?

Welche Mathematik braucht ein absoluter Neuling, um Algorithmen für die Computerprogrammierung zu verstehen? Welche Bücher über Algorithmen sind für einen absoluten Anfänger geeignet?

Wie kann man das Leben so gestalten, dass es zu einem passt, und wie kann man verhindern, dass das Leben einen geistig und emotional missbraucht?

Hybride Suchergebnisse:

Wie fange ich am besten mit der Robotik an? Welches ist die beste Entwicklungsplatine, mit der ich anfangen kann zu arbeiten?

Was ist Java-Programmierung? Wie lernt man die Programmiersprache Java?

Was ist der beste Weg, um mit dem Lernen von Robotik zu beginnen?

Wie bereitet man sich auf UPSC vor?

Wie kann man Physik leicht erlernen?

Was sind die besten Wege, Französisch zu lernen?

Wie kann ich lernen, fließend Englisch zu sprechen?

Wie kann ich Computersicherheit lernen?

Wie kann ich anfangen, Informationssicherheit zu lernen?

Wie lerne ich eine Computersprache wie Java?

Was ist die Alternative zum maschinellen Lernen?

Wie erstelle ich ein neues Terminal und eine neue Shell in Linux mit C-Programmierung?

Wie erstelle ich eine neue Shell in einem neuen Terminal mit C-Programmierung (Linux-Terminal)?

Welches Unternehmen ist in Hyderabad besser zu gründen?

Welches Unternehmen ist ein guter Start in Hyderabad?

Welche Mathematik braucht ein völliger Neuling, um Algorithmen für die Computerprogrammierung zu verstehen? Welche Bücher über Algorithmen sind für einen absoluten Anfänger geeignet?

Wie kann man das Leben so gestalten, dass es zu einem passt, und wie kann man verhindern, dass das Leben einen geistig und emotional missbraucht?

Schnell einsatzbereit

Um zu erfahren, wie man mit diesem Tutorial eine Online-Demo startet, sehen Sie sich bitte die Beispielanwendung an.

Übersetzt vonDeepL

Tabelle der Inhalte

Try Managed Milvus for Free

Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

Get Started
Feedback

War diese Seite hilfreich?