Warum wir Loon entwickelt haben: eine Speicher-Engine für KI-Daten, die sich ständig ändern.

  • Engineering
June 05, 2026
Ted Xu

Dieser Blogbeitrag wurde ursprünglich auf zilliz.com veröffentlicht und mit Genehmigung erneut veröffentlicht.

Das Wichtigste auf einen Blick

Da es sich hierbei um einen langen, tiefgehenden technischen Einblick handelt, finden Sie hier die wichtigsten Punkte, bevor wir ins Detail gehen.

  • KI-Datensätze sind keine statischen Tabellen. Die gleichen Zeilen ändern sich ständig, da Teams Embedding-Modelle ersetzen, spärliche Vektoren hinzufügen, Bildunterschriften überarbeiten, Labels nachträglich ergänzen, Indizes neu erstellen und Offline-Analysen durchführen.
  • Herkömmliche Speicherlayouts weisen drei Schwachstellen auf: Lange Vektorspalten machen das Nachfüllen aufwendig, ein einziges Dateiformat kann weder Scans noch Punktlesungen gut unterstützen, und die Speicherung in privaten Datenbanken zwingt externe Pipelines dazu, zusätzliche Kopien der Originaldaten zu erstellen.
  • Loon ist die neue Speicher-Engine für Milvus und Zilliz Vector Lakebase. Sie basiert auf hybriden Dateiformaten, der Ausrichtung von Zeilen-IDs und einem Manifest, das den versionierten Zustand des Datensatzes definiert.
  • Das Ziel ist es, mit einem einzigen Vektordatensatz Online-Suche, Offline-Analyse, Backfills, Komprimierung und externe Berechnungen zu ermöglichen, ohne Daten ständig kopieren, neu schreiben oder erneut importieren zu müssen.

Einleitung

Eine Zeit lang gab es ein Argument gegen Vektordatenbanken, das vernünftig klang.

Herkömmliche Datenbanken speichern bereits Ganzzahlen, Zeichenfolgen, JSON, Blobs und Indizes. Warum also nicht einen Typ_vector_hinzufügen , daneben einen ANN-Index erstellen und es dabei belassen?

Für die semantische Suche in der Anfangsphase funktioniert das gut genug. Eine Vektorspalte plus ein Index reichen für eine Demo, eine kleine RAG-Anwendung oder eine interne Suchfunktion aus. Das Problem tritt erst später zutage, wenn sich der Datensatz weniger wie eine Tabelle und mehr wie ein KI-Datensystem verhält.

Ein Vektordatensatz in der Produktion verfügt über Zeilen, Primärschlüssel, skalare Felder und abfragbare Spalten. In diesem Sinne ähnelt er einer Datenbanktabelle. Aber er hat auch die Größenordnung und die Workflow-Struktur eines Data Lake. Er kann Hunderte von Millionen Datensätze enthalten. Er wird wiederholt von Spark, Ray, DuckDB, Trainingspipelines, Auswertungsjobs und Datenqualitätssystemen gelesen und neu geschrieben.

Er stützt sich zudem auf Objektspeicher. Bei den Quellobjekten handelt es sich häufig um Videos, Bilder, PDFs, Audiodateien oder Webdokumente, die in S3, GCS, OSS oder einem anderen Objektspeicher verbleiben. Die Datenbank speichert Referenzen, Metadaten, abgeleitete Merkmale und Indizes. Dann fügt sie Elemente hinzu, für deren Verwaltung herkömmliche Speichermodelle nicht ausgelegt waren, und zwar als Objekte erster Klasse: dichte Einbettungen, spärliche Vektoren, Bildunterschriften, Vektorindizes, Textindizes, Löschprotokolle, Statistiken, Modellversionen, Parser-Versionen, Referenzen auf externe Blobs sowie die Versionsbeziehungen zwischen all diesen Elementen.

An dieser Stelle stößt der Ansatz „einfach eine Vektorspalte hinzufügen“ an seine Grenzen. Die Frage ist nicht, ob eine Datenbank Vektor-Bytes speichern kann. Viele Systeme können das. Die schwierigere Frage ist , ob das Speichermodell damit umgehen kann, wie sich Vektordaten ändern, wie sie abgefragt werden und wie sie über den gesamten KI-Datenstack hinweg gemeinsam genutzt werden.

Aus diesem Grund haben wir Loon entwickelt, die neue Speicher-Engine für Milvus und Zilliz Vector Lakebase (die nächste Evolutionsstufe von Zilliz Cloud).

Loon basiert auf drei Grundgedanken:

  1. Verwendung unterschiedlicher physischer Formate für verschiedene Spaltenarten.
  2. Diese Spalten über einen gemeinsamen Zeilen-ID-Raum aufeinander abstimmen.
  3. Verwendung eines Manifests zur Definition des versionierten Zustands des Datensatzes.

Um zu verstehen, warum diese Aspekte wichtig sind, beginnen wir mit einem gängigen multimodalen Workflow.

Ein Vektordatensatz ist nie wirklich fertig.

Stellen Sie sich ein KI-Team vor, das einen Videodatensatz für das multimodale Training erstellt.

Ein langes Video wird in einen Objektspeicher hochgeladen. Eine Pipeline zerlegt es anhand von Szenenwechseln, Schnittpunkten oder Zeitfenstern in Clips. Clips, die zu lang oder zu kurz, unscharf, doppelt vorhanden oder von geringer Qualität sind, werden herausgefiltert. Die verbleibenden Clips werden von einem ästhetischen Modell bewertet, von einem anderen Modell mit Untertiteln versehen, von einem Bild-Sprache-Modell eingebettet und in einer Vektordatenbank für die Suche, Deduplizierung und Filterung von Trainingsdaten gespeichert.

Auf einer übergeordneten Ebene sieht der Arbeitsablauf einfach aus:

video
→ clips
→ metadata
→ aesthetic_score
→ caption
→ embedding
→ search / dedup / training data filtering

Doch der Datensatz liegt nicht von vornherein in fertiger Form vor.

  • In der ersten Woche enthält die Tabelle möglicherweise nur clip_id, video_id, start_offset und duration.
  • In der zweiten Woche fügt das Team „ aesthetic_score “ hinzu.
  • In der dritten Woche wird ein Untertitelungsmodell ausgeführt, und jeder Clip erhält eine „ caption “.
  • In der vierten Woche geht das erste Einbettungsmodell online, und jeder Clip erhält eine 768-dimensionale CLIP-Einbettung.
  • Einen Monat später wechselt das Team die Modelle und füllt die „ embedding_v2 “ nachträglich auf – nun mit 1024 Dimensionen.
  • Zwei Monate später wird die hybride Suche zur Voraussetzung, sodass das Team eine Spalte mit spärlichen Vektoren hinzufügt.
  • Drei Monate später werden die Bildunterschriften einer manuellen Überprüfung unterzogen und müssen direkt korrigiert werden.

Der Datensatz wurde nie vollständig fertiggestellt. Es kamen immer wieder neue Interpretationen derselben zugrunde liegenden Zeilen hinzu.

Das ist einer der wesentlichen Unterschiede zwischen Vektordaten und herkömmlichen Geschäftsdaten. Dieselbe Zeile wird immer wieder neu verarbeitet. Und der Umfang verwandelt dies von einer Unannehmlichkeit in ein Speicherproblem: Multimodale Datensätze umfassen oft nicht Millionen von Datensätzen, sondern Hunderte von Millionen oder Milliarden. LAION-5B ist ein nützlicher Anhaltspunkt für die Struktur – Milliarden von Bild-Text-Paaren, jedes mit Metadaten, Bildunterschriften und Einbettungen. Das Schwierige ist also nicht das erste Einfügen. Das Schwierige ist alles, was passiert, nachdem sich der Datensatz weiterentwickelt. Diese Weiterentwicklung bringt drei Probleme zum Vorschein.

Das erste Problem: Lange Spalten machen die Schreibamplifikation kostspielig

Spaltenorientierte Formate wie Parquet eignen sich hervorragend für viele analytische Workloads. Sie funktionieren gut, wenn Schemata relativ stabil sind, Daten häufiger gelesen als überschrieben werden, Scans nur eine Teilmenge der Spalten betreffen und Komprimierung eine Rolle spielt. Das ist die Welt, für die viele analytische Formate optimiert wurden.

Vektorzeilen sind viel breiter als analytische Zeilen

Das TPC-H- lineitem t eine gute Basis. Es verfügt über 16 Spalten: Ganzzahlschlüssel, Dezimalwerte, Datumsangaben, kurze Zeichenfolgen und ein kleines Kommentarfeld. Eine unkomprimierte Zeile ist etwa 150 Byte groß. Nach der Komprimierung kann sie deutlich kleiner sein. Bei einer Zeilengruppe von 64 MB kann ein Speichersystem Hunderttausende von Zeilen in einer Gruppe zusammenfassen.

Vektordatensätze sehen anders aus.

Ein Bild-Text-Datensatz im LAION-Stil kommt dem, was viele KI-Pipelines heute produzieren, viel näher. Jede Zeile enthält nach wie vor gewöhnliche Metadaten: eine URL, eine Bildunterschrift, Breite, Höhe, Qualitätswerte, Labels und so weiter. Sobald jedoch die Einbettung hinzugefügt wird, ändert sich die physische Form der Zeile.

Ein 768-dimensionaler CLIP-Vektor nimmt etwa 1,5 KB in fp16 oder 3 KB in fp32 ein. Diese eine Spalte kann viel größer sein als eine gesamte TPC-H- lineitem -Zeile.

Und 768 Dimensionen sind nach heutigen Maßstäben weder ungewöhnlich noch groß. Eine 1024- oder 2048-dimensionale Einbettung ist in multimodalen Pipelines üblich. OpenAIs „ text-embedding-3-large “ reicht bis zu 3072 Dimensionen, was etwa 12 KB pro Vektor in fp32 entspricht.

Der Vergleich ist eklatant:

Form des DatensatzesUngefähre ZeilengrößeWas die Zeile dominiert
TPC-H-Lineitem~150 Byte unkomprimiertskalare Felder und kurze Zeichenfolgen
Zeile im LAION-Stil mit einem fp16-Vektor der Dimension 768~1,5 KB+Einbettung
Zeile im LAION-Stil mit einem 768-dimensionalen fp32-Vektor~3 KB+Einbettung
Zeile mit einem 3072-dimensionalen fp32-Vektor~12 KB+ allein für den VektorEinbettung

In vielen KI-Datensätzen ist die Vektorspalte nicht nur ein weiteres Feld. Physisch gesehen macht sie den größten Teil der Zeile aus. Das verändert die Kosten der Schemaentwicklung.

Das Hinzufügen einer Vektorspalte kann Hunderte von Gigabyte bedeuten

Angenommen, ein Datensatz enthält 100 Millionen Videoclips. Das Hinzufügen einer neuen 1024-dimensionalen fp32-Einbettungsspalte bedeutet das Schreiben von etwa 400 GB Rohvektordaten. Darin sind Statistiken, Indizes, Metadaten-Aktualisierungen, Overhead für den Objektspeicher, Validierung oder die Integration in den Serving-Pfad noch nicht enthalten.

Wenn das Team jeden Monat ein oder zwei vektorähnliche Spalten hinzufügt, wie z. B. „ embedding_v2 “, „ sparse_vector “ oder „Rerank Features“, wird die Schemaentwicklung zu einer wiederkehrenden Aufgabe des Data Engineering, die sich in Hunderten von Gigabyte oder Terabyte bemisst.

Kleine logische Aktualisierungen können umfangreiche physische Umschreibungen auslösen

Aktualisierungen sind ebenso wichtig.

In spaltenorientierten Systemen werden alte Daten in der Regel nicht an Ort und Stelle aktualisiert. Ein Löschprotokoll erfasst, was sich geändert hat, und bei der späteren Komprimierung werden aktive Zeilen in neue Dateien umgeschrieben. Dieses Modell ist überschaubar, solange die Zeilen klein sind.

Bei Vektordaten kann eine kleine logische Aktualisierung eine umfangreiche physische Neuschreibung auslösen.

Ein manueller Überprüfungsvorgang korrigiert vielleicht nur ein paar hundert Byte in einer Bildunterschrift. Wenn jedoch die Bildunterschrift, der dichte Vektor, der spärliche Vektor und andere abgeleitete Merkmale denselben physischen Dateilebenszyklus teilen, kann es passieren, dass das System am Ende auch die Vektoren neu schreibt. Die logische Änderung ist gering. Die physische E/A-Last kann enorm sein.

Dies ist das Problem der Schreibverstärkung bei der Vektorspeicherung. Der aufwendige Teil besteht nicht nur darin, dass Vektoren groß sind. Vielmehr werden große abgeleitete Felder und kleine veränderbare Felder oft durch ein Speicherlayout miteinander verknüpft, das sie als eine Einheit behandelt.

Bei KI-Datensätzen ist das Nachfüllen eine routinemäßige Arbeitslast

Bei herkömmlichen Analysetabellen kommt es nur gelegentlich zu einer Schemaentwicklung. Bei KI-Datensätzen ist dies Routine. Bildunterschriftenmodelle werden aktualisiert. Einbettungsmodelle werden ersetzt. Sparse-Vektoren werden nachträglich hinzugefügt. Rerank-Merkmale tauchen auf. Manuelle Beschriftungen werden korrigiert. Governance-Tags werden nachgetragen. Indizes werden neu aufgebaut.

Diese Vorgänge sind keine einfachen Anfügungen. Sie ändern oder erweitern häufig bestehende Zeilen.

Deshalb darf der Vektorspeicher nicht nur auf den Scan-Durchsatz optimiert sein. Er muss auch Nachträge und Teilaktualisierungen kostengünstiger gestalten.

Das zweite Problem: Dieselben Daten müssen sowohl Scans als auch Punktzugriffe unterstützen

Nach dem Schreiben der Daten teilt sich der Lesepfad. Derselbe Vektordatensatz weist typischerweise zwei unterschiedliche Zugriffsmuster auf: analytische Scans und Punktlesungen.

Analytische Workloads erfordern breite, komprimierte Scans

Eine Pipeline kann Filter ausführen wie:

WHERE aesthetic_score > 0.8 AND duration > 5

Oder sie führt Offline-Analysen, vollständige Einbettungsauswertungen, BM25-Statistiken, Bitmap-Erstellung, Datenqualitätsprüfungen, Zählungen und Gruppierungen durch.

Bei diesem Muster werden viele Zeilen, aber nur wenige Spalten gelesen. Es profitiert von sequenzieller E/A, größeren Zeilengruppen, Komprimierung, Spaltenausdünnung, Batch-Dekodierung und vektorisierter Ausführung.

Große Zeilengruppen sind hier von Vorteil. Sie ermöglichen es, mit einer einzigen E/A-Anfrage eine große Menge nützlicher Daten abzurufen, verbessern die Komprimierungseffizienz und versorgen die Ausführungs-Engine mit genügend zusammenhängenden Daten, um den Overhead zu amortisieren. Wenn mehrere Spalten gemeinsam gelesen werden, trägt ihre Organisation im Hinblick auf den Scan-Durchsatz zudem dazu bei, Cache-Fehltreffer während der vektorisierten Ausführung zu reduzieren.

Parquet ist auf diesem Gebiet besonders stark.

ANN-Ergebnisse erfordern gezielte Abfragen auf Zeilenebene

Nachdem die ANN-Suche Kandidaten-Zeilen-IDs zurückgibt, muss das System häufig Felder abrufen wie:

caption
embedding
rerank feature
video_uri
metadata

Bei diesem Muster werden weniger Zeilen gelesen – oft Hunderte oder Tausende –, jedoch ist ein präziser Zugriff über die Zeilen-ID erforderlich. Es geht darum, eine bestimmte Zeile und Spalte zu lokalisieren, nur den benötigten Byte-Bereich abzurufen und zu vermeiden, dass eine ganze Zeilengruppe geladen wird, nur um einige wenige Datensätze abzurufen.

Die Punktabfrage hat fast die entgegengesetzte Präferenz beim Scannen. Sie benötigt eine kleinere Lese-Granularität. Im Idealfall kann die Speicherschicht das relevante Segment oder den Byte-Bereich anhand der Zeilen-ID finden, nur diesen Bereich lesen und nur die für das Ergebnis benötigten Daten dekodieren.

Auch bei der Komprimierung gibt es unterschiedliche Abwägungen. Bei Scans lohnt sich oft eine stärkere Komprimierung, da das System viele Daten liest und dadurch E/A-Vorgänge einspart. Bei der Punktabfrage kann Komprimierung jedoch zum Nachteil werden, wenn das Abrufen einer einzigen Zeile die Dekodierung eines viel größeren komprimierten Blocks erfordert.

Ein Layout kann nicht für beide Pfade optimiert werden

Dies ist der zentrale Konflikt. Skalare Filterung und Analysen erfordern breite, komprimierte, scanfreundliche Layouts. Vektor-Lookups erfordern schmale, präzise, zeilenadressierbare Layouts.

Ein einzelnes Dateiformat kann beides bis zu einem gewissen Grad unterstützen, kann jedoch nicht gleichzeitig für beide optimal sein.

Wenn sich alle Spalten in Parquet befinden, sind skalare Scans problemlos möglich. Die ANN-Abfrage nach dem Abruf wird jedoch schwieriger. Das System benötigt möglicherweise nur einige hundert Vektoren, Beschriftungen oder Metadatensätze, während die Speicherschicht möglicherweise große Zeilengruppen lesen muss, die größtenteils irrelevante Zeilen enthalten.

Auf einer lokalen SSD können Cache und mmap einen Teil dieser Kosten verbergen. Sobald die Daten im Objektspeicher abgelegt sind, werden die Kosten deutlicher sichtbar. Jeder Cache-Fehler kann zu einem Remote-Bereichs-Lesevorgang führen. Wenn Kandidatenzeilen über viele Zeilengruppen verstreut sind, kann eine einzige Abfrage mehrere Lesevorgänge auslösen, von denen jeder mehr Daten abruft, als die Abfrage benötigt. Bei einem ungünstigen Layout kann das Abrufen von 1.000 Kandidatenzeilen leicht zu Dutzenden oder Hunderten von Megabyte unnötiger E/A führen – und in Extremfällen sogar zu weitaus mehr.

Kleinere Zeilengruppen erleichtern zwar die Punktabfrage, beeinträchtigen jedoch Scans. Zu viele kleine Fragmente verringern die Komprimierungseffizienz, erhöhen den Metadaten-Overhead und unterbrechen die langen sequenziellen Lesevorgänge, auf die Analyse-Engines angewiesen sind.

Das Problem besteht also nicht darin, eine einzige „magische“ Zeilengruppengröße zu finden. Das Problem ist vielmehr, dass von ein und demselben Datensatz erwartet wird, sich wie zwei verschiedene Speichersysteme zu verhalten.

Die hybride Suche zwingt beide Pfade in eine einzige Abfrage

Die hybride Suche macht es schwieriger, diesen Konflikt zu ignorieren. Eine einzelne Abfrage wendet möglicherweise zunächst skalare Filter an:

aesthetic_score > 0.8 AND duration > 5

Anschließend führt sie eine ANN-Suche durch.

Anschließend ruft sie Bildunterschrift, Vektor und Metadaten anhand der Zeilen-ID ab.

Für den Nutzer ist dies eine einzige Suchanfrage. Für die Speicherschicht ist es sowohl ein analytischer Scan als auch eine zufällige Abfrage mit geringer Latenz.

Deshalb benötigt die Vektorspeicherung mehr als nur eine bessere Parquet-Einstellung. Sie benötigt eine Möglichkeit, verschiedene Spalten entsprechend ihrer tatsächlichen Lesereihenfolge anzuordnen.

Das dritte Problem: Der Datensatz befindet sich nicht innerhalb einer einzigen Engine

Die ersten beiden Probleme treten innerhalb der Datenbank auf. Das dritte Problem tritt an der Schnittstelle zwischen den Systemen auf.

KI-Datenpipelines erstrecken sich über viele Systeme

Im Video-Workflow findet innerhalb der Vektordatenbank selbst nur sehr wenig statt.

Die Rohvideos befinden sich im Objektspeicher. Die Clip-Erstellung kann in Spark oder Ray erfolgen. Die ästhetische Bewertung kann in einem GPU-Dienst laufen. Die Untertitelung kann in einer LLM-Inferenz-Pipeline erfolgen. Einbettungen können durch einen anderen GPU-Job generiert werden. Sparse-Vektoren können aus einem SPLADE-Dienst stammen. Offline-Auswertung, Filterung der Trainingsdaten, manuelle Überprüfung und Governance-Aufgaben können alle an anderer Stelle ausgeführt werden.

Die Vektordatenbank dient der Online-Suche, doch der Datensatz wird von vielen Systemen erstellt, korrigiert, ausgewertet und erweitert.

Proprietäre Speicherformate erzeugen mehrere Kopien der „Wahrheit“

Wenn die Datenbank ein proprietäres physisches Format verwendet, das nur sie selbst lesen und schreiben kann, benötigt jeder externe Job einen Export, eine Konvertierung, eine Kopie und einen Import. Dieselbe Sammlung kann in der Datenbank, in einem temporären Spark-Verzeichnis, in einer Auswertungsausgabe und in einem lokalen Backfill-Verzeichnis vorhanden sein. Dann lautet die eigentliche Frage:

  • Welche Kopie ist die „Quelle der Wahrheit“?
  • Welche enthält das Bildunterschriftenmodell vom letzten Monat?
  • Welche Zeilen wurden bereits durch menschliche Überprüfung korrigiert?
  • Welche Spalten mit spärlichen Vektoren wurden von welchem Modell generiert?
  • Welcher Vektorindex ist nach dem Backfill noch gültig?
  • Auf welches ursprüngliche Videoobjekt bezieht sich diese Zeile?

Im kleinen Maßstab kommen Teams manchmal noch mit Namenskonventionen und manuellen Überprüfungen aus. Bei Hunderten von Millionen von Zeilen und Terabytes an Einbettungen wird dies jedoch zu einem Konsistenzproblem.

Vektordatensätze benötigen einen gemeinsamen, versionierten Zustand

Lakehouse-Systeme haben eine Variante dieses Problems für strukturierte Daten gelöst. Bei Iceberg, Delta Lake und Hudi geht es nicht nur um die Speicherung von Dateien. Ihr wesentlicher Beitrag besteht darin, dass sich mehrere Engines auf denselben Tabellenzustand abstimmen können.

Vektordatenbanken benötigen nun eine ähnliche Fähigkeit, doch der Zustand ist komplexer. Er muss nicht nur Tabellendateien und Partitionen umfassen, sondern auch Vektorindizes, Textindizes, spärliche Merkmale, Löschprotokolle, Statistiken, Zeilen-ID-Bereiche und Verweise auf externe Blobs.

Die Frage lautet nicht einfach: „Kann Spark Milvus-Dateien lesen?“

Die Frage lautet vielmehr: Nachdem Spark eine spärliche Vektorspalte nachgefüllt hat, woher weiß Milvus, zu welcher Version diese Spalte gehört, welche Zeilen sie abdeckt, welches Modell sie erzeugt hat und wann Online-Abfragen sie sicher verwenden können?

Die Antwort muss im Speichermodell liegen.

Warum Patches nicht ausreichen

Es ist verlockend, diese als drei separate technische Probleme zu behandeln.

  • Schreibverstärkung? Batching hinzufügen.
  • Punktlesungen? Fügen Sie einen Cache hinzu.
  • Externe Systeme? Export- und Import-Tools hinzufügen.

Diese Patches können zwar helfen, lösen aber nicht das zugrunde liegende Problem: Ein Vektordatensatz ist physikalisch heterogen.

Im Beispielvideo sind „ clip_id “, „ video_id “, „ duration “ und „ aesthetic_score “ kurze Skalarfelder. Sie sind nützlich für Filterung und Analyse.

  • caption ist Text. Er kann für BM25, Überprüfung, Korrektur und Backfill verwendet werden.
  • embedding ist ein langer, dichter Vektor. Er wird für den ANN-Recall und später für die Suche auf Zeilenebene oder die Neureihung verwendet.
  • embedding_v2 ist eine neue Modellausgabe, die oft erst lange nach dem Einfügen der Originaldaten nachgetragen wird.
  • sparse_vector unterstützt die hybride Suche und verfügt über ein eigenes Zugriffsmuster.
  • Das Rohvideo sollte im Objektspeicher verbleiben. Die Datenbank sollte einen Verweis, eine Prüfsumme, einen MIME-Typ, eine Parser-Version und eine Beziehung auf Zeilenebene speichern.
  • Vektorindizes, Textindizes, Statistiken und Löschprotokolle sind abgeleitete Objekte mit eigener Versionssemantik.

Diese Objekte teilen sich eine logische Zeile, sollten jedoch nicht alle dasselbe physische Layout oder denselben Lebenszyklus aufweisen.

  • Werden sie in ein gewöhnliches Tabellenlayout gezwängt, werden Aktualisierungen aufwendig.
  • Werden sie in ein spaltenorientiertes Dateiformat gezwängt, werden punktuelle Lesevorgänge aufwendig.
  • Werden sie als unabhängige Objektdateien behandelt, wird die Versionsverwaltung anfällig.

Das Speichermodell muss also von der Tatsache ausgehen, dass der Datensatz heterogen ist.

Daraus ergeben sich drei Designanforderungen:

  • Erstens sollten verschiedene Spaltengruppen in unterschiedlichen physischen Formaten gespeichert werden.
  • Zweitens benötigen diese Spaltengruppen einen gemeinsamen Zeilen-ID-Raum, damit sie sich weiterhin wie eine einzige logische Tabelle verhalten können.
  • Drittens benötigt der Datensatz ein versioniertes Manifest, das angibt, welche Dateien, Indizes, Protokolle, Statistiken und Objektreferenzen zur aktuellen Ansicht gehören.

Dies ist das Design hinter Loon, unserer neuen Speicher-Engine, die Milvus und Zilliz Cloud zugrunde liegt.

Loon: eine Speicher-Engine hinter Milvus und Zilliz Cloud für sich weiterentwickelnde Vektordatensätze

Um alle oben genannten Probleme zu lösen, haben wir Loon entwickelt, die neue Speicher-Engine für Milvus und Zilliz Vector Lakebase (die nächste Evolutionsstufe von Zilliz Cloud), die für sich weiterentwickelnde Vektordatensätze konzipiert ist.

Der Name folgt der Tradition von Zilliz, Systeme nach Vogelarten zu benennen. Ein „Loon“ ist ein Tauchvogel, der an Seen lebt, was gut zum Ziel des Systems passt: Eine Vektordatenbank sollte nicht jedes Mal, wenn sie eine Abfrage ausführt, eine Spalte nachträglich auffüllt oder einen Index erstellt, einen ganzen See voller Daten verschieben, durchsuchen oder neu schreiben müssen. Sie sollte zunächst die aktuelle Version des Datensatzes verstehen, einschließlich seiner Spalten, Indizes, Statistiken, Löschprotokolle und Objektreferenzen, und dann nur den Teil lesen, den sie tatsächlich benötigt.

Hybride Dateiformate, Zeilen-ID-Ausrichtung und Manifest sind keine drei separaten Funktionen. Sie beruhen auf derselben Designannahme: Ein Vektordatensatz ist von Natur aus heterogen.

Drei Komponenten, ein Speichermodell

Hybride Dateiformate tragen der Tatsache Rechnung, dass verschiedene Spalten unterschiedliche Zugriffsmuster aufweisen. Skalare Felder eignen sich gut für Scans und Filter. Vektorfelder erfordern eine effiziente Suche auf Zeilenebene. Rohdatenobjekte wie Videos, PDFs, Bilder und Audiodateien gehören in den Objektspeicher und nicht in Datenbankdateien.

Die Zeilen-ID-Ausrichtung berücksichtigt, dass diese Spalten zwar physisch getrennt sein können, aber dennoch dieselben logischen Zeilen beschreiben. Eine Bildunterschrift, eine Einbettung, ein spärlicher Vektor und eine Video-URI können sich in unterschiedlichen Dateien und Formaten befinden, müssen aber dennoch als ein einziges Ergebnis zusammengeführt werden.

Das Manifest berücksichtigt, dass der Datensatz nicht einmalig geschrieben und dann unverändert belassen wird. Er wird von mehreren Systemen über mehrere Versionen hinweg für verschiedene Aufgaben modifiziert. Indizes, Statistiken, Löschprotokolle, Verweise auf externe Objekte und Spaltengruppen müssen alle in derselben versionierten Ansicht erscheinen.

Deshalb ist Loon nicht nur ein schnelleres Vektordateiformat. Ein schnelleres Format erleichtertzwar die Punktabfrage, löst aber weder die Schemaentwicklung noch die Koordination mehrerer Engines. Die Zeilen-ID-Ausrichtung lässt geteilte Spalten sich wie eine einzige Tabelle verhalten, legt jedoch nicht fest, welche Dateien zur aktuellen Version gehören. Ein Manifest kann den Zustand eines Datensatzes beschreiben, doch ohne Spaltengruppen und Zeilen-ID-Ausrichtung kann es unterschiedliche physische Layouts innerhalb einer logischen Sammlung nicht sauber abbilden.

Das Speichermodell benötigt alle drei Komponenten: unterschiedliche Formate für verschiedene Spaltengruppen, einen gemeinsamen Zeilen-ID-Raum zur Rekonstruktion von Zeilen und ein versioniertes Manifest, das jedem Leser und Schreiber mitteilt, wie der Datensatz aktuell beschaffen ist.

Wo Loon in Milvus und Zilliz Vector Lakebase zum Einsatz kommt

In Milvus ersetzt es die alte Segment-Binlog-Speicherschicht durch ein Modell, das auf Manifest, ColumnGroup, Dateiformat und Dateisystem-Abstraktionen aufbaut. In Zilliz Vector Lakebase (der nächsten Entwicklungsstufe von Zilliz Cloud) gilt derselbe Ansatz für die Vector Lakebase-Architektur: Der Abrufpfad der Vektordatenbank soll schnell bleiben, während die zugrunde liegenden Daten einfacher weiterentwickelt, analysiert und mit externen Systemen koordiniert werden können.

Die übergeordneten Milvus-Komponenten behalten weiterhin ihre gewohnten Rollen bei. Proxy übernimmt das Routing. QueryCoord und DataCoord kümmern sich um die Planung. IndexNode erstellt Indizes. Die anwendungsseitigen APIs für Sammlungen, Einfügungen, Suchvorgänge und hybride Suchvorgänge müssen keine Manifest-Dateien oder ColumnGroups offenlegen.

Die Änderung findet im Hintergrund statt.

DataNode, QueryNode, segcore, die Komprimierung und externe Konnektoren können über dieselbe Speicherabstraktion arbeiten. Das ist wichtig, da der Datensatz nicht mehr ausschließlich von der Datenbank geschrieben und gelesen wird. Er kann durch externe Rechensysteme erweitert und gleichzeitig von der Online-Suche genutzt werden.

Auf einer übergeordneten Ebene sehen die Schichten wie folgt aus:

Manifest
→ ColumnGroup
→ file format layer
→ filesystem abstraction

Das Manifest beschreibt den versionierten Zustand des Datensatzes. ColumnGroups ordnen eine logische Sammlung physischen Spaltengruppen zu. Die Dateiformat-Schicht ermöglicht es jeder ColumnGroup, ein geeignetes Format zu wählen. Die Dateisystem-Abstraktion funktioniert sowohl für Objektspeicher als auch für lokalen Speicher.

Der wichtige Punkt ist, dass hybride Dateiformate, die Ausrichtung der Zeilen-IDs und das Manifest keine separaten Funktionen sind. Zusammen definieren sie das Speichermodell.

Mit diesem Modell können wir die drei Entwurfsentscheidungen nacheinander betrachten: wie Loon verschiedene ColumnGroups speichert, wie es sie wieder in Zeilen ausrichtet und wie das Manifest diese Dateien in einen versionierten Datensatz umwandelt.

Entwurf 1: Das richtige Dateiformat für die richtige Spaltengruppe verwenden

Verschiedene Spalten weisen unterschiedliche Zugriffsmuster auf. Sie sollten nicht in dasselbe Dateiformat gezwängt werden.

Loon unterteilt eine logische Sammlung in ColumnGroups.

  • Skalarfelder, Filterfelder, Geschäftsschlüssel und statistische Felder werden häufig gescannt, gefiltert, aggregiert oder für die Abfrageplanung verwendet. Sie profitieren von Komprimierung, Spaltenausdünnung und Kompatibilität mit dem Ökosystem. Parquet eignet sich gut für diese Spalten.
  • Dichte Vektoren, spärliche Vektoren und Rerank-Merkmale werden oft nach dem ANN-Recall anhand der Zeilen-ID gelesen. Sie benötigen Zufallszugriff mit geringer Latenz, präzise Lesevorgänge im Byte-Bereich und selektive Dekodierung. Ein segmentorientiertes Layout ist hierfür besser geeignet. Loon nutzt in diesem Zusammenhang Vortex.
  • Rohobjekte wie Videos, PDFs, Bilder und Audiodateien sollten nicht in die Datendateien der Vektordatenbank eingebettet werden. Sie sollten im Objektspeicher verbleiben. Die Datenbank erfasst Referenzen, Prüfsummen, MIME-Typen, Parser-Versionen und Beziehungen auf Zeilenebene.

Für das Video-Beispiel könnte ein physisches Layout wie folgt aussehen:

Parquet ColumnGroup:
clip_id / video_id / start_offset / duration / aesthetic_score / caption

Vortex ColumnGroups: embedding embedding_v2 sparse_vector

Object storage: raw video objects

Für die Anwendung handelt es sich weiterhin um eine einzige Sammlung. Für die Speicherschicht verwenden verschiedene Teile dieser Sammlung unterschiedliche physische Formate. Dies reduziert unnötige Umschreibungen direkt. Das Hinzufügen von „ embedding_v2 “ kann zu einer neuen Vektor-ColumnGroup sowie einem Manifest-Commit führen. Es erfordert kein Umschreiben der Beschriftungsspalte, der skalaren Metadaten oder der bestehenden Einbettungsspalte.

Das gleiche Prinzip gilt für spärliche Vektoren, Rerank-Merkmale oder andere abgeleitete Felder. Wenn eine neue Spalte physisch unabhängig und anhand der Zeilen-ID ausgerichtet werden kann, müssen nicht auch nicht damit zusammenhängende Spalten denselben Umschreibungspfad durchlaufen.

Loon passt auch die Verwendung von Dateiformaten an.

Bei Parquet sind die Standardeinstellungen für datenintensive Vektoren nicht immer ideal. Eine 64-MB-Zeilengruppe kann für die Punkt-Suche zu groß sein, da ein kleiner zufälliger Lesezugriff weit mehr Daten abrufen kann, als benötigt werden. Loon verkleinert Zeilengruppen in relevanten Pfaden auf 1 MB und deaktiviert Kodierungen – wie beispielsweise die Wörterbuchkodierung bei Vektorspalten –, wenn diese bei zufällig angeordneten Vektordaten nicht hilfreich sind.

Bei Vortex liegt der Schwerpunkt auf dem Layout. Loon verwendet ein Layout, das einen Ausgleich zwischen Scan-Effizienz und Punktabfrage schafft. Innerhalb einer Zeilengruppe können Segmente aus verwandten Spalten nahe beieinander platziert werden, um das Scannen zu unterstützen. Zur Durchführung von Operationen ermöglichen das Lesen von Teilsegmenten dem System, nur die relevanten Bytes abzurufen, anstatt ein gesamtes Segment zu laden.

Loon unterstützt zudem eine schreibgeschützte Lance-Integration, sodass bestehende Lance-Datensätze als ColumnGroups eingebunden werden können, wenn Kompatibilität eine Rolle spielt.

Was der Benchmark zeigt

In einem lokalen Test mit einer einzelnen Datei mit 40.000 Zeilen und dem Schema {id: int64, name: utf8, value: float64, vector: list<float32>[128]} zeigte Vortex im Vergleich zu Parquet mit 1-MB-Zeilengruppen folgende Ergebnisse:

OperationVortexParquetUnterschied
Auslesen, K = 1.000 zufällige Zeilen5,8 ms144 ms25-mal schneller
Vollständiger Vektor-Spalten-Scan21 ms142 ms6,76-mal schneller
Dateigröße, ~21 MB Rohdaten6,62 MB7,16 MB7 % kleiner

Das Ergebnis „ take “ ergibt sich aus der Reduzierung der Menge an irrelevanten Daten, die gelesen und dekodiert werden müssen. Das Scan-Ergebnis ist auf Komprimierung und Implementierungsentscheidungen zurückzuführen.

Diese Zahlen sollten immer im Zusammenhang mit der jeweiligen Konfiguration betrachtet werden: 8 vCPUs, Ubuntu 22.04 KVM, lokales Dateisystem, eine Datei, 40.000 Zeilen, 1 MB große Zeilengruppen und das oben dargestellte Schema. Bei Objektspeichern kann die Netzwerk-E/A eine dominierende Rolle spielen, sodass die Reduzierung der Leseamplifikation noch wichtiger sein kann. Die tatsächlichen Ergebnisse hängen von der Form des Datensatzes, dem Verhalten des Objektspeichers, dem Cache-Status und dem Abfragemuster ab.

Der übergeordnete Punkt ist nicht, dass jede Spalte Vortex verwenden sollte.

Der Punkt ist vielmehr, dass Vektordatensätze eine Auswahl des Dateiformats auf ColumnGroup-Ebene erfordern.

Entwurf 2: Physische Dateien anhand von Zeilen-IDs ausrichten

Hybride Dateiformate lösen ein Problem: Verschiedene Spalten können nun in den Formaten gespeichert werden, die am besten zu ihnen passen.

Doch dadurch entsteht ein zweites Problem. Wenn skalare Felder in Parquet, Vektoren in Vortex und Rohobjekte im Objektspeicher liegen, wie kann das System sie dann dennoch als eine einzige Sammlung behandeln?

Loon löst dies durch die Ausrichtung anhand von Zeilen-IDs.

Die Zeilen-ID ist das Koordinatensystem der Speicherebene

Jede physische ColumnGroupFile speichert den Dateipfad und den von ihr abgedeckten Zeilen-ID-Bereich:

path
start_index
end_index

Verschiedene ColumnGroups können denselben Zeilen-ID-Bereich abdecken, selbst wenn sie in unterschiedlichen Dateien und Formaten gespeichert sind.

Für den Zeilen-ID- 12345 können sich die skalaren Metadaten in einer Parquet-ColumnGroup befinden, die Einbettung in einer Vortex-ColumnGroup und das Rohvideo durch einen Verweis auf den Objektspeicher dargestellt werden. Logisch gesehen bilden sie weiterhin eine Zeile. Dies verleiht der Speicherebene ein stabiles Koordinatensystem.

Die Zeilen-ID ist nicht der primäre Geschäftsschlüssel. Es ist das Koordinatensystem der Speicherschicht, das es Loon ermöglicht, eine Sammlung physisch aufzuteilen, ohne die Fähigkeit zu verlieren, sie logisch wiederherzustellen.

Neue Spalten erfordern kein Überschreiben alter Spalten

Das Hinzufügen von „ embedding_v2 “ erfordert kein Überschreiben der ursprünglichen „Caption“, Metadaten oder „ embedding_v1 “-ColumnGroups. Loon kann eine neue „Vector“-ColumnGroup schreiben, den von ihr abgedeckten Zeilen-ID-Bereich aufzeichnen und diese Änderung über das Manifest festschreiben.

Das Gleiche gilt für spärliche Vektoren, neu gewertete Merkmale oder andere abgeleitete Felder, die später hinzukommen.

Solange die neue „ColumnGroup“ den richtigen Zeilen-ID-Bereich abdeckt, kann sie derselben logischen Sammlung hinzugefügt werden, ohne dass nicht zugehörige Daten verschoben werden müssen.

Löschvorgänge und Komprimierung können gezielter erfolgen

Die Ausrichtung der Zeilen-IDs hilft auch bei Löschvorgängen.

Ein Löschvorgang kann zunächst über ein Löschprotokoll ausgedrückt werden. Die Zeile wird auf logischer Ebene unsichtbar, während die physische Bereinigung bis zur Komprimierung zurückgestellt wird. Wenn die Komprimierung schließlich ausgeführt wird, muss sie nicht immer jede mit den betroffenen Zeilen verknüpfte ColumnGroup neu schreiben. Sie kann sich auf die ColumnGroups konzentrieren, die bereinigt werden müssen.

Dies ist von Bedeutung, da nicht jede Spalte das gleiche Kostenprofil aufweist. Das Umschreiben einer kurzen skalaren ColumnGroup unterscheidet sich erheblich vom Umschreiben von Hunderten von Gigabyte dichter Vektoren.

Die hybride Suche kann nur die Spalten abrufen, die sie benötigt

Die Ausrichtung der Zeilen-IDs ist zudem der Grund, warum die hybride Suche auf der Grundlage hybrider Dateiformate praktikabel ist.

Nachdem die ANN-Suche Kandidaten-Zeilen-IDs zurückgegeben hat, kann das System nur die Felder abrufen, die für das Endergebnis benötigt werden: Beschriftungen, Metadaten, Vektoren, Rerank-Merkmale oder Objektreferenzen.

Beispielsweise benötigt eine Abfrage möglicherweise:

caption
embedding
video_uri

Diese Felder können sich in verschiedenen ColumnGroups befinden. Loon kann die relevanten Dateien anhand des Zeilen-ID-Bereichs lokalisieren, die erforderlichen Byte-Bereiche lesen und das Ergebnis zusammenstellen.

Ohne Zeilen-ID-Ausrichtung wären Hybridformate lediglich separate Dateien, die nebeneinander liegen. Mit Zeilen-ID-Ausrichtung verhalten sie sich wie eine einzige logische Sammlung.

Der „Packed Reader“ verbirgt die Aufteilung vor der oberen Ebene

Die Laufzeitkomponente, die dies nutzbar macht, ist der „Packed Reader“.

Die obere Ebene sieht einen einheitlichen Arrow-RecordBatch-Stream. Im Hintergrund können die Daten aus mehreren ColumnGroups in unterschiedlichen Dateiformaten stammen. Der Packed Reader verbirgt diese Unterschiede, richtet die Daten anhand von Zeilen-ID-Bereichen aus und plant die E/A-Vorgänge für mehrere Dateien unter kontrollierter Speichernutzung.

Er unterstützt zudem das direkte „ take “ anhand von Zeilen-IDs. Anhand einer Reihe von Zeilen-IDs lokalisiert er die relevanten ColumnGroupFiles, führt Bereichslesungen durch und gibt die angeforderten Felder zurück.

Für den Video-Workflow kann eine ANN-Abfrage „ caption “, „ embedding “ und „ video_uri “ erfordern. Der Packed Reader kann die skalare ColumnGroup und die vektorielle ColumnGroup abrufen, ohne nicht relevante Spalten zu berühren.

Das ist der Unterschied zwischen „separaten Dateien“ und „einer Tabelle mit mehreren physischen Layouts“.

Entwurf 3: Das Manifest als „Quelle der Wahrheit“ nutzen

Hybride Dateiformate definieren, wie Daten physisch gespeichert werden. Die Ausrichtung der Zeilen-IDs bestimmt, wie getrennte ColumnGroups dennoch eine einzige logische Tabelle bilden. Das System muss jedoch noch eine übergeordnete Frage beantworten: Welche Dateien, Protokolle, Statistiken, Indizes und Objektreferenzen gehören zur aktuellen Version des Datensatzes? Das ist die Aufgabe des Manifests.

Objektspeicherverzeichnisse reichen nicht aus

Objektspeicher ist kein Datenbankkatalog. Ein Verzeichnis kann alte Dateien, neue Dateien, Ausgabedateien fehlgeschlagener Jobs, temporäre Dateien, Löschprotokolle, Dateien, auf die noch von älteren Snapshots verwiesen wird, sowie Dateien enthalten, die auf die Bereinigung warten. Die Tatsache, dass eine Datei existiert, bedeutet nicht, dass sie zur aktuellen Version des Datensatzes gehört.

Ein Loon-Datensatz kann beispielsweise in folgenden Verzeichnissen organisiert sein:

_metadata/
_data/
_delta/
_stats/
_index/

Doch die Verzeichnisstruktur ist nicht die „Quelle der Wahrheit“. Das Manifest ist es. Leser sollten keine Verzeichnisse auflisten und den Status aus den zufällig vorhandenen Dateien ableiten. Sie sollten das aktuelle Manifest lesen und der darin deklarierten versionierten Ansicht folgen.

Das Manifest definiert eine versionierte Ansicht des Datensatzes

Das Manifest definiert den Datensatz in einer bestimmten Version. Es enthält folgende Angaben:

  • welche ColumnGroups vorhanden sind
  • welche Zeilen-ID-Bereiche sie abdecken
  • welches physische Format jede ColumnGroup verwendet
  • wo sich die Dateien befinden
  • welche Löschprotokolle aktiv sind
  • Welche Statistiken verfügbar sind
  • welche Indizes vorhanden sind
  • auf welche externen Blobs verwiesen wird
  • welche Spalten und Zeilenbereiche diese Statistiken oder Indizes abdecken

Bei jeder Aktualisierung wird eine neue Manifest-Version geschrieben. Ein Leser, der Version N öffnet, sieht eine stabile Ansicht des Datensatzes in Version N. Ein Schreiber kann Version N+1 vorbereiten, ohne Leser zu stören, die noch Version N verwenden.

Das Manifest erfasst mehr als nur Tabellendateien

In Loon ist der Hauptteil des Manifests mit Apache Avro kodiert und in vier Hauptabschnitte gegliedert.

  • ColumnGroups beschreiben die Spalten, Formate, Dateien und Zeilen-ID-Bereiche.
  • „DeltaLogs“ beschreiben Löschvorgänge. Verschiedene Löschtypen decken unterschiedliche Ursachen für Änderungen ab, wie z. B. Primärschlüssel-Löschungen durch Clients, positionsbezogene Löschungen durch interne Komprimierung oder Gleichheitslöschungen durch externe Engines.
  • „Stats“ enthalten Planungsmetadaten wie Bloom-Filter, BM25-Statistiken sowie Min-/Max-Werte.
  • Indexes beschreiben den Indextyp, Parameter, die abgedeckten Spalten und Zeilen-ID-Bereiche. Dazu können Vektorindizes wie HNSW oder IVF, Textindizes, invertierte Indizes, Bitmap-Indizes und zugehörige Strukturen gehören.

Hier unterscheidet sich Loon von einem herkömmlichen Tabellenmanifest.

Ein Vektordatensatz muss nicht nur Datendateien und Partitionen nachverfolgen. Er muss auch Vektorindizes, Textindizes, spärliche Merkmale, Löschprotokolle, Statistiken, Verweise auf externe Objekte und die Zeilen-ID-Bereiche nachverfolgen, die diese miteinander verbinden.

Das Manifest muss nicht nur von der Datenbank, sondern auch von anderen geschrieben werden können

Das Wichtigste ist nicht nur, was das Manifest enthält, sondern auch, wer es schreiben darf.

  • Wenn nur die Datenbank das Manifest schreiben kann, bleibt es interne Metadaten. Sauberere Metadaten, aber immer noch auf eine Engine beschränkt.
  • Wenn externe Engines neue ColumnGroups, Statistiken und Manifest-Einträge generieren können, wird das Manifest zu einer Koordinationsschnittstelle.
  • Ein Spark-Job kann beispielsweise eine spärliche Vektorspalte nachbelegen. Er schreibt eine neue ColumnGroup, erfasst die Zeilenabdeckung und Statistiken und führt ein neues Manifest durch. Online-Abfragen können während des Jobs weiterhin die alte Version lesen. Sobald der Commit erfolgreich ist, wird die neue Version sichtbar.

Dies ähnelt im Grundgedanken Iceberg und Delta Lake, doch das Objektmodell ist umfassender. Ein Vektordatensatz muss Vektorindizes, Textindizes, spärliche Merkmale, Löschprotokolle, Statistiken, Blob-Referenzen und Zeilen-ID-Bereiche nachverfolgen, nicht nur Tabellendateien und Partitionen.

Optimistische Commits vereinfachen Versionsaktualisierungen

Bei jedem Commit wird eine neue Manifest-Version geschrieben. Ein Schreiber kann neue Inhalte auf Basis der Version N erstellen und anschließend versuchen, diese unter manifest-{N+1}.avro zu schreiben. Die Semantik des bedingten Schreibens oder der Generationsabgleichs bei Objektspeichern kann dazu führen, dass der Commit fehlschlägt, wenn diese Version bereits existiert. Der Schreiber kann es dann mit der neueren Version erneut versuchen.

Dies verleiht Loon optimistische Parallelität, ohne dass jede Aktualisierung einen aufwendigen, stark konsistenten Koordinationspfad durchlaufen muss. Ohne ein Manifest führt die Speicherung in verschiedenen Formaten und auf verschiedenen Engines letztendlich zu Namenskonventionen und manueller Abstimmung. Das mag bei kleinen Datensätzen funktionieren. Bei Vektordaten im TB-Maßstab funktioniert es jedoch nicht.

Das Manifest ist das, was heterogene Dateien in einen Datensatz verwandelt, den mehrere Systeme sicher lesen und aktualisieren können.

Was ändert sich für Nutzer, wenn der Speicher versioniert wird?

Für Anwendungsentwickler sollte Loon keine neue API-Belastung darstellen.

Die Nutzer sollten weiterhin mit den vertrauten Milvus-Konzepten arbeiten: Sammlungen, Einfügungen, Suche und hybride Suche. Sie sollten sich bei der normalen Anwendungsentwicklung keine Gedanken über Manifest-Dateien, ColumnGroups, Zeilen-ID-Bereiche oder das Dateilayout machen müssen.

Die Änderung findet im Hintergrund statt. Der Speicher berücksichtigt nun besser, wie sich KI-Datensätze tatsächlich entwickeln.

Das Hinzufügen einer neuen Einbettung sollte die alten Daten nicht verschieben

Bisher erforderte das Hinzufügen von „ embedding_v2 “ zu einer bestehenden Sammlung oft das Exportieren von Daten, das Trainieren eines neuen Modells, das Generieren von Vektoren und anschließend das erneute Importieren oder die Massenaktualisierung der Sammlung über das SDK. Dieser Weg verursacht einen hohen Betriebsaufwand: Versionsverfolgung, Wiederholungsversuche bei fehlgeschlagenen Jobs, Index-Neuerstellungen, Auswirkungen auf den Betrieb und Konsistenzprüfungen.

Mit Loon lässt sich dies auf eine Schemaentwicklung plus einen neuen ColumnGroup-Commit reduzieren. Die neue Einbettungsspalte kann als eigene physische ColumnGroup geschrieben, anhand der Zeilen-ID ausgerichtet und über das Manifest sichtbar gemacht werden. Die alte Beschriftungsspalte, die skalare Metadatenspalte und die ursprüngliche Einbettungsspalte müssen nicht verschoben werden.

Nachträgliche Einträge sollten keine clientseitige Aktualisierungsschleife erfordern

Viele AI-Datenaktualisierungen sind Backfills. Ein Team fügt möglicherweise spärliche Vektoren hinzu, nachdem die hybride Suche an Bedeutung gewonnen hat. Es fügt möglicherweise Rerank-Merkmale hinzu, nachdem ein neues Modell trainiert wurde. Es korrigiert möglicherweise Bildunterschriften nach einer manuellen Überprüfung. Es fügt möglicherweise Governance-Tags hinzu, nachdem eine Richtlinie aktualisiert wurde.

In einem herkömmlichen Layout erfolgen diese Änderungen oft über Client-SDK-Updates oder rein datenbankbasierte Schreibpfade, selbst wenn die Daten von Spark, Ray oder einer anderen externen Engine erzeugt werden.

Mit Loon können externe Rechensysteme neue ColumnGroups erzeugen und diese über das Manifest festschreiben. Die Datenbank muss nicht mehr der einzige Einstiegspunkt für jede Neuschreibung sein.

Für die Offline-Analyse sollte keine weitere Kopie der „Wahrheit“ erforderlich sein

Bisher haben Teams häufig eine Online-Sammlung zur Offline-Auswertung oder -Analyse in Parquet exportiert. Dadurch entstehen zwei Versionen desselben Datensatzes: die Online-Sammlung und die Analysekopie. Sobald Beschriftungen korrigiert, Einbettungen neu generiert, Löschprotokolle angewendet oder Indizes neu aufgebaut wurden, muss das Team abklären, welche Kopie aktuell ist.

Mit einem Manifest-basierten Speichermodell können Analyse-Engines dieselbe versionierte Datensatzansicht lesen wie das Servingsystem. Sie können nur die Spalten projizieren, die sie benötigen, nur die relevanten Zeilenbereiche scannen und mit einer deklarierten Datensatzversion arbeiten, anstatt mit einem manuell exportierten Snapshot.

Löschungen und Korrekturen sollten nur die geänderten Teile betreffen

Löschungen, Korrekturen von Beschriftungen, Korrekturen von Labels und Governance-Aktualisierungen gehören bei KI-Datensätzen zur Routine. Sie sollten nicht dazu führen, dass jede Spalte mit langen Vektoren denselben Umschreibungsprozess durchlaufen muss.

Mit Loon können Löschprotokolle zunächst als logische Löschung behandelt werden. Eine spätere Komprimierung kann die betroffenen ColumnGroups bereinigen, ohne nicht betroffene Daten neu zu schreiben. Wenn sich ein kurzes Textfeld ändert, sollte die Speicherschicht nicht Hunderte von Gigabyte dichter Vektoren neu schreiben müssen, nur weil diese dieselbe logische Zeile teilen.

Externe Engines werden Teil des Workflows, nicht mehr nur eine Notlösung

Die größere Veränderung besteht darin, dass externe Engines nicht mehr als Systeme außerhalb der Vektordatenbank behandelt werden.

Spark, Ray, Auswertungsjobs, Labeling-Systeme und Governance-Pipelines erzeugen und modifizieren bereits einen Großteil der Daten. Die Speicherschicht sollte es ihnen ermöglichen, auf der Grundlage einer einzigen „Single Source of Truth“ zusammenzuarbeiten, anstatt ständig Daten zu exportieren, zu kopieren und wieder zu importieren.

Genau das ermöglicht eine Version von Manifest. Sie bietet Online-Bereitstellung, Offline-Analyse, Backfill-Jobs und Komprimierung eine gemeinsame Sicht auf den Datensatz.

Das mag nach internen Speicherdetails klingen, hat aber Einfluss darauf, wie schnell Teams mit KI-Datensätzen iterieren können. Jede Modelländerung, jedes Feature-Backfill, jede Bildbeschriftungskorrektur, jeder Qualitätsfilter und jeder Index-Neuaufbau hängt von derselben Frage ab:„Kann das System den Datensatz aktualisieren, ohne Daten zu verschieben, die es nicht verschieben muss?“

Das ist der praktische Nutzen des Speichermodells.

Loon ist in der Milvus 3.0-Beta und in Zilliz Vector Lakebase verfügbar

Loon ist in der Milvus 3.0-Beta verfügbar und ist zudem Teil der Speicherschicht in Zilliz Vector Lakebase, der nächsten Entwicklungsstufe von Zilliz Cloud. Diese Version konzentriert sich auf drei Kernbereiche:

  • Das Manifest. Das Ziel besteht darin, dass Schreibvorgänge, Nachträge, Löschungen, Statistiken und Indexaktualisierungen versionierte Datensatzansichten erzeugen, die Leser konsistent öffnen können. Für Leser bedeutet dies, dass eine Abfrage eine bestimmte Manifest-Version öffnen und eine stabile Ansicht des Datensatzes anzeigen kann. Für Schreiber bedeutet dies, dass neue Datendateien, Löschprotokolle, Statistiken oder Indexdateien zunächst vorbereitet und dann durch einen versionierten Commit sichtbar gemacht werden können.
  • Unterstützung für ColumnGroup und Formate. Parquet unterstützt skalare und ökosystemfreundliche Spalten. Vortex unterstützt vektorlastige Zugriffsmuster. Lance kann im schreibgeschützten Modus integriert werden, um die Kompatibilität mit bestehenden Lance-Datensätzen zu gewährleisten.
  • Der Index auf Lake. Skalare Statistiken, Filterindizes und invertierte Textindizes können an der Manifest-basierten Planung nach Zeilenbereichen teilnehmen. Lake-native Vektorindizes sind stärker eingebunden. HNSW und IVF verhalten sich bei Objektspeichern unterschiedlich, wobei insbesondere HNSW empfindlich auf wahlfreien Zugriff und Cache-Lokalität reagiert. Es ist nicht möglich, einfach ein für eine lokale SSD konzipiertes Layout wiederzuverwenden und das gleiche Ergebnis zu erwarten.

Es gibt noch einiges zu tun

  • Externe Schreibpfade sind wichtig, da Spark und Ray in der Lage sein sollten, ColumnGroups und Manifest-Commits zu erzeugen, ohne jeden Backfill über eine Client-SDK-Schleife erzwingen zu müssen.
  • Die Lakehouse-Interoperabilität ist wichtig, da viele Teams bereits Kataloge und Abfrage-Engines wie Iceberg, Delta Lake, Trino, DuckDB und Athena nutzen . Vektordaten sollten in dieses Ökosystem integriert werden können, ohne dass die Suchleistung bei Vektoren beeinträchtigt wird.
  • Das Indexlayout ist wichtig, da Graph-Indizes und invertierte Strukturen unterschiedliche Zugriffsmuster auf Objektspeichern aufweisen.
  • Die Semantik großer Objekte ist wichtig, da Rohvideos, PDFs, Bilder und Audiodateien ein Referenzmanagement, eine Versionierung und ein Löschverhalten erfordern, die mit dem abgeleiteten Vektordatensatz übereinstimmen.

Das genaue Release-Verhalten, die Standardeinstellungen und der Migrationspfad sollten den entsprechenden Release-Hinweisen von Milvus und Zilliz Cloud entsprechen. Die Richtung in Sachen Speicher ist jedoch klar: Vektordatenbanken benötigen eine versionierte, Lake-native Grundlage unterhalb der Servicing-Schicht.

Testen Sie Loon unter Zilliz Vector Lakebase

Wenn Ihr aktueller Stack Online-Bereitstellung, Offline-Analyse, Backfills und externe Data-Lake-Workflows in verschiedene Systeme aufteilt, ist Zilliz Vector Lakebase einen Blick wert. Sie können es in der Zilliz Cloud ausprobieren. Bei einer Neuanmeldung mit Ihrer geschäftlichen E-Mail-Adresse erhalten Sie 100 US-Dollar Gratisguthaben. Gerne können Sie auch mit uns über Ihren Anwendungsfall sprechen.

Sie können auch die Veröffentlichung von Milvus 3.0 verfolgen, um zu sehen, wie sich Loon in der Open-Source-Engine weiterentwickelt.

Zilliz Vector Lakebase vereint:

  • Mehrstufige Bereitstellung für unterschiedliche Kompromisse zwischen Echtzeit-Leistung und Kosten
  • On-Demand-Suche für groß angelegte oder explorative Workloads ohne ständig aktive Rechenkapazität
  • Externe Data-Lake-Suche, sodass Sie bestehende Lake-Daten direkt indizieren und durchsuchen können
  • Umfassende Suche über Vektoren, Text, JSON und Geodaten hinweg mit hybrider Abfrage und Neurangierung
  • Einheitlicher, Lake-nativer Speicher auf Basis von Vortex, einem offenen Format, das für schnellere und kostengünstigere zufällige Lesezugriffe auf vektorlastige Daten entwickelt wurde

    Try Managed Milvus for Free

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

    Get Started

    Like the article? Spread the word

    Weiterlesen