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 Valkey- und 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 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.
Themen
Indizes und der OSS-Schlüsselraum von Valkey und Redis
Indizes werden über eine Teilmenge des OSS-Schlüsselraums Valkey und Redis erstellt und verwaltet. Bei mehreren Indizes können unzusammenhängende oder überlappende Teilmengen des 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 Indexerstellung bereitgestellt werden. Die Liste der Präfixe ist optional, und wenn sie weggelassen wird, ist der gesamte 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 Hintergrund-Thread und durchsucht den 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.
Vektorindex-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. DerEF_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 and/or degraded recall quality. Reindexing is one method for restoring optimal memory usage and/or beim Abrufen des Index-Speichers führen.
Ausdruck einer 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 einer booleschen Logik kombiniert werden: and/or. Parentheses can be used to group operators and/or Ändern Sie die Reihenfolge der Auswertung. 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“.
Vektor-Suche
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 diePARAM
Tabelle desFT.AGGREGATE
BefehlsFT.SEARCH
or an. Dieser Parameter ist der Referenzvektorwert für Entfernungsberechnungen. Der Wert des Vektors wird in denPARAM
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 die Befehle Valkey und Redis OSS INFOSEARCH
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 Aktualisierung des Aufnahme-Batches |
search_ingestion
Abschnitt
Name | Beschreibung |
---|---|
search_background_indexing_status | Status der Einnahme. NO_ACTIVITY bedeutet 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) des aktuellen Auffüllvorgangs |
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 ACL (Access Control Lists)@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 ACL gesteuert. Zugriffsprüfungen werden auf der Ebene des gesamten Indexes durchgeführt, nicht auf der Ebene einzelner 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 ACLs mit MemoryDB finden Sie unter Benutzer mit Zugriffskontrolllisten authentifizieren (). ACLs