# Vektorsuche

Die Vektorsuche ist eine Suchmethode, bei der Daten als Vektoren dargestellt werden. Sie wird häufig in Anwendungen wie der Bildersuche, Videosuche und Textsuche verwendet, sowie in maschinellen Lernanwendungen wie der Bildklassifizierung und Clusterbildung.

In diesem Abschnitt wird erläutert, wie man Vektorindizes erstellt und manipuliert, um die Vektorsuche zu beschleunigen, sowie wie man verschiedene Arten von Vektorindizes konfiguriert.

# Befehlsreferenz

# Erstellen einer Tabelle mit Vektoren

In MyScale stellen wir Einbettungsvektoren als Datentyp Array dar und derzeit werden nur float32-Arrays (Array(Float32)) unterstützt. Beachten Sie, dass alle Arrays einer Einbettungsvektor-Spalte die gleiche Länge haben müssen. Verwenden Sie CONSTRAINT, um Fehler zu vermeiden. Zum Beispiel CONSTRAINT constraint_name_1 CHECK length(data) = 256.

Folgendes ist ein Beispiel für die Erstellung einer Tabelle für Vektordaten:

CREATE TABLE test_vector
(
    id    UInt32,
    data  Array(Float32),
    CONSTRAINT check_length CHECK length(data) = 128,
    date  Date,
    label Enum8('person' = 1, 'building' = 2, 'animal' = 3)
) ENGINE = MergeTree ORDER BY id

Beachten Sie, dass die Namen der Datentypen Groß- und Kleinschreibung beachten und ein Fehler zurückgegeben wird, wenn die Groß- und Kleinschreibung nicht korrekt ist.

# Erstellen eines Vektorindex

Ein Vektorindex muss erstellt werden, bevor eine Vektorsuche durchgeführt werden kann. Die Syntax zum Erstellen eines Vektorindex lautet wie folgt:

ALTER TABLE [db.]table_name
ADD VECTOR INDEX index_name column_name
TYPE index_type
(
  'param1 = value1',
  'param2 = value2',
  ...
)
  • index_name: der Name des Vektorindex.
  • column_name: der Name der Spalte, auf der der Vektorindex erstellt werden soll. Diese Spalte muss vom Typ Array(Float32) sein und eine Einschränkung haben, die die Länge des Arrays angibt.
  • index_type: der spezifische Typ des Vektorindex. Derzeit empfehlen wir dringend die Verwendung des MSTG-Algorithmus für optimale Ergebnisse. Es gibt jedoch auch andere verfügbare Indextypen wie FLAT (der Brute-Force-Algorithmus für den Vergleich), die IVF-Familie (einschließlich IVFFLAT, IVFSQ und IVFPQ) und die HNSW-Familie (einschließlich HNSWFLAT, HNSWSQ und HNSWPQ).

Um beispielsweise einen Vektorindex mit dem Namen idx vom Typ MSTG für die Spalte vector in der Tabelle test_vector zu erstellen, verwenden Sie den folgenden Befehl:

ALTER TABLE test_vector ADD VECTOR INDEX idx vector TYPE MSTG

Für detaillierte Informationen zu Parametern für bestimmte Typen siehe den Abschnitt Erklärung der Konfigurationsoptionen für Vektorindizes. Für Vorschläge zur Leistungsoptimierung siehe den Abschnitt Ratschläge zur Leistungsoptimierung.

# Löschen eines Vektorindex

Die folgende Syntax kann verwendet werden, um einen Vektorindex zu löschen. Dadurch wird der Index entfernt und die damit verbundenen Speicher- und Festplattenressourcen freigegeben. Wenn der Index derzeit erstellt wird, wird der Erstellungsprozess ebenfalls sofort gestoppt.

ALTER TABLE [db.]table_name DROP VECTOR INDEX index_name

# Überprüfen des Status von Vektorindizes

Um den aktuellen Status von Vektorindizes anzuzeigen, können Sie die Tabelle system.vector_indices verwenden. Die folgende Syntax ermöglicht es Ihnen, alle vorhandenen Vektorindizes anzuzeigen:

SELECT * FROM system.vector_indices

Sie können eine WHERE-Klausel verwenden, um die Ergebnisse nach Tabellennamen oder anderen Kriterien zu filtern. Um beispielsweise die Vektorindizes für eine bestimmte Tabelle wie test_vector anzuzeigen, können Sie den folgenden Befehl verwenden:

SELECT table, name, status FROM system.vector_indices
WHERE table = 'test_vector'

Dies gibt Informationen über den Vektorindex aus, einschließlich seines aktuellen Status, der einer der folgenden sein kann:

  1. Built: Dieser Status gibt an, dass der Index erfolgreich erstellt wurde und einsatzbereit ist.
  2. InProgress: Dieser Status bedeutet, dass der Index derzeit erstellt oder aktualisiert wird. Während dieser Zeit kann der Index unvollständig sein und die Vektorsuche auf Daten, die nicht indiziert wurden, wird auf den Brute-Force-Algorithmus zurückfallen, der viel langsamer ist.
  3. Error: Wenn der Index während des Aufbaus oder der Verwendung einen Fehler aufweist, wechselt er in den Status Error. Dies kann verschiedene Gründe haben, wie ungültige Eingabedaten oder Systemfehler. Wenn der Index sich in diesem Status befindet, ist er in der Regel nicht verfügbar, bis der Fehler behoben ist.

Für Vektorindizes im Status Error können Sie die Fehlergründe mit dem folgenden Befehl anzeigen:

SELECT table, name, latest_failed_part, latest_fail_reason
FROM system.vector_indices WHERE status = 'Error'

# Grundlegende Vektorsuche

Die Funktion distance() wird verwendet, um Vektorsuchen in MyScale durchzuführen. Sie berechnet den Abstand zwischen einem angegebenen Vektor und allen Vektordaten in einer angegebenen Spalte und gibt die besten Kandidaten zurück. Die grundlegende Syntax für die Funktion distance() lautet wie folgt:

distance('param1 = value1', 'param2 = value2')(column_name, query_vector)
  • params repräsentiert suchspezifische Parameter. params kann auch indexspezifische Parameter enthalten, wie z.B. nprobe = 1 für den IVFFLAT-Vektorindex, um den Suchbereich festzulegen.
  • column_name bezieht sich auf die Spalte, die die zu durchsuchenden Vektordaten enthält.
  • query_vector ist der zu suchende Vektor, zum Beispiel ein 128D-Vektor im Format [3.0, 9, ..., 4]. Es ist wichtig, einen Dezimalpunkt im Abfragevektor einzuschließen, um zu verhindern, dass er als Typ Array(UInt64) erkannt wird, was zu einem Fehler bei der Ausführung der Abfrage führen würde.

Hinweise:

  • Die Funktion distance() sollte mit ORDER BY und LIMIT-Klausel verwendet werden, um die besten Kandidaten zu erhalten.
  • Die Sortierrichtungen der Spalte der distance()-Funktion in der ORDER BY-Klausel müssen den Metriktypen (Cosinus, IP usw.) des Vektorindex entsprechen, sonst wird ein Fehler gemeldet. Wenn der Metriktyp IP ist, muss die Sortierrichtung DESC sein.

Eine typische Vektorsuchanfrage würde wie folgt aussehen:

SELECT id, date, label,
  distance(data, [3.0, 9, 45, 22, 28, 11, 4, 3, 77, 10, 4, 1, 1, 4, 3, 11, 23, 0, 0, 0, 26, 49, 6, 7, 5, 3, 3, 1, 11, 50, 8, 9, 11, 7, 15, 21, 12, 17, 21, 25, 121, 12, 4, 7, 4, 7, 4, 41, 28, 2, 0, 1, 10, 42, 22, 20, 1, 1, 4, 9, 31, 79, 16, 3, 23, 4, 6, 26, 31, 121, 87, 40, 121, 82, 16, 12, 15, 41, 6, 10, 76, 48, 5, 3, 21, 42, 41, 50, 5, 17, 18, 64, 86, 54, 17, 6, 43, 62, 56, 84, 116, 108, 38, 26, 58, 63, 20, 87, 105, 37, 2, 2, 121, 121, 38, 25, 44, 33, 24, 46, 3, 16, 27, 74, 121, 55, 9, 4]) AS dist
FROM test_vector
ORDER BY dist LIMIT 10

Diese Abfrage gibt die id, date, label und den Abstand zwischen der Vektor-Spalte und dem Abfragevektor [3.0, 9, ..., 4] aus der Tabelle test_vector zurück. Die Klausel ORDER BY dist LIMIT 10 gibt an, dass die 10 nächsten Ergebnisse zurückgegeben werden sollen.

Ausgabe:

id date label dist
3 "2024-08-11" "animal" 0
790110 "2001-10-14" "person" 102904
396372 "1987-12-15" "animal" 108579
401952 "1975-08-24" "animal" 117388
603558 "1999-09-26" "animal" 118487
25589 "1978-08-29" "animal" 119259
12632 "2019-02-25" "animal" 119662
800289 "2000-07-09" "building" 119673
16298 "1997-03-11" "animal" 120011
395903 "2020-08-19" "animal" 121352

Das Abfrageergebnis ist eine Tabelle mit drei Spalten: id, date, label und dist, die die ID des Vektors, das Datum, das Label und den Abstand zwischen den besten Vektorergebnissen und dem Abfragevektor zeigt.

# Vektorsuche mit Filtern

Die Vektorsuche mit Filtern ermöglicht es Ihnen, die Ergebnisse basierend auf Werten aus anderen Spalten oder Abstandswerten einzuschränken. Zum Beispiel liefert die folgende Abfrage die ID, den Vektor und den Abstand zwischen der Vektor-Spalte und dem Abfragevektor [3.0, 9, ..., 4] aus der Tabelle test_vector, aber nur für Zeilen, bei denen die ID-Spalte größer als 100000 ist:

SELECT id, date, label,
  distance(data, [3.0, 9, 45, 22, 28, 11, 4, 3, 77, 10, 4, 1, 1, 4, 3, 11, 23, 0, 0, 0, 26, 49, 6, 7, 5, 3, 3, 1, 11, 50, 8, 9, 11, 7, 15, 21, 12, 17, 21, 25, 121, 12, 4, 7, 4, 7, 4, 41, 28, 2, 0, 1, 10, 42, 22, 20, 1, 1, 4, 9, 31, 79, 16, 3, 23, 4, 6, 26, 31, 121, 87, 40, 121, 82, 16, 12, 15, 41, 6, 10, 76, 48, 5, 3, 21, 42, 41, 50, 5, 17, 18, 64, 86, 54, 17, 6, 43, 62, 56, 84, 116, 108, 38, 26, 58, 63, 20, 87, 105, 37, 2, 2, 121, 121, 38, 25, 44, 33, 24, 46, 3, 16, 27, 74, 121, 55, 9, 4]) AS dist
FROM test_vector WHERE id > 100000
ORDER BY dist LIMIT 10

Ausgabe:

id date label dist
790110 "2001-10-14" "person" 102904
396372 "1987-12-15" "animal" 108579
401952 "1975-08-24" "animal" 117388
603558 "1999-09-26" "animal" 118487
800289 "2000-07-09" "building" 119673
395903 "2020-08-19" "animal" 121352
600737 "1972-08-25" "animal" 125027
790101 "1990-02-22" "person" 129224
790265 "2019-05-26" "building" 133267
198290 "1974-04-22" "building" 134178

Um nach distance-Werten zu filtern, verwenden Sie die WHERE-Klausel wie folgt:

SELECT id, date, label,
  distance(data, [3.0, 9, 45, 22, 28, 11, 4, 3, 77, 10, 4, 1, 1, 4, 3, 11, 23, 0, 0, 0, 26, 49, 6, 7, 5, 3, 3, 1, 11, 50, 8, 9, 11, 7, 15, 21, 12, 17, 21, 25, 121, 12, 4, 7, 4, 7, 4, 41, 28, 2, 0, 1, 10, 42, 22, 20, 1, 1, 4, 9, 31, 79, 16, 3, 23, 4, 6, 26, 31, 121, 87, 40, 121, 82, 16, 12, 15, 41, 6, 10, 76, 48, 5, 3, 21, 42, 41, 50, 5, 17, 18, 64, 86, 54, 17, 6, 43, 62, 56, 84, 116, 108, 38, 26, 58, 63, 20, 87, 105, 37, 2, 2, 121, 121, 38, 25, 44, 33, 24, 46, 3, 16, 27, 74, 121, 55, 9, 4]) AS dist
FROM test_vector WHERE dist < 110000
ORDER BY dist LIMIT 10

Diese Abfrage gibt die ID, das Datum, das Label und den Abstand zwischen der Vektor-Spalte und dem Abfragevektor [3.0, 9, ..., 4] aus der Tabelle test_vector zurück, aber nur für Zeilen, bei denen der Abstand kleiner als 110000 ist.

Ausgabe:

id date label dist
3 "2024-08-11" "animal" 0
790110 "2001-10-14" "person" 102904
396372 "1987-12-15" "animal" 108579

# Erklärung der Konfigurationsoptionen für Vektorindexe

Vektorindexe haben zwei Arten von Parametern: Indexerstellungparameter und Suchparameter.

Indexerstellungparameter werden bei der Indexerstellung angegeben, zum Beispiel

ALTER TABLE [db.]table_name
ADD VECTOR INDEX index_name column_name
TYPE index_type
(
  'creation_param1 = value1',
  'creation_param2 = value2',
  ...
)

Suchparameter werden während der Suche angegeben, zum Beispiel

SELECT
  id,
  distance('search_param1 = value1', 'search_param2 = value2')(column_name, query_vector) as dist
FROM test_vector
ORDER BY dist LIMIT 10

# Allgemeine Parameter zur Indexerstellung

Die folgenden Parameter können bei der Erstellung eines beliebigen Vektorindexes verwendet werden:

  • metric_type = L2|Cosine|IP: Dieser Parameter bestimmt die Distanzmetrik, die bei der Vektorsuche verwendet wird. Es stehen drei Optionen zur Verfügung:

    • L2: die L2-Metrik, auch als euklidische Distanz bekannt.
    • Cosine: die Kosinus-Distanz, die auf der Kosinus-Ähnlichkeit basiert. Die Formel für die Kosinus-Distanz lautet:

      Die Kosinus-Ähnlichkeit kann durch Subtrahieren des Distanzwerts von 1 erhalten werden.
    • IP: Die Innenprodukt (IP)-Metrik. Beachten Sie, dass bei Verwendung der IP-Metrik ORDER BY ... DESC verwendet werden muss, da höhere IP-Werte eine größere Ähnlichkeit anzeigen.

    Der Standardwert ist L2.

# MSTG-Parameter

Der Multi-Scale Tree Graph (MSTG)-Algorithmus, entwickelt von MyScale, ist eine proprietäre Lösung, die eine hohe Datendichte und hohe Leistung für Standard- und gefilterte Vektorsuchoperationen bietet.

Parameter zur Indexerstellung:

MSTG nimmt während der Indexerstellung keine anderen Parameter als den oben beschriebenen metric_type an.

Suchparameter:

  • alpha = float: Dieser Parameter steuert die Genauigkeit der Suchoperation. Je höher der Wert, desto genauer die Suche, aber desto geringer die QPS. Der Standardwert ist 3, und der gültige Bereich liegt zwischen 1 und 4.

# FLAT-Parameter

FLAT ist die einfachste Form der Vektorindizierung, bei der die Distanzen basierend auf den Rohdaten ohne zusätzliche Optimierungsparameter direkt berechnet werden. Es eignet sich für Prototyping und zur Sicherstellung der Genauigkeit der Suchergebnisse, wird jedoch aufgrund seiner relativ langsamen Leistung nicht für den Produktionsbetrieb empfohlen.

# IVFFLAT-Parameter

IVFFLAT ist ein hierarchischer Index, der Clustering verwendet, um Vektoren in kleinere Cluster aufzuteilen und effizientere Suchen zu ermöglichen.

Parameter zur Indexerstellung:

  • ncentroids = int: Bestimmt die Anzahl der Cluster, in die alle Vektordaten aufgeteilt werden. Größere Werte von ncentroids führen zu längeren Aufbauzeiten der Tabelle. Der Standardwert ist 1024.

Suchparameter:

  • nprobe = int: Gibt die Anzahl der Cluster an, die während einer Suchoperation durchsucht werden sollen. Größere Werte führen zu langsameren Suchen, aber größerer Genauigkeit. Der Standardwert ist 1.

Empfohlene Parameterwerte:

Es wird empfohlen, einen Wert zwischen 1000 und 10000 für ncentroids zu wählen, wobei Werte in der Nähe der Quadratwurzel der Datenmenge bevorzugt werden. Wenn ncentroids zu groß ist, kann dies die Leistung beeinträchtigen. Ein Wert zwischen 0,1% und 10% von ncentroids wird für nprobe vorgeschlagen.

# IVFPQ-Parameter

Parameter zur Indexerstellung:

  • ncentroids = int: Siehe IVFFLAT.

  • M = int: Reduziert die ursprüngliche Vektordimension auf M. M muss durch die ursprüngliche Vektordimension teilbar sein. Der Standardwert ist 16.

  • bit_size = int: Bezieht sich auf die Größe der zur Ersetzung des ursprünglichen Vektors verwendeten Product Quantization (PQ)-Codierungstabelle. Gültige Werte sind Vielfache von 4, mit einem Standardwert von 8.

Suchparameter:

Empfohlene Parameterwerte:

Die empfohlenen Werte für ncentroids und nprobe sind ähnlich wie bei IVFFLAT. Es ist wichtig zu beachten, dass das Kompressionsverhältnis von PQ wie folgt berechnet wird: (bit_size * M) / (original_dimension * original_element_size). Für einen 128-dimensionalen Float32-Vektor beträgt das Kompressionsverhältnis bei M = 16 und bit_size = 8 entsprechend (16*8)/(128*32) = 1/32. Übermäßig hohe Kompressionsverhältnisse können die Genauigkeit der Suchergebnisse erheblich beeinträchtigen, daher wird empfohlen, bit_size auf 8 und M innerhalb von 1/4 der ursprünglichen Dimension zu halten, um dieses Problem zu vermeiden.

# IVFSQ Parameter

Parameter zur Indexerstellung:

  • ncentroids = int: Siehe IVFFlat.

  • bit_size = string: Zulässige Werte sind 8bit, 6bit, 4bit, 8bit_uniform, 8bit_direct, 4bit_uniform und QT_fp16 mit einem Standardwert von 8bit.

Der Scalar Quantization (SQ) Algorithmus wird verwendet, um jede Vektordimension zu komprimieren, während die Anzahl der Dimensionen beibehalten wird. Wenn bit_size auf 8 gesetzt ist, beträgt die Kompressionsrate etwa 25%. Die Präzision des Algorithmus nimmt in der Reihenfolge 8bit_direct, 8bit_uniform und 8bit zu, aber die Geschwindigkeit des Indexaufbaus ist umgekehrt proportional zur Präzision. 8bit_direct konvertiert float in uint_8 mit static_cast, 8bit_uniform teilt alle float-Werte gleichmäßig in 256 Bins auf und 8bit teilt jede Dimension gleichmäßig in 256 Bins auf. 4bit_uniform teilt und quantisiert Daten in 16 Bins auf. QT_fp16 ist eine Variation des SQ-Algorithmus, der halbgenaue Gleitkommazahlen verwendet, und weitere Details finden Sie unter dem Link https://gist.github.com/rygorous/2156668 (opens new window).

Parameter zur Suche:

# HNSWFLAT Parameter

Der Hierarchical Navigable Small World (HNSW) Algorithmus ist ein Typ von Approximate Nearest Neighbor Search Algorithmus, der entwickelt wurde, um die nächsten Nachbarn eines gegebenen Abfragepunkts in einem hochdimensionalen Raum schnell zu finden. Dies geschieht durch die Organisation der Datenpunkte in einer mehrstufigen Graphen-Datenstruktur. Der HNSW-Algorithmus verwendet das Prinzip der "Small World"-Netzwerke, bei denen die meisten Knoten nur wenige Schritte voneinander entfernt sind, um den Graphen zu navigieren und effizient die nächsten Datenpunkte zum Abfragepunkt zu finden. Er ist bekannt für seine hohe Leistung und Skalierbarkeit bei großen Datensätzen und hochdimensionalem Raum.

Parameter zur Indexerstellung:

  • m = int: Dieser Parameter bestimmt die Anzahl der Nachbarn jedes Datenpunkts im HNSW-Diagramm und beeinflusst die Qualität des Indexes. Ein größeres m führt zu einer höheren Genauigkeit der Suchergebnisse, erhöht jedoch auch die Zeit, die für den Aufbau des Indexes benötigt wird. Standardwert ist 16.
  • ef_c = int: Dieser Parameter bestimmt die Größe der Prioritätswarteschlange, die von HNSW beim Erstellen des Indexes verwendet wird, und beeinflusst die Qualität des Indexes. Ein größeres ef_c führt zu einer höheren Präzision der Suchergebnisse, erhöht jedoch auch die Zeit, die für den Aufbau des Indexes benötigt wird. Standardwert ist 100.

Parameter zur Suche:

  • ef_s = int: Dieser Parameter bestimmt die Größe der Prioritätswarteschlange, die von HNSW während der Suchoperation verwendet wird. Ein größeres ef_s führt zu einer höheren Präzision der Suchergebnisse, erhöht jedoch auch die Suchzeit. Standardwert ist 50.

Empfohlene Parameterwerte:

Es wird im Allgemeinen empfohlen, m zwischen 8-128 und ef_c zwischen 50-400 einzustellen. Das Verdoppeln von ef_c führt ungefähr zu einer Verdopplung der Zeit für den Indexaufbau. Der Wert von ef_s sollte entsprechend den Suchanforderungen angepasst werden, und es wird empfohlen, den gleichen Wertebereich wie ef_c zu verwenden. Ein niedrigerer Wert kann gewählt werden, wenn eine geringe Latenzanforderung erforderlich ist.

# HNSWSQ Parameter

Parameter zur Indexerstellung:

Parameter zur Suche:

Empfohlene Parameterwerte:

Siehe IVFSQ für die Auswahl von bit_size und HNSWFLAT für den Rest.

# Ratschläge zur Leistungsoptimierung

Im Allgemeinen empfehlen wir die Verwendung des MSTG-Index und der Standardwerte für die Indexerstellung, um die Leistung zu optimieren. Bei der Suche können Sie den Wert alpha je nach gewünschter Durchsatz und Genauigkeit anpassen.

In MyScale wird die Daten automatisch in mehrere Teile aufgeteilt, und intern wird für jeden Teil ein Vektorindex erstellt. Für optimale Leistung empfehlen wir, die Tabelle vor der Erstellung des Vektorindex in einen Datenpart zu optimieren. Sie können den folgenden Befehl verwenden, um eine Tabelle zu optimieren:

OPTIMIZE TABLE test_vector FINAL

Daher lautet die empfohlene Reihenfolge der Operationen:

  1. Tabelle mit CREATE TABLE ... erstellen;
  2. Daten mit INSERT INTO ... einfügen;
  3. Tabelle optimieren;
  4. Vektorindex mit ALTER TABLE ... ADD VECTOR INDEX erstellen;
  5. Warten, bis der Vektorindex erstellt ist;
  6. Mit der Suche beginnen.

Es ist wichtig zu beachten, dass das Optimieren einer Tabelle nach der Indexerstellung viel Speicher verbrauchen kann. Bitte optimieren Sie daher eine Tabelle nicht nach der Indexerstellung.