Überblick über die Vektorsuche - Amazon MemoryDB

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

Überblick über die Vektorsuche

Die Vektorsuche basiert auf der Erstellung, Pflege und Verwendung von Indizes. Jede Vektorsuchoperation spezifiziert einen einzelnen Index und ihre Operation ist auf diesen Index beschränkt, d. h. Operationen an einem Index werden von Operationen an einem anderen Index nicht beeinflusst. Mit Ausnahme der Operationen zum Erstellen und Löschen von Indizes können jederzeit beliebig viele Operationen für jeden Index ausgeführt werden, was bedeutet, dass auf Clusterebene mehrere Operationen mit mehreren Indizes gleichzeitig ausgeführt werden können.

Einzelne Indizes sind benannte Objekte, die in einem eindeutigen Namespace existieren, der sich von den anderen Redis OSS-Namespaces unterscheidet: Schlüssel, Funktionen usw. Jeder Index ist konzeptionell einer herkömmlichen Datenbanktabelle insofern ähnlich, als er in zwei Dimensionen strukturiert ist: Spalten und Zeilen. Jede Zeile in der Tabelle entspricht einem Redis-OSS-Schlüssel. Jede Spalte im Index entspricht einem Element oder Teil dieses Schlüssels. In diesem Dokument sind die Begriffe Schlüssel, Zeile und Datensatz identisch und werden synonym verwendet. In ähnlicher Weise sind die Begriffe Spalte, Feld, Pfad und Element im Wesentlichen identisch und werden auch synonym verwendet.

Es gibt keine speziellen Befehle zum Hinzufügen, Löschen oder Ändern indizierter Daten. Vielmehr aktualisieren die vorhandenen JSON Befehle HASH oder Befehle, die einen Schlüssel ändern, der sich in einem Index befindet, auch automatisch den Index.

Indizes und der Redis OSS-Keyspace

Indizes werden über eine Teilmenge des Redis OSS-Schlüsselraums erstellt und verwaltet. Bei mehreren Indizes können unzusammenhängende oder überlappende Teilmengen des Redis OSS-Schlüsselraums ohne Einschränkung ausgewählt werden. Der Schlüsselraum für jeden Index wird durch eine Liste von Schlüsselpräfixen definiert, die bei der Erstellung des Indexes bereitgestellt werden. Die Liste der Präfixe ist optional, und wenn sie weggelassen wird, ist der gesamte Redis OSS-Schlüsselraum Teil dieses Indexes. Indizes werden auch so eingegeben, dass sie nur Schlüssel abdecken, die einen passenden Typ haben. Derzeit werden nur JSON- und HASH-Indizes unterstützt. Ein HASH-Index indexiert nur HASH-Schlüssel, die in seiner Präfixliste enthalten sind, und in ähnlicher Weise indexiert ein JSON-Index nur JSON-Schlüssel, die in seiner Präfixliste enthalten sind. Schlüssel in der Schlüsselraum-Präfixliste eines Indexes, die nicht den angegebenen Typ haben, werden ignoriert und wirken sich nicht auf Suchvorgänge aus.

Wenn ein HASH- oder JSON-Befehl einen Schlüssel ändert, der sich innerhalb eines Schlüsselraums eines Indexes befindet, wird dieser Index aktualisiert. Dieser Prozess beinhaltet das Extrahieren der deklarierten Felder für jeden Index und das Aktualisieren des Index mit dem neuen Wert. Der Aktualisierungsprozess wird in einem Hintergrundthread durchgeführt, was bedeutet, dass die Indizes erst irgendwann mit ihren Schlüsselrauminhalten konsistent sind. Somit wird das Einfügen oder Aktualisieren eines Schlüssels für einen kurzen Zeitraum nicht in den Suchergebnissen sichtbar sein. In Zeiten hoher Systemlast und/oder starker Datenmutation kann die Sichtbarkeitsverzögerung länger werden.

Die Erstellung eines Index ist ein mehrstufiger Prozess. Der erste Schritt besteht darin, den Befehl FT.CREATE auszuführen, der den Index definiert. Bei erfolgreicher Ausführung einer Erstellung wird automatisch der zweite Schritt eingeleitet — das Backfilling. Der Backfill-Prozess läuft in einem Hintergrundthread und durchsucht den Redis-OSS-Schlüsselbereich nach Schlüsseln, die sich in der Präfixliste des neuen Indexes befinden. Jeder gefundene Schlüssel wird dem Index hinzugefügt. Schließlich wird der gesamte Schlüsselraum gescannt, wodurch der Indexerstellungsprozess abgeschlossen ist. Beachten Sie, dass während der Ausführung des Backfill-Prozesses Mutationen von indizierten Schlüsseln zulässig sind, es keine Einschränkungen gibt und der Index-Backfill-Prozess erst abgeschlossen wird, wenn alle Schlüssel ordnungsgemäß indexiert sind. Abfrageoperationen, die versucht werden, während ein Index aufgefüllt wird, sind nicht zulässig und werden mit einem Fehler beendet. Der Abschluss des Backfill-Vorgangs kann anhand der Ausgabe des FT.INFO Befehls für diesen Index ('backfill_status') ermittelt werden.

Typen von Indexfeldern

Jedes Feld (Spalte) eines Indexes hat einen bestimmten Typ, der bei der Indexerstellung deklariert wird, sowie eine Position innerhalb eines Schlüssels. Bei HASH-Schlüsseln ist der Speicherort der Feldname innerhalb des HASH. Bei JSON-Schlüsseln ist der Speicherort eine JSON-Pfadbeschreibung. Wenn ein Schlüssel geändert wird, werden die mit den deklarierten Feldern verknüpften Daten extrahiert, in den deklarierten Typ konvertiert und im Index gespeichert. Wenn die Daten fehlen oder nicht erfolgreich in den deklarierten Typ konvertiert werden können, wird dieses Feld aus dem Index weggelassen. Es gibt vier Arten von Feldern, die im Folgenden erklärt werden:

  • Zahlenfelder enthalten eine einzelne Zahl. Bei JSON-Feldern müssen die numerischen Regeln für JSON-Nummern befolgt werden. Bei HASH wird erwartet, dass das Feld den ASCII-Text einer Zahl enthält, die im Standardformat für Fest- oder Fließkommazahlen geschrieben ist. Unabhängig von der Darstellung innerhalb des Schlüssels wird dieses Feld zur Speicherung im Index in eine 64-Bit-Fließkommazahl konvertiert. Zahlenfelder können mit dem Bereichssuchoperator verwendet werden. Da die zugrunde liegenden Zahlen mit ihren Genauigkeitsbeschränkungen in Fließkommazahlen gespeichert werden, gelten die üblichen Regeln für numerische Vergleiche für Fließkommazahlen.

  • Tag-Felder enthalten null oder mehr Tag-Werte, die als einzelne UTF-8-Zeichenfolge codiert sind. Die Zeichenfolge wird mithilfe eines Trennzeichens (Standard ist ein Komma, kann aber überschrieben werden) in Tagwerte zerlegt, wobei führende und nachfolgende Leerzeichen entfernt werden. In einem einzigen Tag-Feld können beliebig viele Tag-Werte enthalten sein. Tag-Felder können verwendet werden, um Abfragen nach der Äquivalenz von Tag-Werten zu filtern, wobei entweder Groß- und Kleinschreibung berücksichtigt wird oder nicht.

  • Textfelder enthalten einen Blob von Bytes, die nicht UTF-8-kompatibel sein müssen. Textfelder können verwendet werden, um Abfrageergebnisse mit anwendungsrelevanten Werten zu versehen. Zum Beispiel eine URL oder der Inhalt eines Dokuments usw.

  • Vektorfelder enthalten einen Zahlenvektor, der auch als Einbettung bezeichnet wird. Vektorfelder unterstützen die Suche nach dem K-Nearest Neighbor (KNN) von Vektoren fester Größe unter Verwendung eines bestimmten Algorithmus und einer bestimmten Entfernungsmetrik. Bei HASH-Indizes sollte das Feld den gesamten Vektor enthalten, der im Binärformat codiert ist (Little-Endian IEEE 754). Bei JSON-Schlüsseln sollte der Pfad auf ein mit Zahlen gefülltes Array der richtigen Größe verweisen. Beachten Sie, dass bei der Verwendung eines JSON-Arrays als Vektorfeld die interne Darstellung des Arrays innerhalb des JSON-Schlüssels in das für den ausgewählten Algorithmus erforderliche Format konvertiert wird, wodurch der Speicherverbrauch und die Genauigkeit reduziert werden. Nachfolgende Lesevorgänge mit den JSON-Befehlen ergeben den reduzierten Genauigkeitswert.

Vektor-Index-Algorithmen

Es stehen zwei Vektorindex-Algorithmen zur Verfügung:

  • Flach — Der Flat-Algorithmus ist eine lineare Brute-Force-Verarbeitung aller Vektoren im Index, die exakte Antworten innerhalb der Grenzen der Genauigkeit der Entfernungsberechnungen liefert. Aufgrund der linearen Verarbeitung des Indexes können die Laufzeiten für diesen Algorithmus bei großen Indizes sehr hoch sein.

  • HNSW (Hierarchical Navigable Small Worlds) — Der HNSW-Algorithmus ist eine Alternative, die im Austausch für wesentlich kürzere Ausführungszeiten eine Annäherung an die richtige Antwort liefert. Der Algorithmus wird durch drei Parameter gesteuert, und. M EF_CONSTRUCTION EF_RUNTIME Die ersten beiden Parameter werden bei der Indexerstellung angegeben und können nicht geändert werden. Der EF_RUNTIME Parameter hat einen Standardwert, der bei der Indexerstellung angegeben wird, aber danach bei jedem einzelnen Abfragevorgang überschrieben werden kann. Diese drei Parameter wirken zusammen, um den Speicher- und CPU-Verbrauch bei Aufnahme- und Abfragevorgängen auszugleichen und die Qualität der Annäherung an eine exakte KNN-Suche (bekannt als Recall-Ratio) zu steuern.

Beide Vektorsuchalgorithmen (Flat und HNSW) unterstützen einen optionalen Parameter. INITIAL_CAP Wenn dieser Parameter angegeben ist, weist er den Indizes vorab Speicher zu, was zu einem geringeren Speicherverwaltungsaufwand und höheren Vektoraufnahmeraten führt.

Vektorsuchalgorithmen wie HNSW können das Löschen oder Überschreiben zuvor eingefügter Vektoren möglicherweise nicht effizient handhaben. Die Verwendung dieser Operationen kann zu einem übermäßigen Speicherverbrauch des Indexes und/oder zu einer Verschlechterung der Abrufqualität führen. Die Neuindizierung ist eine Methode zur Wiederherstellung einer optimalen Speichernutzung und/oder eines optimalen Speicherabrufs.

Ausdruck für eine Vektor-Suchanfrage

Die Befehle FT.SEARCH und FT.AGGREGATE erfordern einen Abfrageausdruck. Dieser Ausdruck ist ein einzelner Zeichenkettenparameter, der aus einem oder mehreren Operatoren besteht. Jeder Operator verwendet ein Feld im Index, um eine Teilmenge der Schlüssel im Index zu identifizieren. Mehrere Operatoren können mithilfe von booleschen Kombinatoren sowie Klammern kombiniert werden, um den gesammelten Satz von Schlüsseln (oder die Ergebnismenge) weiter zu erweitern oder einzuschränken.

Platzhalter

Der Platzhalteroperator, das Sternchen ('*'), entspricht allen Schlüsseln im Index.

Numerischer Bereich

Der numerische Bereichsoperator hat die folgende Syntax:

<range-search> ::= '@' <numeric-field-name> ':' '[' <bound> <bound> ']' <bound> ::= <number> | '(' <number> <number> ::= <integer> | <fixed-point> | <floating-point> | 'Inf' | '-Inf' | '+Inf'

Bei < numeric-field-name > muss es sich um ein deklariertes Feld vom Typ handelnNUMERIC. Standardmäßig ist die Grenze inklusiv, aber eine führende offene Klammer ['('] kann verwendet werden, um eine Grenze exklusiv zu machen. Die Bereichssuche kann mithilfe Inf von +Inf oder -Inf als eine der Grenzen in einen einzelnen relationalen Vergleich (<, <=, >, > =) umgewandelt werden. Unabhängig vom angegebenen numerischen Format (Ganzzahl, Festkomma, Gleitkomma, Unendlich) wird die Zahl für Vergleiche in 64-Bit-Gleitkommazahlen umgewandelt, wodurch die Genauigkeit entsprechend reduziert wird.

Beispiele
@numeric-field:[0 10] // 0 <= <value> <= 10 @numeric-field:[(0 10] // 0 < <value> <= 10 @numeric-field:[0 (10] // 0 <= <value> < 10 @numeric-field:[(0 (10] // 0 < <value> < 10 @numeric-field:[1.5 (Inf] // 1.5 <= value

Tag-Vergleich

Der Tag-Vergleichsoperator hat die folgende Syntax:

<tag-search> ::= '@' <tag-field-name> ':' '{' <tag> [ '|' <tag> ]* '}'

Wenn eines der Tags im Operator mit einem der Tags im Tag-Feld des Datensatzes übereinstimmt, wird der Datensatz in die Ergebnismenge aufgenommen. Das von dem entworfene Feld <tag-field-name> muss ein Feld des mit type deklarierten Index sein. TAG Beispiele für einen Tag-Vergleich sind:

@tag-field:{ atag } @tag-field: { tag1 | tag2 }

Boolesche Kombinationen

Die Ergebnismengen eines numerischen Operators oder eines Tag-Operators können mithilfe der booleschen Logik kombiniert werden: und/oder. Klammern können verwendet werden, um Operatoren zu gruppieren und/oder die Reihenfolge der Auswertung zu ändern. Die Syntax boolescher Logikoperatoren lautet:

<expression> ::= <phrase> | <phrase> '|' <expression> | '(' <expression> ')' <phrase> ::= <term> | <term> <phrase> <term> ::= <range-search> | <tag-search> | '*'

Mehrere Begriffe, die zu einer Phrase zusammengefasst sind, sind „und“ -ed. Mehrere Phrasen, die mit einem senkrechten Strich ('|') kombiniert werden, stehen für „oder“.

Vektorindizes unterstützen zwei verschiedene Suchmethoden: Nearest Neighbor und Range. Bei der Suche nach dem nächsten Nachbarn wird eine Zahl, K, der Vektoren im Index gefunden, die dem angegebenen (Referenz-) Vektor am nächsten sind. Dies wird umgangssprachlich KNN für „K“ -Nearest Neighbours genannt. Die Syntax für eine KNN-Suche lautet:

<vector-knn-search> ::= <expression> '=>[KNN' <k> '@' <vector-field-name> '$' <parameter-name> <modifiers> ']' <modifiers> ::= [ 'EF_RUNTIME' <integer> ] [ 'AS' <distance-field-name>]

Eine Vektor-KNN-Suche wird nur auf die Vektoren angewendet, die die Kriterien erfüllen. Dabei kann es sich um eine beliebige Kombination der oben definierten Operatoren handeln: Platzhalter, Bereichssuche, Tag-Suche und/oder boolesche Kombinationen <expression> davon.

  • <k>ist eine Ganzzahl, die die Anzahl der Vektoren mit den nächsten Nachbarn angibt, die zurückgegeben werden sollen.

  • <vector-field-name>muss ein deklariertes Feld vom Typ angebenVECTOR.

  • <parameter-name>field gibt einen der Einträge für die PARAM Tabelle des FT.AGGREGATE Befehls FT.SEARCH or an. Dieser Parameter ist der Referenzvektorwert für Entfernungsberechnungen. Der Wert des Vektors wird in den PARAM Wert im Little-Endian-Binärformat IEEE 754 codiert (genauso codiert wie bei einem HASH-Vektorfeld)

  • Bei Vektorindizes des Typs HNSW kann die optionale EF_RUNTIME Klausel verwendet werden, um den Standardwert des Parameters zu überschreiben, der bei der Indexerstellung festgelegt wurde. EF_RUNTIME

  • Die optionale Option <distance-field-name> stellt einen Feldnamen für die Ergebnismenge bereit, der die berechnete Entfernung zwischen dem Referenzvektor und dem gefundenen Schlüssel enthält.

Bei einer Bereichssuche werden alle Vektoren innerhalb einer bestimmten Entfernung (Radius) von einem Referenzvektor lokalisiert. Die Syntax für eine Bereichssuche lautet:

<vector-range-search> ::= ‘@’ <vector-field-name> ‘:’ ‘[’ ‘VECTOR_RANGE’ ( <radius> | ‘$’ <radius-parameter> ) $<reference-vector-parameter> ‘]’ [ ‘=’ ‘>’ ‘{’ <modifiers> ‘}’ ] <modifiers> ::= <modifier> | <modifiers>, <modifier> <modifer> ::= [ ‘$yield_distance_as’ ‘:’ <distance-field-name> ] [ ‘$epsilon’ ‘:’ <epsilon-value> ]

Wobei gilt:

  • <vector-field-name>ist der Name des Vektorfeldes, das durchsucht werden soll.

  • <radius> or $<radius-parameter>ist die numerische Entfernungsgrenze für die Suche.

  • $<reference-vector-parameter> ist der Name des Parameters, der den Referenzvektor enthält. Der Wert des Vektors wird in den PARAM-Wert im Little-Endian-Binärformat IEEE 754 codiert (dieselbe Kodierung wie für ein HASH-Vektorfeld)

  • Das optionale Feld <distance-field-name> stellt einen Feldnamen für die Ergebnismenge bereit, der die berechnete Entfernung zwischen dem Referenzvektor und den einzelnen Schlüsseln enthält.

  • Die optionale Option <epsilon-value> steuert die Grenze des Suchvorgangs. Vektoren innerhalb der Entfernung <radius> * (1.0 + <epsilon-value>) werden auf der Suche nach möglichen Ergebnissen durchquert. Die Standardeinstellung ist 0,01.

Befehl INFO

Die Vektorsuche erweitert den Redis OSS INFO-Befehl um mehrere zusätzliche Abschnitte mit Statistiken und Zählern. Bei einer Anfrage zum Abrufen des Abschnitts SEARCH werden alle folgenden Abschnitte abgerufen:

search_memory Abschnitt

Name Beschreibung
search_used_memory_bytes Anzahl der in allen Suchdatenstrukturen verbrauchten Speicherbytes
search_used_memory_human Für Menschen lesbare Version von oben

search_index_stats Abschnitt

Name Beschreibung
search_number_of_indexes Anzahl der erstellten Indizes
search_num_fulltext_indexes Anzahl der Nicht-Vektor-Felder in allen Indizes
search_num_vector_indexes Anzahl der Vektorfelder in allen Indizes
search_num_hash_indexes Anzahl der Indizes für Schlüssel vom Typ HASH
search_num_json_indexes Anzahl der Indizes für Schlüssel vom Typ JSON
search_total_indexed_keys Gesamtzahl der Schlüssel in allen Indizes
search_total_indexed_vectors Gesamtzahl der Vektoren in allen Indizes
search_total_indexed_hash_keys Gesamtzahl der Schlüssel des Typs HASH in allen Indizes
search_total_indexed_json_keys Gesamtzahl der Schlüssel vom Typ JSON in allen Indizes
search_total_index_size Von allen Indizes verwendete Bytes
search_total_fulltext_index_size Bytes, die von Indexstrukturen verwendet werden, die keine Vektoren sind
search_total_vector_index_size Von Vektorindexstrukturen verwendete Bytes
search_max_index_lag_ms Verzögerung bei der Aufnahme während der letzten Batch-Aktualisierung

search_ingestion Abschnitt

Name Beschreibung
search_background_indexing_status Status der Einnahme. NO_ACTIVITYbedeutet untätig. Andere Werte deuten darauf hin, dass sich Schlüssel im Prozess der Aufnahme befinden.
search_ingestion_paused Außer beim Neustart sollte dies immer „nein“ sein.

search_backfill Abschnitt

Anmerkung

Einige der in diesem Abschnitt dokumentierten Felder sind nur sichtbar, wenn gerade ein Backfill im Gange ist.

Name Beschreibung
search_num_active_backfills Anzahl der aktuellen Backfill-Aktivitäten
search_backfills_pausiert Außer wenn nicht genügend Speicher zur Verfügung steht, sollte dies immer „nein“ sein.
search_current_backfill_progress_percentage % Abschluss (0-100) der aktuellen Auffüllung

search_query Abschnitt

Name Beschreibung
search_num_active_queries Anzahl der Befehle und, die derzeit ausgeführt werden FT.SEARCH FT.AGGREGATE

Sicherheit bei der Vektorsuche

Die Sicherheitsmechanismen von Redis OSS ACL (Access Control Lists) sowohl für den Befehls- als auch für den Datenzugriff wurden erweitert, um die Suchfunktion zu kontrollieren. Die ACL-Steuerung einzelner Suchbefehle wird vollständig unterstützt. Eine neue ACL-Kategorie@search,, wird bereitgestellt, und viele der vorhandenen Kategorien (@fast@read,@write, usw.) wurden aktualisiert, um die neuen Befehle aufzunehmen. Suchbefehle ändern keine Schlüsseldaten, was bedeutet, dass die bestehende ACL-Maschinerie für den Schreibzugriff erhalten bleibt. Die Zugriffsregeln für HASH- und JSON-Operationen werden durch das Vorhandensein eines Indexes nicht verändert; auf diese Befehle wird weiterhin die normale Zugriffskontrolle auf Schlüsselebene angewendet.

Der Zugriff auf Suchbefehle mit einem Index wird ebenfalls über Redis OSS ACL gesteuert. Zugriffsprüfungen werden auf der Ebene des gesamten Indexes durchgeführt, nicht auf der Ebene pro Schlüssel. Das bedeutet, dass einem Benutzer nur dann Zugriff auf einen Index gewährt wird, wenn dieser Benutzer berechtigt ist, auf alle möglichen Schlüssel in der Schlüsselraumpräfixliste dieses Indexes zuzugreifen. Mit anderen Worten, der tatsächliche Inhalt eines Indexes steuert den Zugriff nicht. Vielmehr ist es der theoretische Inhalt eines Indexes, wie er in der Präfixliste definiert ist, der für die Sicherheitsüberprüfung verwendet wird. Es kann leicht sein, eine Situation zu erzeugen, in der ein Benutzer Lese- und/oder Schreibzugriff auf einen Schlüssel hat, aber nicht auf einen Index zugreifen kann, der diesen Schlüssel enthält. Beachten Sie, dass nur Lesezugriff auf den Schlüsselraum erforderlich ist, um einen Index zu erstellen oder zu verwenden — das Vorhandensein oder Fehlen von Schreibzugriff wird nicht berücksichtigt.

Weitere Informationen zur Verwendung von ACLs mit MemoryDB finden Sie unter Benutzer mit Access Control Lists (ACLs) authentifizieren.