Auf dieser Seite wird erläutert, wie Sie Spanner-Vektorindizes erstellen und verwalten. Dabei werden die ungefähre Suche nach dem nächsten Nachbarn (Approximate Nearest Neighbor, ANN) und baumbasierte Strukturen verwendet, um die Suche nach Vektorähnlichkeiten in Ihren Daten zu beschleunigen.
Spanner beschleunigt die ANN-Vektorsuche (Approximate Nearest Neighbor) mithilfe eines speziellen Vektorindex. Dieser Index nutzt den Scalable Nearest Neighbor (ScaNN) von Google Research, einen hocheffizienten Algorithmus für die Suche nach dem nächsten Nachbarn.
Der Vektorindex verwendet eine baumbasierte Struktur, um Daten zu partitionieren und schnellere Suchvorgänge zu ermöglichen. Spanner bietet sowohl zwei- als auch dreistufige Baumkonfigurationen:
- Zweistufige Baumkonfiguration: Blattknoten (
num_leaves) enthalten Gruppen eng verwandter Vektoren zusammen mit dem entsprechenden Schwerpunkt. Die Stammebene besteht aus den Schwerpunkten aller Blattknoten. - Dreistufige Baumkonfiguration: Ähnlich wie ein zweistufiger Baum, jedoch mit einer zusätzlichen Verzweigungsebene (
num_branches), von der aus die Schwerpunkte der Blattknoten weiter partitioniert werden, um die Stammebene (num_leaves) zu bilden.
Spanner wählt einen Index für Sie aus. Wenn Sie jedoch wissen, dass ein
bestimmter Index am besten funktioniert, können Sie mit dem FORCE_INDEX Hinweis
den am besten geeigneten Vektorindex für Ihren Anwendungsfall auswählen.
Weitere Informationen finden Sie unter
VECTOR INDEX Anweisungen für GoogleSQL
und INDEX Anweisungen für PostgreSQL.
Beschränkungen
- Vektorindizes können nicht vorab aufgeteilt werden. Weitere Informationen finden Sie unter Vorabaufteilung.
Vektorindex erstellen
So optimieren Sie die Trefferquote und Leistung eines Vektorindex:
Erstellen Sie den Vektorindex, nachdem die meisten Zeilen mit Einbettungen in Ihre Datenbank geschrieben wurden. Möglicherweise müssen Sie den Vektorindex auch regelmäßig neu erstellen, nachdem Sie neue Daten eingefügt haben. Weitere Informationen finden Sie unter Vektorindex neu erstellen.
Verwenden Sie für GoogleSQL die
STORINGKlausel und für PostgreSQL dieINCLUDEKlausel, um eine Kopie einer Spalte im Vektorindex zu speichern. Wenn ein Spaltenwert im Vektorindex gespeichert ist, führt Spanner die Filterung auf der Blattebene des Index aus, um die Abfrageleistung zu verbessern. Wir empfehlen, eine Spalte zu speichern, wenn sie in einer Filterbedingung verwendet wird.Verwenden Sie im Vektorindex Spalten mit Schlüsseln, die keine Einbettungen enthalten. Schlüsselspalten ähneln
STORING- oderINCLUDE-Spalten, ermöglichen es der Abfrage-Engine jedoch, die Filterung bei der Vektorsuche effizienter durchzuführen. Weitere Informationen finden Sie unter Vektorindex erstellen (GoogleSQL) oder Indexanweisungen (PostgreSQL).
Wenn Sie die Tabelle erstellen, muss die Einbettungsspalte ein Array des
FLOAT32 (GoogleSQL) oder float4[] (PostgreSQL) Datentyps sein (empfohlen) und eine
Anmerkung zur Vektorlänge (vector_length=>N für GoogleSQL oder VECTOR LENGTH N für PostgreSQL) enthalten,
die die Dimension der Vektoren angibt.
Die optimale Vektorlänge hängt von der Arbeitslast, der Datasetgröße und den verfügbaren Rechenressourcen ab. Testen Sie verschiedene Dimensionen, um die kleinste Größe zu finden, die die Genauigkeit und Leistung für Ihre Anwendung beibehält.
Mit der folgenden DDL-Anweisung wird eine Tabelle Documents mit einer Einbettungsspalte DocEmbedding mit einer Vektorlänge erstellt:
GoogleSQL
CREATE TABLE Documents (
UserId INT64 NOT NULL,
DocId INT64 NOT NULL,
Author STRING (1024),
DocContents Bytes(MAX),
DocEmbedding ARRAY<FLOAT32>(vector_length=>128) NOT NULL,
NullableDocEmbedding ARRAY<FLOAT32>(vector_length=>128),
WordCount INT64
) PRIMARY KEY (DocId);
PostgreSQL
CREATE TABLE documents (
user_id bigint not null,
doc_id bigint not null,
author varchar(1024),
doc_contents bytea,
doc_embedding float4[] VECTOR LENGTH 128 not null,
nullable_doc_embedding float4[] VECTOR LENGTH 128,
word_count bigint,
PRIMARY KEY (doc_id)
);
Nachdem Sie die Tabelle Documents gefüllt haben, können Sie einen Vektorindex mit einem zweistufigen Baum und 1.000 Blattknoten für die Tabelle Documents mit einer Einbettungsspalte DocEmbedding mit der Kosinusdistanz erstellen:
GoogleSQL
CREATE VECTOR INDEX DocEmbeddingIndex
ON Documents(DocEmbedding)
STORING (WordCount)
OPTIONS (distance_type = 'COSINE', tree_depth = 2, num_leaves = 1000);
PostgreSQL
CREATE INDEX doc_embedding_index
ON documents
USING scann(doc_embedding)
INCLUDE (word_count)
WITH (distance_type = 'COSINE', num_leaves = 1000)
WHERE doc_embedding IS NOT NULL;
Wenn die Einbettungsspalte in der Tabellendefinition nicht als NOT NULL gekennzeichnet ist, müssen Sie sie in der Vektorindexdefinition mit einer WHERE COLUMN_NAME IS NOT NULL Klausel deklarieren, wobei COLUMN_NAME der Name der Einbettungsspalte ist. So erstellen Sie einen Vektorindex mit einem dreistufigen Baum und 1.000.000 Blattknoten für die Einbettungsspalte NullableDocEmbedding, die NULL-Werte zulässt, mit der Kosinusdistanz:
GoogleSQL
CREATE VECTOR INDEX DocEmbeddingThreeLevelIndex
ON Documents(NullableDocEmbedding)
STORING (WordCount)
WHERE NullableDocEmbedding IS NOT NULL
OPTIONS (distance_type = 'COSINE', tree_depth = 3, num_branches=1000, num_leaves = 1000000);
PostgreSQL
CREATE INDEX doc_embedding_index
ON documents
USING scann(nullable_doc_embedding)
INCLUDE (word_count)
WITH (distance_type = 'COSINE', tree_depth = 3, num_branches = 1000, num_leaves = 1000000)
WHERE nullable_doc_embedding IS NOT NULL;
Vektorindex filtern
Sie können auch einen gefilterten Vektorindex erstellen, um die ähnlichsten Elemente in Ihrer Datenbank zu finden, die der Filterbedingung entsprechen. Ein gefilterter Vektorindex indexiert selektiv Zeilen, die die angegebenen Filterbedingungen erfüllen, wodurch die Suchleistung verbessert wird.
Im folgenden Beispiel hat die Tabelle Documents2 eine Spalte mit dem Namen Category.
Bei der Vektorsuche möchten wir die Kategorie „Tech“ indexieren. Daher erstellen wir eine generierte Spalte, die NULL ergibt, wenn die Kategoriebedingung nicht erfüllt ist.
GoogleSQL
CREATE TABLE Documents2 (
UserId INT64 NOT NULL,
DocId INT64 NOT NULL,
DocName STRING (1024),
Author STRING (1024),
DocContents Bytes(MAX),
Category STRING(MAX),
NullIfFiltered BOOL AS (IF(Category = 'Tech', TRUE, NULL)) HIDDEN,
DocEmbedding ARRAY<FLOAT32>(vector_length=>128)
) PRIMARY KEY (DocId);
PostgreSQL
CREATE TABLE documents2 (
user_id bigint not null,
doc_id bigint not null,
doc_name varchar(1024),
author varchar(1024),
doc_contents bytea,
category varchar,
null_if_filtered boolean GENERATED ALWAYS AS (CASE WHEN category = 'Tech' THEN true END) VIRTUAL HIDDEN,
doc_embedding float4[] VECTOR LENGTH 128,
PRIMARY KEY (doc_id)
);
Anschließend erstellen wir einen Vektorindex mit einem Filter. Der Vektorindex TechDocEmbeddingIndex indexiert nur Dokumente in der Kategorie „Tech“.
GoogleSQL
CREATE VECTOR INDEX TechDocEmbeddingIndex
ON Documents2(DocEmbedding)
STORING(NullIfFiltered)
WHERE DocEmbedding IS NOT NULL AND NullIfFiltered IS NOT NULL
OPTIONS (...);
PostgreSQL
CREATE INDEX tech_doc_embedding_index
ON documents2
USING scann(doc_embedding)
INCLUDE (null_if_filtered)
WITH (distance_type = 'COSINE', num_leaves = 1000)
WHERE doc_embedding IS NOT NULL AND null_if_filtered IS NOT NULL;
Wenn Spanner die folgende Abfrage ausführt, die Filter enthält, die mit TechDocEmbeddingIndex übereinstimmen, wird TechDocEmbeddingIndex automatisch ausgewählt und beschleunigt. Die Abfrage durchsucht nur Dokumente in der Kategorie „Tech“. Sie können auch den Hinweis FORCE_INDEX verwenden (@{FORCE_INDEX=TechDocEmbeddingIndex} für GoogleSQL oder /*@ FORCE_INDEX = tech_doc_embedding_index */ für PostgreSQL), um Spanner explizit zur Verwendung des Index zu zwingen.
GoogleSQL
SELECT *
FROM Documents2
WHERE DocEmbedding IS NOT NULL AND NullIfFiltered IS NOT NULL
ORDER BY APPROX_(....)
LIMIT 10;
PostgreSQL
SELECT *
FROM documents2
WHERE doc_embedding IS NOT NULL AND null_if_filtered IS NOT NULL
ORDER BY spanner.approx_cosine_distance(doc_embedding, ARRAY[1.0::float4, 2.0::float4, 3.0::float4])
LIMIT 10;
Um die Abfrageleistung zu verbessern, können Sie Spalten mit Schlüsseln, die keine Einbettungen enthalten, in den Vektorindex aufnehmen. Dadurch kann die Abfrage-Engine die Filterung bei der Vektorsuche effizienter durchführen.
In der Anweisung zur Indexerstellung müssen Sie diese zusätzlichen Schlüsselspalten nach der Einbettungsspalte auflisten. Mit der folgenden Anweisung wird beispielsweise ein Vektorindex erstellt, der die Schlüsselspalten DocName und Author für eine effizientere Filterung enthält:
GoogleSQL
CREATE VECTOR INDEX DocEmbeddingIndexWithKeys
ON Documents2(DocEmbedding, DocName, Author)
STORING(NullIfFiltered)
WHERE DocEmbedding IS NOT NULL AND NullIfFiltered IS NOT NULL
OPTIONS (...);
PostgreSQL
CREATE INDEX doc_embedding_index_with_keys
ON documents2
USING scann(doc_embedding, doc_name, author)
INCLUDE (null_if_filtered)
WITH (distance_type = 'COSINE', num_leaves = 1000)
WHERE doc_embedding IS NOT NULL AND null_if_filtered IS NOT NULL;
Nächste Schritte
Weitere Informationen zu ungefähren nächsten Nachbarn in Spanner .
Weitere Informationen zu den Funktionen für ungefähre Distanzen in GoogleSQL und PostgreSQL.
Weitere Informationen zu Indexanweisungen für GoogleSQL
VECTOR INDEXund PostgreSQLINDEX.Weitere Informationen zu Best Practices für Vektorindizes.