Startseite / Artikel

Semantische Suche in PostgreSQL mit pgvector und Node.js – kein LLM erforderlich

Semantische Suche in PostgreSQL mit pgvector und Node.js – ohne LLM: MiniLM-Embeddings, Chunks, ein IVFFlat-Index, Abstandsberechnungsfunktionen und wie man die Scores liest.

Verlag: REACTAPP.TOP8 Min. Lesezeit1884 Wörter

Quellen: Talk to Your Database Like a Human — No LLM Required: Semantic Search with Node.js + PostgreSQL

Eine Datenbank kann Fragen, die in gewöhnlichem Englisch gestellt werden, beantworten, ohne dass ein Sprachmodell im Prozess involviert ist. Was das möglich macht, ist die Vektorsuche. Mit Node.js, PostgreSQL und der pgvector-Erweiterung kann man ein System erstellen, das nach Absicht statt nach Schlüsselwörtern abgleicht, wobei das einzige verwendete Modell ein kleines Embedding-Modell ist, das Text in Zahlen umwandelt.

Relationale Datenbanken waren schon immer hervorragend darin, Daten zu speichern und abzurufen, vorausgesetzt, man stellt die genau richtige Frage. Genaue Übereinstimmungen, Filter und strukturierte Abfragen sind mächtig, aber eingeschränkt. Vektordatenbanken scheinen ein anderes Problem zu lösen: das Suchen in unstrukturiertem Inhalt nach seinem Sinn und nicht nach den enthaltenen Wörtern.

Vier Begriffe, die man klar verstehen sollte

Token. Der kleinste Textabschnitt, mit dem ein Modell arbeitet. Tokens sind nicht immer ganze Wörter. Ein Token kann ein vollständiges Wort wie „hello“ sein, ein Fragment (so könnte „unbelievable“ zu „un“, „believ“ und „able“ werden), ein einzelnes Zeichen wie „!“ oder ein Teil von Satzzeichen oder Leerzeichen. Ein Satz wie „ChatGPT ist großartig“ könnte in „Chat“, „G“, „PT“, „ist“ und „großartig“ aufgeteilt werden.

Chunk. Ein kleiner, eigenständiger Teil eines größeren Dokuments, in der Regel ein paar Sätze oder ein Absatz. Die Einbettung eines ganzen Dokuments auf einmal funktioniert schlecht, daher wird es zunächst in Chunks aufgeteilt. Das Chunking beschleunigt die Verarbeitung, verbessert die Suchgenauigkeit und sorgt dafür, dass die Ergebnisse zur Anfrage passen.

Embedding. Eine numerische Vertretung für einen Text-, Bild- oder Audiodatenpunkt, die dessen Bedeutung einfängt. Ein maschinelles Lernmodell, wie zum Beispiel MiniLM, erzeugt sie. Man kann sich ein Embedding als die Idee hinter den Daten vorstellen.

Vector. Die Art und Weise, wie ein Embedding tatsächlich gespeichert wird: ein Array von Zahlen.

[0.2, -0.5, 0.9, ...]

Das ist die in Erinnerung und in PostgreSQL gespeicherte Struktur, sobald eine Erweiterung wie pgvector installiert ist.

Zusammengefasst sieht die Idee so aus: Wörter, Sätze oder Bilder werden zu Embeddings. Objekte mit ähnlichen Bedeutungen weisen Vektoren auf, die nah beieinander liegen, während unverwandte Objekte weiter voneinander entfernt sind. Ein String wie „Hello world“ wird zu einer langen Liste von Fließkommazahlen:

// "Hello world" turns into this embedding:
const embedding = [0.01, -0.42, 0.15, ..., 0.99]; // ← this is a vector

Und diese Liste wird anschließend neben den ursprünglichen Text gespeichert:

INSERT INTO documents (content, embedding)
VALUES ('Hello world', embedding);

Warum eine relationale Datenbank nicht ausreicht

Ein traditionelles RDBMS arbeitet mit Tabellen, Zeilen und Spalten. Es bewältigt Anfragen wie „alle Tickets mit Status OPEN“ oder „Benutzer, die nach 2024 erstellt wurden“, mühelos. Moderne Anwendungen müssen jedoch auch mit Dokumenten, Konversationen, Bildern und Audio umgehen. Eine exakte Abgleichung hilft dabei kaum.

Eine Vektor-Datenbank speichert Embeddings zusammen mit den Daten und findet Elemente anhand von Ähnlichkeit und Kontext. Statt nach Dokumenten zu suchen, die das Wort „Fehler“ enthalten, kann man nach Dokumenten zu Authentifizierungsproblemen fragen – und diese erhalten, selbst wenn „Fehler“ nie vorkommt. Der Vergleich erfolgt dabei über eine mathematische Distanz zwischen Vektoren, nicht über einen Textabgleich.

Der übliche Ablauf sieht so aus:

  1. Roher Inhalt wird eingegeben: Dokumente, Tickets oder alles andere.
  2. Ein Embedding-Modell wandelt es in Vektoren um.
  3. Die Vektoren werden beispielsweise mit pgvector in PostgreSQL gespeichert.
  4. Ein annähernder Näherungs-Nachbarn-Index (ANN-Index) sorgt für schnelle Abfragen.
  5. Auch die Abfrage des Benutzers wird in einen Vektor umgewandelt.
  6. Die Datenbank gibt die Vektoren zurück, die am nächsten liegen, also die am ähnlichsten sind.

Was dies ermöglicht:

  • Semantische Suche, die von der Bedeutung einer Abfrage und nicht nur von ihren genauen Worten gesteuert wird.
  • Langfristiges Gedächtnis für ein LLM, indem vergangene Interaktionen, Dokumente oder Fakten gespeichert werden, die das Modell auch dann abrufen kann, wenn sie nicht in seinen Trainingsdaten enthalten waren.
  • Empfehlungen, indem Elemente oder Verhaltensweisen gefunden werden, die im Embedding-Raum ähnlich sind.
  • Ähnlichkeitssuche in Texten, Bildern, Audiodateien oder Videos.

PostgreSQL als Vektorlager

Man muss dafür keine neue Datenbank einsetzen. Mit pgvector kann PostgreSQL Embeddings direkt speichern, Ähnlichkeitsabfragen ausführen und Indizes wie IVFFlat nutzen, um schnell zu bleiben. Die bereits vorhandene Datenbank erlangt einfach eine neue Fähigkeit – von der Speicherung von Daten bis hin zur Möglichkeit, deren Bedeutung zu vergleichen. Die Suche konzentriert sich nicht mehr auf das Abgleichen von Wörtern, sondern auf das Abgleichen von Bedeutungen.

Schritt für Schritt einrichten

1. PostgreSQL installieren und pgvector aktivieren. Installieren Sie PostgreSQL von der offiziellen Download-Seite, verbinden Sie sich und aktivieren Sie die Erweiterung:

CREATE EXTENSION IF NOT EXISTS vector;

2. Erstellen Sie die Dokumententabelle. Sie enthält den Rohtext sowie seine Embedding-Daten. Die 384 in der Definition gibt die Ausgabegröße des all-MiniLM-L6-v2-Modells an.

-- Note: 384 is the embedding size output by all-MiniLM-L6-v2
CREATE TABLE documents (
  id SERIAL PRIMARY KEY,
  content TEXT,
  embedding VECTOR(384)
);

3. Fügen Sie einen Vektorindex hinzu. Um die Ähnlichkeitssuche effizient zu halten, verwenden Sie einen annähernden nächsten-Nachbarn-Index:

CREATE INDEX documents_embedding_idx
ON documents
USING ivfflat (embedding vector_l2_ops)
WITH (lists = 100);

Dies wählt IVFFlat für schnelle, annähernde Abfragen aus, misst mit der L2-(euklidischen) Distanz und teilt die Vektoren in 100 Clustern auf.

4. Passen Sie den Abfragesoperator zum Index an. Der Operator in Ihrer Abfrage muss zur Operatorklasse passen, mit der Sie den Index erstellt haben. pgvector bietet mehrere Operatoren, von denen jeder mit seiner eigenen Klasse verbunden ist. Im Beispiel wird mit <#> abgefragt und vector_l2_ops konfiguriert. Beachten Sie, dass in der Dokumentation von pgvector die L2-Distanz normalerweise mit <-> dargestellt wird und <#> das negative Skalarprodukt ist – überprüfen Sie daher, ob Ihre Abfrage und der Index übereinstimmen.

5. Führen Sie das Projekt aus. Ein vollständiges, funktionierendes Beispiel befindet sich in einem GitHub-Repositorium namens vectorgarquer/vectorized-database-embeddings. Klonen oder Forken Sie es und installieren Sie anschließend die Abhängigkeiten:

npm install

Kopieren Sie .env.example in eine .env-Datei im Projektverzeichnis und füllen Sie die Details Ihrer PostgreSQL-Verbindung ein. Starten Sie das Projekt anschließend:

npm start

6. Beobachten Sie die Suche. Sobald das Programm läuft, stellt es eine Verbindung her, fügt Embeddings ein und führt semantische Suchen ohne weitere Eingaben durch. Von dort aus können Sie Ihr eigenes Datenmaterial sowie Abfragen eingeben. Die Beispielsuche nach „Was bedeutet generative KI?“ liefert die in der Datenbank gefundenen Ergebnisse wie folgt:

Search Results:

[1] Distance: -0.7562
n be represented in another modality such as text.
2.2  A Model-, System-, and Application-Level View
of Generative AI
2.2.1 Model-Level View
A  generative  AI  model  is  a  type  of  machine  learning
architecture  that  uses  AI  algorithms  to  create  novel  data
instances,  drawing  upon  the  patterns  and  relationships
observed in the training data. A generative AI model is of
critically central  yet incomplete  nature,  as it requires fur-
ther  fine-tuning  to  specific   tasks   thro


[2] Distance: -0.7562
n be represented in another modality such as text.
2.2  A Model-, System-, and Application-Level View
of Generative AI
2.2.1 Model-Level View
A  generative  AI  model  is  a  type  of  machine  learning
architecture  that  uses  AI  algorithms  to  create  novel  data
instances,  drawing  upon  the  patterns  and  relationships
observed in the training data. A generative AI model is of
critically central  yet incomplete  nature,  as it requires fur-
ther  fine-tuning  to  specific   tasks   thro


[3] Distance: -0.7562
n be represented in another modality such as text.
2.2  A Model-, System-, and Application-Level View
of Generative AI
2.2.1 Model-Level View
A  generative  AI  model  is  a  type  of  machine  learning
architecture  that  uses  AI  algorithms  to  create  novel  data
instances,  drawing  upon  the  patterns  and  relationships
observed in the training data. A generative AI model is of
critically central  yet incomplete  nature,  as it requires fur-
ther  fine-tuning  to  specific   tasks   thro


[4] Distance: -0.7562
n be represented in another modality such as text.
2.2  A Model-, System-, and Application-Level View
of Generative AI
2.2.1 Model-Level View
A  generative  AI  model  is  a  type  of  machine  learning
architecture  that  uses  AI  algorithms  to  create  novel  data
instances,  drawing  upon  the  patterns  and  relationships
observed in the training data. A generative AI model is of
critically central  yet incomplete  nature,  as it requires fur-
ther  fine-tuning  to  specific   tasks   thro


[5] Distance: -0.7094

assistants,  personalized  education  and  service,  and  digital
art. As such, generative AI has substantial implications for
BISE  practitioners  and  scholars  as  an  interdisciplinary
research community. In our Catchword article, we offered
a conceptualization of the principles of generative AI along
a model-, system-, and application-level view as well as a
social-technical  view  and  described  limitations  of  current
generative   AI.   Ultimately,   we   provided   an   impactful
rese

Lesen der Ausgabe

Nach einem Lauf erhalten Sie eine Liste in dieser Form:

Search Results:

[1] Distance: -0.7562
...
[5] Distance: -0.7094
...

Die Distanz gibt an, wie nah ein gespeicherter Chunk dem Abfragedatenvektor ist. Sowohl der Chunk als auch die Abfrage werden in Vektoren umgewandelt, und PostgreSQL mit pgvector misst, wie weit sie voneinander entfernt sind. Die Regel ist einfach: Je kleiner die Distanz, desto ähnlicher ist der Inhalt.

Die Werte sind negativ, beispielsweise:

-0.7562

Das liegt daran, dass der Operator <#> einen negierten Wert zurückgibt, sodass eine normale Sortierung die am nächsten liegenden Zeilen zuerst anordnet. In der Praxis bedeutet eine noch negativere Zahl eine näher liegende, relevantere Übereinstimmung, während eine Zahl, die dem Nullwert näher ist, eine schwächere Übereinstimmung darstellt.

Wenn man sich die Rangliste ansieht, weisen die Ergebnisse 1 bis 4 denselben Wert von -0,7562 auf, wodurch sie für die Abfrage gleich relevant sind. Ergebnis 5 hat einen Wert von -0,7094, was ebenfalls relevant ist, aber etwas weniger ähnlich.

Man wird möglicherweise auch mehrere Ergebnisse mit nahezu identischem Text feststellen. Das ist zu erwarten. Das Quelldokument wurde in Blöcke aufgeteilt, benachbarte Blöcke überschneiden sich oder wiederholen ähnlichen Inhalt, und jeder Block hat seine eigene Embedding-Darstellung.

Was das Ergebnis zeigt

Auch ohne LLM zum Zeitpunkt der Abfrage verstand das System den Sinn und nicht nur die Schlüsselwörter, holte Texte ab, die zum Kontext passten, und ordnete sie nach vektorieller Ähnlichkeit. Die zurückgegebenen Abschnitte konzentrierten sich auf generative KI-Modelle, eine modellbasierte Sichtweise sowie Machine-Learning-Architekturen, sodass die Suche eindeutig auf Konzeptebene statt auf exakten Wörtern funktionierte.

Das Ergebnis ist eine semantische Suchmaschine, die in PostgreSQL integriert ist. Bei Abfragen ist kein LLM erforderlich, es gibt keine separate Vektordatenbank, und Embeddings zusammen mit pgvector übernehmen die gesamte Arbeit.

Verwandte Artikel

  • Was wirklich ein neuronales Netz antreibt: AI-Kompilatoren hinter Python — Verfolgen Sie ein Modell von einer Python-Expression über Rechungsgraphen, Operator-Fusion, IRs im MLIR-Stil bis hin zur Umsetzung in CPU-, GPU- und Accelerator-Code.
  • Ihr semantisches Modell ist die API: Zertifizierte Metriken für KI-Agenten bereitstellen — Warum KI-Agenten eigene Definitionen von Umsatz und Lagerbeständen erfinden und wie ein reguliertes semantisches Modell mit Details, Eigentümern und Ablehnungen ihnen einen einheitlichen Vertrag bietet.
  • Vectorloses RAG: Wie PageIndex Dokumente ohne Embeddings liest — Die Vektorsuche teilt lange Dokumente in Blöcke auf und verliert dabei den Kontext. Erfahren Sie, wie ein auf Schlussfolgerungen basierender Baumindex Antworten in komplexen Berichten mithilfe von Code findet.
  • Fortgeschrittenes RAG mit Milvus: Hybride Suche, HyDE, Abfragen umschreiben und Neuranking — Bauen Sie schrittweise einen Milvus-RAG-Pipeline auf: dichte und BM25-Vektoren, RRF-hybride Suche, Metadatenfilter, Abfragen umschreiben, HyDE, Dekomposition sowie Neuranking mit Cross-Encoder.