Die Vektorsuche ist eine entscheidende Komponente generativer KI-Tools, da Retrieval Augmented Generation (RAG) so ähnlich ist
Im Jahr 2023 kam es zu einem explosionsartigen Anstieg der Vektorsuchprodukte und -projekte, was die Auswahl zu einer großen Herausforderung machte. Während Sie die Optionen recherchieren, müssen Sie die folgenden schwierigen Probleme und die verschiedenen Lösungsansätze berücksichtigen. Hier werde ich Sie durch diese Herausforderungen führen und beschreiben, wie DataStax sie für unsere Implementierung der Vektorsuche für DataStax Astra DB und Apache Cassandra bewältigt hat.
Im Kern dieser schwierigen Probleme liegt das, was Forscher als „
Viele Vektorsuchalgorithmen wurden für Datensätze entwickelt, die in den Speicher eines einzelnen Computers passen, und dies ist immer noch das einzige getestete Szenario
Wie bei jeder anderen Domäne erfordert die Skalierung sowohl Replikation als auch Partitionierung sowie Subsysteme, die das Ersetzen toter Replikate, deren Reparatur nach einer Netzwerkpartition usw. übernehmen.
Das war für uns einfach: Scale-out-Replikation ist das A und O von Cassandra, und die Kombination mit dem neuen SAI in Cassandra-5.0 (Storage-Attached Indexing – siehe
Mit „Garbage Collection“ meine ich das Entfernen veralteter Informationen aus dem Index – das Bereinigen gelöschter Zeilen und den Umgang mit Zeilen, deren indizierter Vektorwert sich geändert hat. Das scheint vielleicht nicht der Rede wert zu sein – es ist seit vierzig Jahren ein mehr oder weniger gelöstes Problem in der Welt der relationalen Datenbanken –, aber Vektorindizes sind einzigartig.
Das Hauptproblem besteht darin, dass alle uns bekannten Algorithmen, die sowohl Suchvorgänge mit geringer Latenz als auch Ergebnisse mit hoher Erinnerung liefern, diagrammbasiert sind. Es stehen viele andere Vektorindizierungsalgorithmen zur Verfügung –
Die Herausforderung bei Diagrammindizes besteht darin, dass Sie nicht einfach den alten (vektorbezogenen) Knoten herausreißen können, wenn sich eine Zeile oder ein Dokument ändert. Wenn Sie dies mehr als ein paar Mal tun, kann Ihr Diagramm seinen Zweck, die BFS (Breite-zuerst-Suche) auf Bereiche mit größerer Ähnlichkeit zu einem Abfragevektor zu lenken, nicht mehr erfüllen.
Sie müssen Ihre Indizes also irgendwann neu erstellen, um diese Speicherbereinigung durchzuführen. Aber wann – und wie – organisieren Sie sie? Wenn Sie bei Änderungen immer alles neu erstellen, erhöhen Sie die Anzahl der durchgeführten physischen Schreibvorgänge erheblich. dies wird als Schreibverstärkung bezeichnet. Wenn Sie andererseits nie eine Neuerstellung durchführen, müssen Sie zusätzliche Arbeit leisten, indem Sie veraltete Zeilen zum Zeitpunkt der Abfrage herausfiltern („Leseverstärkung“).
Dies ist ein weiterer Problembereich, an dem Cassandra seit Jahren arbeitet. Da SAI-Indizes an den Hauptspeicherlebenszyklus angehängt sind, nehmen sie auch an Cassandra teil
DataStax Astra DB basiert auf Apache Cassandra und bietet eine Plattform für Cloud-Anwendungs-Workloads.
Das bedeutet Arbeitslasten, die:
Massiv gleichzeitig Tausende bis Millionen von Anfragen pro Sekunde, normalerweise um jeweils nur ein paar Zeilen abzurufen. Aus diesem Grund könnten Sie Netflix nicht auf Snowflake ausführen, selbst wenn Sie es sich leisten könnten: Snowflake und ähnliche Analysesysteme sind darauf ausgelegt, nur wenige gleichzeitige Anfragen zu verarbeiten, die jeweils viele Sekunden bis Minuten oder sogar länger laufen.
Größer als der Speicher Wenn Ihr Datensatz in den Speicher eines einzelnen Computers passt, spielt es fast keine Rolle, welche Tools Sie verwenden. SQLite, MongoDB, MySQL – sie werden alle gut funktionieren. Wenn das nicht der Fall ist, wird es schwieriger – und die schlechte Nachricht ist, dass Vektoreinbettungen normalerweise mehrere KB oder etwa eine Größenordnung größer als typische Datenbankdokumente sind, sodass Sie relativ schnell zu einer Größe kommen, die größer als der Speicher ist.
Der Kern der Anwendung Wenn es Ihnen egal ist, ob Sie Ihre Daten verlieren, weil sie entweder nicht so wichtig sind oder weil Sie sie aus der eigentlichen Datenquelle wiederherstellen können, spielt es wiederum keine Rolle, welche Tools Sie verwenden. Datenbanken wie Cassandra und Astra DB sind darauf ausgelegt, Ihre Daten in jedem Fall verfügbar und dauerhaft zu halten.
Ich habe oben das Bekannte erwähnt
Ein damit verbundenes Problem besteht darin, dass ann-benchmarks jeweils nur eine Art von Operation ausführt: Zuerst wird der Index erstellt und dann wird er abgefragt. Der Umgang mit Updates, die mit Suchvorgängen verzahnt sind, ist optional – und wahrscheinlich sogar ein Handicap; Wenn Sie wissen, dass Sie sich nicht mit Updates befassen müssen, können Sie viele vereinfachende Annahmen treffen, die auf künstlichen Benchmarks gut aussehen.
Wenn es Ihnen wichtig ist, mehrere gleichzeitige Vorgänge mit Ihrem Index durchzuführen oder ihn nach der Erstellung zu aktualisieren, müssen Sie etwas genauer hinschauen, um zu verstehen, wie er funktioniert und welche Kompromisse damit verbunden sind.
Erstens verwenden alle mir bekannten Allzweck-Vektordatenbanken graphbasierte Indizes. Das liegt daran, dass Sie mit der Abfrage eines Diagrammindex beginnen können, sobald der erste Vektor eingefügt wird. Bei den meisten anderen Optionen müssen Sie entweder den gesamten Index erstellen, bevor Sie ihn abfragen, oder zumindest einen vorläufigen Scan der Daten durchführen, um einige statistische Eigenschaften zu erfahren.
Allerdings gibt es auch innerhalb der Diagrammindexkategorie noch wichtige Implementierungsdetails. Beispielsweise dachten wir zunächst, dass wir durch die Verwendung der HNSW-Indeximplementierung von Lucene Zeit sparen könnten, so wie es MongoDB Elastic und Solr tun. Aber wir haben schnell gelernt, dass Lucene nur Single-Threaded-, nicht-gleichzeitige Indexkonstruktionen bietet. Das heißt, Sie können es weder während der Erstellung abfragen (was einer der Hauptgründe für die Verwendung dieser Datenstruktur sein sollte!) noch zulassen, dass mehrere Threads es gleichzeitig erstellen.
Das HNSW-Papier legt nahe, dass ein feinkörniger Sperransatz funktionieren kann, aber wir sind noch einen Schritt weiter gegangen und haben einen nicht blockierenden Index erstellt. Dies ist Open-Source in
JVector skaliert gleichzeitige Updates linear auf mindestens 32 Threads. Dieses Diagramm ist sowohl auf der x- als auch auf der y-Achse logarithmisch skaliert und zeigt, dass eine Verdoppelung der Thread-Anzahl die Erstellungszeit halbiert.
Noch wichtiger ist, dass die nicht blockierende Parallelität von JVector durch die Mischung von Suchvorgängen und Aktualisierungen realistischere Arbeitslasten ermöglicht. Hier ist ein Vergleich der Leistung von Astra DB (mit JVector) im Vergleich zu Pinecone über verschiedene Datensätze hinweg. Während Astra DB für einen statischen Datensatz etwa 10 % schneller ist als Pinecone, ist es 8- bis 15-mal schneller und indiziert auch neue Daten. Wir haben mit Pinecone die beste verfügbare Pod-Stufe ausgewählt (Pod-Typ: p2 und Pod-Größe: x8, mit 2 Pods pro Replikat), basierend auf den Empfehlungen für höheren Durchsatz und geringere Latenz. Pinecone gibt nicht bekannt, auf welche physischen Ressourcen dies zurückzuführen ist. Auf der Astra DB-Seite haben wir uns für das standardmäßige PAYG-Bereitstellungsmodell entschieden und mussten uns keine Gedanken über die Auswahl der Ressourcen machen, da es serverlos ist. Tests wurden mit durchgeführt
Astra DB erreicht dies und behält gleichzeitig eine höhere Erinnerung und Präzision bei (
Wir begannen mit dem
Ein HNSW-Index besteht aus einer Reihe von Schichten, wobei jede Schicht über der Basisschicht etwa 10 % so viele Knoten wie die vorherige aufweist. Dadurch können die oberen Schichten als Sprungliste fungieren, sodass sich die Suche auf die rechte Nachbarschaft der unteren Schicht konzentrieren kann, die alle Vektoren enthält.
Dieses Design bedeutet jedoch, dass Sie (wie bei allen Diagrammindizes) nicht mit der Aussage „Der Festplatten-Cache wird uns retten“ davonkommen können, da im Gegensatz zu normalen Datenbankabfrage-Workloads jeder Vektor im Diagramm eine nahezu gleiche Wahrscheinlichkeit hat für eine Suche relevant sein. (Die Ausnahme bilden die oberen Schichten, die wir zwischenspeichern können und auch tun.)
So sah ein Profil zur Bereitstellung eines 100 Millionen Vektordatensatzes aus Wikipedia-Artikelblöcken (ca. 120 GB auf der Festplatte) auf meinem Desktop mit 64 GB RAM aus, als wir Lucene verwendeten:
Cassandra verbringt fast die ganze Zeit damit, darauf zu warten, Vektoren von der Festplatte zu lesen.
Um dieses Problem zu lösen, haben wir einen fortschrittlicheren Algorithmus namens DiskANN implementiert und ihn als eigenständige eingebettete Vektorsuchmaschine als Open-Source-Lösung bereitgestellt.
So sieht HNSW im Vergleich zu DiskANN in einem rein eingebetteten Szenario ohne Client/Server-Komponenten aus. Dies misst die Geschwindigkeit der Suche im Deep100M-Datensatz unter Lucene (HNSW) und JVector (DiskANN). Der Lucene-Index ist 55 GB groß, einschließlich des Index und der Rohvektoren. Der JVector-Index beträgt 64 GB. Die Suche wurde auf meinem 24-GB-MacBook durchgeführt, das etwa ein Drittel so viel Speicher hat, wie nötig wäre, um den Index im RAM zu halten.
Zusammensetzbarkeit bezieht sich im Kontext von Datenbanksystemen auf die Fähigkeit, verschiedene Funktionen und Fähigkeiten nahtlos und kohärent zu integrieren. Dies ist besonders wichtig, wenn die Integration einer neuen Funktionskategorie wie der Vektorsuche diskutiert wird. Nicht-Spielzeug-Anwendungen erfordern immer beide klassischen
Betrachten Sie das Einfache
In einem realistischeren Anwendungsfall arbeitete einer unserer Lösungsingenieure kürzlich mit einem Unternehmen in Asien zusammen, das seinen Produktkatalog um eine semantische Suche erweitern, aber auch einen begriffsbasierten Abgleich ermöglichen wollte. Wenn der Benutzer beispielsweise nach [„roter“ Kugelhahn] sucht, möchte er die Suche auf Elemente beschränken, deren Beschreibung mit dem Begriff „rot“ übereinstimmt, unabhängig davon, wie semantisch ähnlich die Vektoreinbettungen sind. Die wichtigste neue Abfrage lautet dann (zusätzlich zu klassischen Funktionen wie Sitzungsverwaltung, Bestellhistorie und Warenkorbaktualisierungen): Beschränken Sie die Produkte auf diejenigen, die alle zitierten Begriffe enthalten, und suchen Sie dann nach den Produkten, die der Suche des Benutzers am ähnlichsten sind
Dieses zweite Beispiel macht deutlich, dass Anwendungen nicht nur sowohl klassische Abfragefunktionen als auch Vektorsuche benötigen, sondern dass sie häufig auch in der Lage sein müssen, Elemente beider in derselben Abfrage zu verwenden.
Der aktuelle Stand der Technik in diesem jungen Bereich besteht darin, zu versuchen, das, was ich klassische Abfragen nenne, in einer „normalen“ Datenbank und Vektorabfragen in einer Vektordatenbank durchzuführen und die beiden dann ad hoc zusammenzufügen, wenn beides der Fall ist gleichzeitig erforderlich. Dies ist fehleranfällig, langsam und teuer; Der einzige Vorteil besteht darin, dass Sie es zum Laufen bringen können, bis Sie eine bessere Lösung haben.
Mit Astra DB haben wir diese bessere Lösung auf Basis von Cassandra SAI entwickelt (und als Open-Source-Lösung bereitgestellt). Da SAI die Erstellung benutzerdefinierter Indextypen ermöglicht, die alle an den Stable- und Komprimierungslebenszyklus von Cassandra gebunden sind, ist es für Astra DB einfach, Entwicklern die Kombination von booleschen Prädikaten, begriffsbasierter Suche und Vektorsuche ohne Mehraufwand zu ermöglichen Verwaltung und Synchronisierung separater Systeme. Dadurch erhalten Entwickler, die generative KI-Anwendungen erstellen, ausgefeiltere Abfragefunktionen, die zu höherer Produktivität und schnellerer Markteinführung führen.
Vektorsuchmaschinen sind eine wichtige neue Datenbankfunktion mit mehreren architektonischen Herausforderungen, darunter Scale-out, Garbage Collection, Parallelität, effektive Festplattennutzung und Zusammensetzbarkeit. Ich glaube, dass wir beim Aufbau der Vektorsuche für Astra DB die Fähigkeiten von Cassandra nutzen konnten, um Entwicklern generativer KI-Anwendungen ein erstklassiges Erlebnis zu bieten.
– Von Jonathan Ellis, DataStax