Agenten

Hybrid-Search und RAG-Retrieval mit Elasticsearch

Vector Search ist nicht automatisch die beste Retrieval-Strategie für RAG. In einem kleinen Elasticsearch-Experiment vergleichen wir klassische Volltextsuche, semantische Suche und Hybrid Search.

Bernd Fischer
5 Minuten Lesezeit
30 Aug 2026

Beim Aufbau eines Retrieval-Augmented-Generation-Systems stellt sich ziemlich früh eine wichtige Architekturfrage:

Wie finden wir eigentlich die Dokumente, die wir anschließend dem LLM zur Verfügung stellen?

Eine häufige Antwort lautet heute: Vector Search.

Wir erzeugen Embeddings, speichern sie in einer Vektordatenbank, erzeugen ein Embedding für die Benutzerfrage und suchen anschließend nach den ähnlichsten Vektoren.

Das funktioniert.

Es bedeutet aber nicht, dass Vector Search automatisch die beste Retrieval-Strategie ist.

Klassische Volltextsuche ist bei bestimmten Aufgaben ausgesprochen gut, beispielsweise bei exakten Begriffen, Identifikatoren, Produktcodes oder technischen Bezeichnungen.

Semantische Suche hat eine andere Stärke: Sie kann relevante Dokumente finden, obwohl Benutzer und Dokument unterschiedliche Begriffe verwenden.

Und dann gibt es noch Hybrid Search, das beide Ansätze miteinander kombiniert.

Statt theoretisch darüber zu diskutieren, welcher Ansatz besser sein müsste, habe ich ein kleines Experiment mit Elasticsearch gebaut.

Den vollständigen Code und alle verwendeten Queries gibt es im Elasticsearch Retrieval Lab auf GitHub.

Das Experiment

Das Setup ist bewusst überschaubar:

  • Elasticsearch 9.5
  • Python
  • 16 Dokumente
  • 10 vorher festgelegte Queries
  • BM25
  • Dense Vector Search
  • Hybrid Search mit Reciprocal Rank Fusion
  • all-MiniLM-L6-v2 als Embedding-Modell

Die Dokumente simulieren eine kleine interne IT-Wissensbasis eines Unternehmens.

Darin geht es beispielsweise um Laptops, Remote Work, Beschaffung, Sicherheitsvorfälle und Unternehmensrichtlinien.

Entscheidend ist, dass die Testdaten absichtlich Konflikte enthalten.

Zum Beispiel:

DOC-013
Security incident SEC-443 concerns a stolen company laptop.
The device must be remotely locked and reported to IT security.

DOC-014
Security incident SEC-444 concerns a phishing campaign targeting
company employees. Suspicious messages must be reported immediately.

Die beiden Dokumente sind sich semantisch ähnlich.

Ihre Incident-IDs sind jedoch unterschiedlich.

Andere Dokumente teilen sich gezielt Begriffe wie company, laptop, security, procurement oder policy, obwohl sie unterschiedliche Themen behandeln.

Bevor die Retrieval-Verfahren miteinander verglichen wurden, habe ich außerdem für jede Query festgelegt, welches Dokument auf Platz 1 erwartet wird.

Das ist für einen solchen Versuch wichtig.

Ansonsten besteht schnell die Gefahr, dass man sich hinterher eine schöne Erklärung dafür zurechtlegt, warum ein bestimmtes Suchergebnis doch irgendwie richtig gewesen sein könnte.

Zuerst: BM25

Elasticsearch bringt bereits eine leistungsfähige klassische Volltextsuche mit.

Für normale text-Felder verwendet Elasticsearch standardmäßig BM25 als Similarity-Algorithmus.

Eine einfache Suche sieht beispielsweise so aus:

response = client.search(
    index="retrieval-lab",
    query={
        "match": {
            "text": query,
        }
    },
    size=3,
)

BM25 versucht nicht, die Bedeutung eines Satzes so zu erfassen, wie es ein Embedding-Modell tut.

Stattdessen werden Dokumente anhand lexikalischer Signale bewertet. Dazu gehören unter anderem die Häufigkeit eines Begriffs, seine Seltenheit im gesamten Dokumentbestand und die Länge eines Dokuments.

Darunter arbeitet eine der fundamentalen Datenstrukturen des Information Retrieval: der Inverted Index. Vielleicht erinnert sich der eine oder andere noch aus dem Informatikunterricht daran.

Vereinfacht kann man sich das so vorstellen:

laptop      -> DOC-001, DOC-007, DOC-013
security    -> DOC-004, DOC-007, DOC-010, ...
procurement -> DOC-006, DOC-011

Das Verfahren ist extrem nützlich. Unser Experiment zeigt aber schnell, wo seine Grenzen liegen.

Nehmen wir diese Query:

QUERY: company laptop policy
EXPECTED: DOC-001

BM25:
#1 DOC-016
#2 DOC-007
#3 DOC-001*

Die tatsächlich gesuchte Laptop-Richtlinie landet lediglich auf Platz 3.

Ein weiteres Beispiel:

QUERY: lost notebook
EXPECTED: DOC-012

BM25:
#1 DOC-009
#2 DOC-016
#3 DOC-012*

Und noch eines:

QUERY: approval for expensive computer purchase
EXPECTED: DOC-006

BM25:
#1 DOC-009
#2 DOC-006*
#3 DOC-003

BM25 macht hier nichts falsch.

Der Algorithmus tut genau das, wofür lexikalisches Retrieval entwickelt wurde.

Das Problem besteht darin, dass die Übereinstimmung von Wörtern nicht immer mit der vom Benutzer gemeinten Bedeutung übereinstimmt.

Vector Search hinzufügen

Im nächsten Schritt kommen Embeddings hinzu.

Jedes Dokument wird mit Sentence Transformers in einen Vektor umgewandelt:

model = SentenceTransformer("all-MiniLM-L6-v2")
embeddings = model.encode(document_texts)

Der Elasticsearch-Index erhält zusätzlich ein dense_vector-Feld mit 384 Dimensionen:

"embedding": {
    "type": "dense_vector",
    "dims": 384,
    "index": True,
    "similarity": "cosine",
}

Der ursprüngliche Text bleibt weiterhin in Elasticsearch gespeichert.

Das ist ein interessanter Architekturpunkt: Elasticsearch kann sowohl die durchsuchbaren Texte als auch deren Vektorrepräsentationen speichern.

Nur weil ein RAG-System mit Embeddings arbeitet, braucht man also nicht zwangsläufig eine zusätzliche separate Vector Database.

Für die Suche wird nun auch die Benutzerfrage in einen Vektor umgewandelt. Anschließend sucht Elasticsearch per k-Nearest-Neighbor-Suche nach ähnlichen Dokumentvektoren.

Vector Search löst die semantischen Fälle

Die Ergebnisse ändern sich unmittelbar.

Bei den drei Beispielen, bei denen BM25 das erwartete Dokument nicht auf Platz 1 gesetzt hat, sieht es nun so aus:

company laptop policy
BM25:   #3 DOC-001*
VECTOR: #1 DOC-001*

lost notebook
BM25:   #3 DOC-012*
VECTOR: #1 DOC-012*

approval for expensive computer purchase
BM25:   #2 DOC-006*
VECTOR: #1 DOC-006*

Genau deshalb ist semantisches Retrieval für RAG so interessant.

Die Formulierung des Benutzers muss nicht exakt mit den Begriffen im Quelldokument übereinstimmen.

Ein Benutzer kann beispielsweise nach

approval for expensive computer purchase

suchen, während im Dokument von

Hardware purchases above €2,000 require approval

die Rede ist.

Semantisch liegen diese Aussagen nah beieinander, obwohl sie unterschiedliche Wörter verwenden.

Bis hierhin könnte man also zu dem Schluss kommen:

Vector Search gewinnt.

Dann habe ich nach exakten Identifikatoren gesucht.

Wo Vector Search danebenlag

Die interessanteste Query des gesamten Experiments war erstaunlich kurz:

SEC-443

Es gibt genau ein korrektes Dokument:

DOC-013
Security incident SEC-443 concerns a stolen company laptop.

BM25 hat damit kein Problem:

BM25:
#1 DOC-013*
#2 DOC-010
#3 DOC-004

Vector Search dagegen schon:

VECTOR:
#1 DOC-014
#2 DOC-013*
#3 DOC-010

Auf Platz 1 steht der falsche Sicherheitsvorfall.

DOC-014 beschreibt SEC-444 und nicht SEC-443.

Ein Blick auf die Vector Scores macht das Problem deutlicher:

DOC-014 SEC-444   0.7615
DOC-013 SEC-443   0.7353
DOC-010 SEC-442   0.7287

Alle drei Dokumente beschreiben Sicherheitsvorfälle und befinden sich deshalb semantisch in einer ähnlichen Umgebung.

Für uns Menschen ist der Unterschied zwischen SEC-443 und SEC-444 absolut entscheidend.

Für das verwendete Embedding-Modell war der Identifier dagegen kein ausreichend starkes Signal, um das korrekte Dokument zuverlässig auf Platz 1 zu setzen.

Das bedeutet ausdrücklich nicht, dass Vector Search grundsätzlich nicht mit Identifikatoren umgehen kann.

Eine andere Query funktionierte problemlos:

QUERY: SEC-444

VECTOR:
#1 DOC-014*
#2 DOC-010
#3 DOC-013

Auch POL-102 wurde korrekt gefunden.

Die Erkenntnis ist daher etwas differenzierter:

Semantische Ähnlichkeit garantiert keinen exakten Identifier-Match.

Das kann in realen RAG-Anwendungen ausgesprochen wichtig sein.

Dort gibt es beispielsweise:

  • Ticketnummern
  • Produkt-IDs
  • Vertragsnummern
  • Fehlercodes
  • API-Bezeichnungen
  • Versionsnummern
  • Paragraphen oder andere Referenzen

Wenn SEC-444 semantisch sehr ähnlich zu SEC-443 ist, hilft uns das wenig, wenn der Benutzer ausdrücklich nach SEC-443 gefragt hat.

Hybrid Search

An diesem Punkt ergänzen sich die Stärken der beiden Retrieval-Ansätze ziemlich gut.

BM25 ist stark, wenn exakte lexikalische Informationen wichtig sind.

Vector Search ist stark, wenn die Sprache des Benutzers von der Formulierung im Dokument abweicht.

Warum also nicht beide Ergebnisse verwenden?

Genau hier kommt Hybrid Search ins Spiel.

Elasticsearch unterstützt dafür unter anderem Reciprocal Rank Fusion, kurz RRF.

Vereinfacht sieht der Ablauf so aus: Reciprocal Rank Fusion

Hybrid Retrieval kombiniert die lexikalische BM25-Suche mit semantischer Vector Search und führt beide Rankings mit Reciprocal Rank Fusion zusammen.

RRF ist hier besonders praktisch, weil BM25-Scores und Vector-Similarity-Scores nicht unmittelbar miteinander vergleichbar sind.

Statt zu versuchen, völlig unterschiedliche Score-Skalen direkt gegeneinander aufzurechnen, arbeitet RRF mit den Rangpositionen der einzelnen Retriever.

Vereinfacht steckt dahinter die Idee:

RRF(document) = sum(1 / (k + rank))

Ein Dokument, das bei mehreren Retrieval-Verfahren weit oben erscheint, erhält dadurch ein stärkeres kombiniertes Ranking.

Und jetzt wird SEC-443 besonders interessant:

QUERY: SEC-443
EXPECTED: DOC-013

BM25:   #1 DOC-013* | #2 DOC-010 | #3 DOC-004
VECTOR: #1 DOC-014  | #2 DOC-013* | #3 DOC-010
HYBRID: #1 DOC-013* | #2 DOC-014 | #3 DOC-010

Diese vier Zeilen fassen das Experiment eigentlich ziemlich gut zusammen.

Vector Search bevorzugt den falschen, aber semantisch sehr ähnlichen Sicherheitsvorfall.

BM25 liefert dagegen das starke lexikalische Signal für den exakten Identifier.

RRF kombiniert beide Rankings und bringt das korrekte Dokument wieder auf Platz 1.

Eine kleine Überraschung beim Elasticsearch-Lizenzmodell

Beim Aufbau des Experiments gab es noch eine praktische Überraschung.

Mein Elasticsearch-Container lief zunächst mit der Basic-Lizenz.

BM25 funktionierte.

Dense Vectors funktionierten.

kNN Vector Search funktionierte.

Der native RRF-Retriever dagegen nicht.

Elasticsearch antwortete mit:

security_exception:
current license is non-compliant for
[Reciprocal Rank Fusion (RRF)]

Für das Experiment habe ich den lokalen Elasticsearch-Container deshalb auf eine Trial-Lizenz umgestellt und das Datenvolume neu erzeugt.

Damit ließ sich der native RRF-Retriever verwenden.

Das ist ein Detail, das man bei der Planung einer Elasticsearch-basierten Hybrid-Retrieval-Architektur im Hinterkopf behalten sollte: Die technische Funktionalität ist zwar grundsätzlich in Elasticsearch vorhanden, die konkret verfügbaren Retrieval-Funktionen hängen aber auch von der verwendeten Lizenz ab.

Eine Alternative wäre, BM25 und Vector Search getrennt auszuführen und die Rank Fusion selbst in der Anwendung zu implementieren.

Für dieses Experiment wollte ich jedoch bewusst die native RRF-Implementierung von Elasticsearch verwenden.

Das Ergebnis

Für die zehn vorher festgelegten Queries wurde geprüft, wie häufig das erwartete Dokument tatsächlich auf Platz 1 landet.

Table

Diese Zahlen sind kein Benchmark.

16 handgebaute Dokumente und zehn Queries erlauben selbstverständlich nicht die Aussage, Vector Search sei grundsätzlich zu 90 Prozent korrekt oder Hybrid Search sei immer überlegen.

Das wäre eine massive Überinterpretation dieses kleinen Experiments.

Interessant sind vielmehr die unterschiedlichen Fehlermuster.

BM25 scheiterte mehrfach dort, wo die lexikalische Übereinstimmung nicht der eigentlich gemeinten Bedeutung entsprach.

Vector Search löste diese Fälle, lieferte dafür bei einem exakten Incident-Identifier das falsche Dokument auf Platz 1.

Hybrid Search kombinierte beide Signale und setzte in unserem kleinen Experiment bei allen zehn Queries das erwartete Dokument auf Platz 1.

Interessant ist dabei noch etwas anderes:

Bei neun der zehn Vector-Search-Ergebnisse konnte Hybrid Search den ersten Platz überhaupt nicht verbessern.

Es gab nichts zu verbessern.

Der Nutzen von Hybrid Search wurde genau in dem Moment sichtbar, in dem sich die beiden Retrieval-Signale widersprachen.

Was bedeutet das für RAG?

Beim Entwurf eines RAG-Systems würde ich deshalb nicht mit dieser Frage beginnen:

Welche Vector Database sollen wir verwenden?

Sondern mit:

Welche Arten von Dokumenten und Suchanfragen muss unser Retrieval-System eigentlich beherrschen?

Wenn Benutzer nach Konzepten in natürlicher Sprache suchen und dabei andere Formulierungen als die Quelldokumente verwenden, kann semantisches Retrieval enorm wertvoll sein.

Enthält der Dokumentbestand dagegen exakte Identifikatoren, technische Begriffe, Fehlercodes, Produktnamen oder andere starke lexikalische Signale, bleibt klassische Volltextsuche ausgesprochen wertvoll.

Und wenn ein System beides benötigt, wird Hybrid Retrieval interessant.

Vor allem sollte man die Qualität des Retrievals unabhängig vom LLM testen.

Ein RAG-System kann ein hervorragendes Sprachmodell verwenden und trotzdem schlechte Antworten erzeugen, wenn das richtige Dokument nie beim Modell ankommt.

Retrieval ist nicht einfach nur die technische Leitung vor dem LLM.

Es ist ein wesentlicher Bestandteil der Qualität des gesamten Systems.

Und manchmal besteht die beste Retrieval-Strategie eben nicht darin, die alte Suchtechnologie durch die neue zu ersetzen.

Sondern beide das tun zu lassen, was sie besonders gut können.

Bernd
Bernd Fischer
Django & Python Trainer

Ich helfe Entwicklern, wartbare Python- und Django-Projekte zu bauen.

Newsletter

Praxisnahe Inhalte zu Python, Django und KI. Kurz und ohne Spam.

Jetzt anmelden
Kostenloses Django-Ebook

Django für Profis: Architektur und Best Practices

Jetzt downloaden

Online- und Präsenzkurse zum Thema

Finden Sie interessante und zum Thema passende Kurse

Django-Entwicklung mit KI

Künstliche Intelligenz verändert die Softwareentwicklung nachhaltig. In diesem Seminar lernen Sie, wie Sie Django-Anwendungen mit ChatGPT, GitHub Copilot und anderen KI-Assistenten effizient entwickeln. Anhand eines durchgängigen Praxisprojekts erstellen Sie eine vollständige Webanwendung und setzen KI gezielt für Spezifikation, Architektur, Codegenerierung, Tests und Fehlersuche ein. Sie lernen, gute Prompts zu formulieren, KI-generierten Code kritisch zu bewerten und moderne Django-Projekte sicher und wartbar umzusetzen.

5 Tage Vollzeit Online

  • Nächster Termin: 7. September 2026
  • Preis p.P.: 1900,00 EUR (inkl. MwSt. 2261,0 EUR)

KI im Unternehmen: Von ChatGPT zu RAG, Workflows und KI-Agenten

Drei Tage moderne KI für Unternehmen: LLMs, RAG, Tool Calling, Workflows und KI-Agenten verständlich und praxisnah erklärt.

3 Tage Online

  • Nächster Termin: 7. September 2026
  • Preis p.P.: 1590,00 EUR (inkl. MwSt. 1892,1 EUR)

KI-Workflows und Automatisierung im Unternehmen

Viele Geschäftsprozesse bestehen aus wiederkehrenden Schritten, Entscheidungen und dem Austausch von Daten zwischen verschiedenen Systemen. Moderne KI kann solche Abläufe erweitern, strukturieren und teilweise automatisieren.

3 Tage Vollzeit Online

  • Nächster Termin: 14. September 2026
  • Preis p.P.: 1590,00 EUR (inkl. MwSt. 1892,1 EUR)

Prompting, Fine-Tuning, RAG, Agenten

Nutzen Sie das Potenzial von KI gezielt für Ihr Unternehmen. In dieser 3-tägigen Python-Schulung lernen Sie, wie Sie Large Language Models praxisnah einsetzen, von Prompting über Fine-Tuning bis zu RAG und Agenten-Workflows. Klare Codebeispiele und viele Übungen sorgen dafür, dass Sie das Gelernte direkt anwenden und fundierte Entscheidungen für den KI-Einsatz treffen können.

3 Tage Vollzeit Online

  • Nächster Termin: 14. September 2026
  • Preis p.P.: 1400,00 EUR (inkl. MwSt. 1666,0 EUR)

Unsicher, welcher Kurs für Sie passt?

Gerne unterstütze ich Sie bei der Auswahl oder stelle eine individuell passende Schulung für Ihre Anforderungen zusammen.

Beratung anfordern