Vektorindexe verwalten

In diesem Dokument wird beschrieben, wie Sie Vektorindexe erstellen und verwalten, um Ihre Vektorsuchen zu beschleunigen.

Ein Vektorindex ist eine Datenstruktur, die die effizientere Ausführung der Funktion VECTOR_SEARCH ermöglicht, insbesondere bei großen Datasets. Bei Verwendung eines Index nutzt VECTOR_SEARCH ANN-Algorithmen (Approximate Nearest Neighbor), um die Abfragelatenz und die Rechenkosten zu reduzieren. ANN führt zwar zu einer gewissen Annäherung, was bedeutet, dass die Trefferquote möglicherweise nicht 100 % beträgt. Die Leistungssteigerungen bieten jedoch in der Regel einen Vorteil für die meisten Anwendungen.

Rollen und Berechtigungen

Zum Erstellen eines Vektorindex benötigen Sie die IAM-Berechtigung bigquery.tables.createIndex für die Tabelle, in der Sie den Index erstellen. Zum Löschen eines Vektorindex benötigen Sie die Berechtigung bigquery.tables.deleteIndex. Jede der folgenden vordefinierten IAM-Rollen enthält die Berechtigungen, die Sie benötigen, um mit Vektorindexen zu arbeiten:

  • BigQuery Dateninhaber (roles/bigquery.dataOwner)
  • BigQuery Datenmitbearbeiter (roles/bigquery.dataEditor)

Vektorindex-Typ auswählen

BigQuery bietet zwei Vektorindex-Typen: IVF und TreeAH. Jeder unterstützt unterschiedliche Anwendungsfälle. BigQuery unterstützt das Batching für die Vektorsuche, indem mehrere Zeilen der Eingabedaten in der Funktion VECTOR_SEARCH verarbeitet werden. Für kleine Abfrage-Batches werden IVF-Indizes bevorzugt. Für große Abfrage-Batches werden TreeAH-Indizes bevorzugt, die mit dem ScaNN-Algorithmus von Google erstellt werden.

IVF-Index

IVF ist ein invertierter Dateiindex, der einen k-Means-Algorithmus verwendet, um die Vektordaten zu clustern und dann die Vektordaten basierend auf diesen Clustern zu partitionieren. Die VECTOR_SEARCH-Funktion kann diese Partitionen verwenden, um die Datenmenge zu reduzieren, die zum Ermitteln eines Ergebnisses gelesen werden muss.

TreeAH-Index

Der TreeAH-Indextyp hat seinen Namen von der Kombination aus einer baumartigen Struktur und der Verwendung von asymmetrischem Hashing (Asymmetric Hashing, AH), einer wichtigen Quantisierungstechnik des zugrunde liegenden ScaNN-Algorithmus. Ein TreeAH-Index funktioniert so:

  1. Die Basistabelle wird in kleinere, besser verwaltbare Shards unterteilt.
  2. Ein Clustering-Modell wird trainiert. Die Anzahl der Cluster wird aus der Option leaf_node_embedding_count im Argument tree_ah_options der Anweisung CREATE VECTOR INDEX abgeleitet.
  3. Die Vektoren werden mit der Produktquantisierung komprimiert, einer Technik, die den Speicherbedarf reduziert. Die komprimierten Vektoren werden dann anstelle der Originalvektoren in den Indextabellen gespeichert, wodurch die Größe der Vektorindexe reduziert wird.
  4. Wenn die VECTOR_SEARCH-Funktion ausgeführt wird, wird für jeden Anfragevektor mithilfe von asymmetrischem Hashing effizient eine Kandidatenliste berechnet. Diese Methode ist hardwareoptimiert für ungefähre Entfernungsberechnungen. Diese Kandidaten werden dann mit genauen Einbettungen neu bewertet und neu eingestuft.

Der TreeAH-Algorithmus ist für Batchabfragen optimiert, bei denen Hunderte oder mehr Anfragevektoren verarbeitet werden. Durch die Verwendung der Produktquantisierung können Latenz und Kosten erheblich gesenkt werden, möglicherweise um Größenordnungen im Vergleich zu IVF. Aufgrund des erhöhten Overheads ist der IVF-Algorithmus jedoch möglicherweise besser geeignet, wenn Sie eine kleinere Anzahl von Abfragevektoren haben.

Wir empfehlen den Index-Typ „TreeAH“, wenn Ihr Anwendungsfall die folgenden Kriterien erfüllt:

  • Ihre Tabelle enthält maximal 200 Millionen Zeilen.

  • Sie führen häufig große Batchabfragen mit Hunderten oder mehr Abfragevektoren aus.

Bei Anfragen mit kleinen Batches und dem TreeAH-Indextyp kann VECTOR_SEARCH auf die Brute-Force-Suche zurückgreifen. In diesem Fall wird ein IndexUnusedReason angegeben, um zu erklären, warum der Vektorindex nicht verwendet wurde.

IVF-Vektorindex erstellen

Verwenden Sie zum Erstellen eines IVF-Vektorindex die Datendefinitionssprachen-Anweisung (DDL) CREATE VECTOR INDEX:

  1. Rufen Sie die Seite BigQuery auf.

    BigQuery aufrufen

  2. Führen Sie im Abfrageeditor folgende SQL-Anweisung aus:

    So erstellen Sie einen IVF-Vektorindex:

    CREATE [ OR REPLACE ] VECTOR INDEX [ IF NOT EXISTS ] INDEX_NAME
    ON DATASET_NAME.TABLE_NAME(COLUMN_NAME)
    STORING(STORED_COLUMN_NAME [, ...])
    OPTIONS(index_type = 'IVF',
      distance_type = 'DISTANCE_TYPE',
      ivf_options = '{"num_lists":NUM_LISTS}')

    Ersetzen Sie Folgendes:

    • INDEX_NAME: Der Name des Vektorindex, den Sie erstellen. Da der Index immer im selben Projekt und Dataset wie die Basistabelle erstellt wird, müssen Sie Projekt und Dataset nicht im Namen angeben.
    • DATASET_NAME: der Name des Datasets, das die Tabelle enthält.
    • TABLE_NAME: der Name der Tabelle, die die Spalte mit Einbettungsdaten enthält.
    • COLUMN_NAME: Der Name einer Spalte, die die Einbettungsdaten enthält. Die Spalte muss den Typ ARRAY<FLOAT64> haben. Die Spalte darf keine untergeordneten Felder haben. Alle Elemente im Array dürfen nicht NULL sein und alle Werte in der Spalte müssen dieselben Array-Dimensionen haben.
    • STORED_COLUMN_NAME: Der Name einer Spalte der obersten Ebene in der Tabelle, die im Vektorindex gespeichert werden soll. Der Spaltentyp darf nicht RANGE sein. Gespeicherte Spalten werden nicht verwendet, wenn die Tabelle eine Zugriffsrichtlinie auf Zeilenebene oder die Spalte ein Richtlinien-Tag hat. Informationen zum Aktivieren gespeicherter Spalten finden Sie unter Spalten speichern und vorfiltern.
    • DISTANCE_TYPE: Gibt den Standarddistanztyp an, der bei der Vektorsuche mit diesem Index verwendet werden soll. Die unterstützten Werte sind EUCLIDEAN, COSINE und DOT_PRODUCT. Standardmäßig ist EUCLIDEAN ausgewählt.

      Für das Erstellen des Index wird immer die EUCLIDEAN-Distanz für das Training verwendet. Die Distanz, die in der VECTOR_SEARCH-Funktion verwendet wird, kann jedoch unterschiedlich sein.

      Wenn Sie einen Wert für das Argument distance_type der Funktion VECTOR_SEARCH angeben, wird dieser Wert anstelle des Werts DISTANCE_TYPE verwendet.

    • NUM_LISTS: ein INT64-Wert, der die Anzahl der Listen angibt, in die der IVF-Index Ihre Vektordaten clustert und partitioniert. Dieser Wert muss kleiner oder gleich 5.000 sein. Bei der Indexierung werden Vektoren der Liste zugewiesen, die dem Schwerpunkt des nächstgelegenen Clusters entspricht. Wenn Sie dieses Argument weglassen, bestimmt BigQuery einen Standardwert basierend auf den Eigenschaften Ihrer Daten. Der Standardwert ist für die meisten Anwendungsfälle geeignet.

      Mit NUM_LISTS wird der Detaillierungsgrad der Anfrageoptimierung gesteuert. Höhere Werte führen zu mehr Listen. Sie können die Option fraction_lists_to_search der Funktion VECTOR_SEARCH so festlegen, dass ein kleinerer Prozentsatz des Index gescannt wird. Beispiel: 1% von 100 Listen scannen statt 10% von 10 Listen. So lässt sich die Suchgeschwindigkeit und der Recall besser steuern, die Indexierungskosten steigen jedoch leicht. Legen Sie diesen Argumentwert entsprechend der Genauigkeit fest, mit der Sie den Abfragebereich anpassen müssen.

Im folgenden Beispiel wird ein Vektorindex für die Spalte embedding von my_table erstellt:

CREATE TABLE my_dataset.my_table(embedding ARRAY<FLOAT64>);

CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding)
OPTIONS(index_type = 'IVF');

Im folgenden Beispiel wird ein Vektorindex für die Spalte embedding von my_table erstellt. Außerdem werden der zu verwendende Distanztyp und die IVF-Optionen angegeben:

CREATE TABLE my_dataset.my_table(embedding ARRAY<FLOAT64>);

CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding)
OPTIONS(index_type = 'IVF', distance_type = 'COSINE',
ivf_options = '{"num_lists": 2500}')

TreeAH-Vektorindex erstellen

Verwenden Sie zum Erstellen eines TreeAH-Vektorindex die Datendefinitionssprachen-Anweisung (DDL) CREATE VECTOR INDEX:

  1. Rufen Sie die Seite BigQuery auf.

    BigQuery aufrufen

  2. Führen Sie im Abfrageeditor folgende SQL-Anweisung aus:

    CREATE [ OR REPLACE ] VECTOR INDEX [ IF NOT EXISTS ] INDEX_NAME
    ON DATASET_NAME.TABLE_NAME(COLUMN_NAME)
    STORING(STORED_COLUMN_NAME [, ...])
    OPTIONS(index_type = 'TREE_AH',
      distance_type = 'DISTANCE_TYPE',
      tree_ah_options = '{"leaf_node_embedding_count":LEAF_NODE_EMBEDDING_COUNT,
        "normalization_type":"NORMALIZATION_TYPE"}')

    Ersetzen Sie Folgendes:

    • INDEX_NAME: Der Name des Vektorindex, den Sie erstellen. Da der Index immer im selben Projekt und Dataset wie die Basistabelle erstellt wird, müssen Sie Projekt und Dataset nicht im Namen angeben.
    • DATASET_NAME: der Name des Datasets, das die Tabelle enthält.
    • TABLE_NAME: der Name der Tabelle, die die Spalte mit Einbettungsdaten enthält.
    • COLUMN_NAME: Der Name einer Spalte, die die Einbettungsdaten enthält. Die Spalte muss den Typ ARRAY<FLOAT64> haben. Die Spalte darf keine untergeordneten Felder haben. Alle Elemente im Array dürfen nicht NULL sein und alle Werte in der Spalte müssen dieselben Array-Dimensionen haben.
    • STORED_COLUMN_NAME: Der Name einer Spalte der obersten Ebene in der Tabelle, die im Vektorindex gespeichert werden soll. Der Spaltentyp darf nicht RANGE sein. Gespeicherte Spalten werden nicht verwendet, wenn die Tabelle eine Zugriffsrichtlinie auf Zeilenebene oder die Spalte ein Richtlinien-Tag hat. Informationen zum Aktivieren gespeicherter Spalten finden Sie unter Spalten speichern und vorfiltern.
    • DISTANCE_TYPE: ein optionales Argument, das den Standarddistanztyp angibt, der bei der Durchführung einer Vektorsuche mit diesem Index verwendet werden soll. Die unterstützten Werte sind EUCLIDEAN, COSINE und DOT_PRODUCT. Standardmäßig ist EUCLIDEAN ausgewählt.

      Für das Erstellen des Index wird immer die EUCLIDEAN-Distanz für das Training verwendet. Die Distanz, die in der VECTOR_SEARCH-Funktion verwendet wird, kann jedoch unterschiedlich sein.

      Wenn Sie einen Wert für das Argument distance_type der Funktion VECTOR_SEARCH angeben, wird dieser Wert anstelle des Werts DISTANCE_TYPE verwendet.

    • LEAF_NODE_EMBEDDING_COUNT: ein INT64-Wert, der größer oder gleich 500 ist und die ungefähre Anzahl der Vektoren in jedem Blattknoten des Baums angibt, den der TreeAH-Algorithmus erstellt. Der TreeAH-Algorithmus unterteilt den gesamten Datenbereich in eine Reihe von Listen, wobei jede Liste etwa LEAF_NODE_EMBEDDING_COUNT Datenpunkte enthält. Ein niedrigerer Wert führt zu mehr Listen mit weniger Datenpunkten, ein höherer Wert zu weniger Listen mit mehr Datenpunkten. Der Standardwert ist 1.000, was für die meisten Datasets angemessen ist.

    • NORMALIZATION_TYPE: Ein STRING-Wert Folgende Werte werden unterstützt: NONE oder L2. Der Standardwert ist NONE. Die Normalisierung erfolgt vor der Verarbeitung sowohl der Daten der Basistabelle als auch der Abfragedaten. Die Einbettungsspalte COLUMN_NAME in TABLE_NAME wird dabei jedoch nicht geändert. Je nach Dataset, Embedding-Modell und Distanztyp, der während VECTOR_SEARCH verwendet wird, kann die Normalisierung der Embeddings den Recall verbessern.

Im folgenden Beispiel wird ein Vektorindex für die Spalte embedding von my_table erstellt. Außerdem werden der zu verwendende Distanztyp und die TreeAH-Optionen angegeben:

CREATE TABLE my_dataset.my_table(id INT64, embedding ARRAY<FLOAT64>);

CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding)
OPTIONS (index_type = 'TREE_AH', distance_type = 'EUCLIDEAN',
tree_ah_options = '{"normalization_type": "L2"}');

Wird gefiltert

In den folgenden Abschnitten wird erläutert, wie sich Vor- und Nachfilter auf die Ergebnisse der Vektorsuche auswirken und wie Sie mithilfe von gespeicherten Spalten und Partitionen im Vektorindex vorfiltern.

Vor- und Nachfilter

Bei VECTOR_SEARCH-Vorgängen in BigQuery dienen sowohl das Vorfiltern als auch das Nachfiltern dazu, die Suchergebnisse zu verfeinern. Dabei werden Bedingungen auf Grundlage von Metadatenspalten angewendet, die den Vektoreinbettungen zugeordnet sind. Es ist wichtig, die Unterschiede, die Implementierung und die Auswirkungen zu verstehen, um die Abfrageleistung, die Kosten und die Genauigkeit zu optimieren.

Die Vor- und Nachfilterung sind so definiert:

  • Vorabfilterung:Filterbedingungen werden angewendet, bevor die ANN-Suche (Approximate Nearest Neighbor) Distanzberechnungen für Kandidatenvektoren durchführt. Dadurch wird die Anzahl der Vektoren, die bei der Suche berücksichtigt werden, eingeschränkt. Vorabfilterung führt daher oft zu schnelleren Abfragezeiten und geringeren Rechenkosten, da bei der ANN-Suche weniger potenzielle Kandidaten ausgewertet werden.
  • Nach dem Filtern:Filterbedingungen werden angewendet, nachdem die ersten top_k nächsten Nachbarn durch die ANN-Suche ermittelt wurden. Dadurch wird die endgültige Ergebnismenge anhand der angegebenen Kriterien verfeinert.

Die Position Ihrer WHERE-Klausel bestimmt, ob ein Filter als Vorfilter oder Nachfilter fungiert.

Wenn Sie einen Vorfilter erstellen möchten, muss die WHERE-Klausel der Abfrage auf das Basistabellenargument der VECTOR_SEARCH-Funktion angewendet werden. Das Prädikat muss auf eine gespeicherte Spalte angewendet werden, da es sonst effektiv zu einem Post-Filter wird.

Das folgende Beispiel zeigt, wie ein Vorfilter erstellt wird:

-- Pre-filter on a stored column. The index speeds up the query.
SELECT *
FROM
  VECTOR_SEARCH(
    (SELECT * FROM my_dataset.my_table WHERE type = 'animal'),
    'embedding',
    TABLE my_dataset.my_testdata);

-- Filter on a column that isn't stored. The index is used to search the
-- entire table, and then the results are post-filtered. You might see fewer
-- than 5 matches returned for some embeddings.
SELECT query.test_id, base.type, distance
FROM
  VECTOR_SEARCH(
    (SELECT * FROM my_dataset.my_table WHERE id = 123),
    'embedding',
    TABLE my_dataset.my_testdata,
    top_k => 5);

-- Use pre-filters with brute force. The data is filtered and then searched
-- with brute force for exact results.
SELECT query.test_id, base.type, distance
FROM
  VECTOR_SEARCH(
    (SELECT * FROM my_dataset.my_table WHERE id = 123),
    'embedding',
    TABLE my_dataset.my_testdata,
    options => '{"use_brute_force":true}');

Wenn Sie einen Post-Filter erstellen möchten, muss die WHERE-Klausel der Abfrage außerhalb der VECTOR_SEARCH-Funktion angewendet werden, damit die von der Suche zurückgegebenen Ergebnisse gefiltert werden.

Das folgende Beispiel zeigt, wie ein Post-Filter erstellt wird:

-- Use post-filters. The index is used, but the entire table is searched and
-- the post-filtering might reduce the number of results.
SELECT query.test_id, base.type, distance
FROM
  VECTOR_SEARCH(
    TABLE my_dataset.my_table,
    'embedding',
    TABLE my_dataset.my_testdata,
    top_k => 5)
WHERE base.type = 'animal';

SELECT base.id, distance
FROM
  VECTOR_SEARCH(
    TABLE mydataset.base_table,
    'embedding',
    (SELECT embedding FROM mydataset.query_table),
    top_k => 10
  )
WHERE type = 'document' AND year > 2022

Wenn Sie die Nachfilterung verwenden oder die von Ihnen angegebenen Filter für die Basistabelle auf nicht gespeicherte Spalten verweisen und daher als Nachfilter fungieren, kann das endgültige Ergebnisset weniger als top_k Zeilen enthalten, möglicherweise sogar null Zeilen, wenn das Prädikat selektiv ist. Wenn Sie nach dem Filtern eine bestimmte Anzahl von Ergebnissen benötigen, sollten Sie einen größeren top_k-Wert angeben oder den fraction_lists_to_search-Wert im VECTOR_SEARCH-Aufruf erhöhen.

In einigen Fällen, insbesondere wenn der Vorfilter sehr selektiv ist, kann die Größe der Ergebnismenge durch das Vorfiltern reduziert werden. Erhöhen Sie in diesem Fall den fraction_lists_to_search-Wert im VECTOR_SEARCH-Aufruf.

Mit gespeicherten Spalten vorfiltern

Um die Effizienz Ihres Vektorindex weiter zu verbessern, können Sie Spalten aus Ihrer Basistabelle angeben, die in Ihrem Vektorindex gespeichert werden sollen. Durch die Verwendung gespeicherter Spalten können Abfragen, in denen die Funktion VECTOR_SEARCH aufgerufen wird, auf folgende Weise optimiert werden:

  • Anstatt in einer ganzen Tabelle zu suchen, können Sie die VECTOR_SEARCH-Funktion in einer Abfrageanweisung aufrufen, die die Basistabelle mit einerWHERE-Klausel vorfiltert. Wenn Ihre Tabelle einen Index hat und Sie nur nach gespeicherten Spalten filtern, optimiert BigQuery die Abfrage, indem die Daten vor der Suche gefiltert und dann der Index verwendet wird, um das kleinere Ergebnis-Dataset zu durchsuchen. Wenn Sie nach Spalten filtern, die nicht gespeichert sind, wendet BigQuery den Filter nach der Tabellensuche an. Diese Filter werden auch als Post-Filter bezeichnet.

  • Die Funktion VECTOR_SEARCH gibt eine Struktur namens base aus, die alle Spalten aus der Basistabelle enthält. Ohne gespeicherte Spalten ist ein potenziell teurer Join erforderlich, um die in base gespeicherten Spalten abzurufen. Wenn Sie einen IVF-Index verwenden und in Ihrer Abfrage nur gespeicherte Spalten aus base ausgewählt werden, optimiert BigQuery die Abfrage, um diesen Join zu entfernen. Bei TreeAH-Indizes wird die Verknüpfung mit der Basistabelle nicht entfernt. Gespeicherte Spalten in TreeAH-Indexen werden nur zum Vorfiltern verwendet.

Wenn Sie Spalten speichern möchten, listen Sie sie in der STORING-Klausel der CREATE VECTOR INDEX-Anweisung auf. Durch das Speichern von Spalten wird der Vektorindex größer. Speichern Sie daher am besten nur die Spalten, die am häufigsten verwendet oder gefiltert werden.

Im folgenden Beispiel wird ein Vektorindex mit gespeicherten Spalten erstellt und dann eine Vektorsuchanfrage ausgeführt, bei der nur gespeicherte Spalten ausgewählt werden:

-- Create a table that contains an embedding.
CREATE TABLE my_dataset.my_table(embedding ARRAY<FLOAT64>, type STRING, creation_time DATETIME, id INT64);

-- Create a query table that contains an embedding.
CREATE TABLE my_dataset.my_testdata(embedding ARRAY<FLOAT64>, test_id INT64);

-- Create a vector index with stored columns.
CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding)
STORING (type, creation_time)
OPTIONS (index_type = 'IVF');

-- Select only stored columns from a vector search to avoid an expensive join.
SELECT query, base.type, distance
FROM
  VECTOR_SEARCH(
    TABLE my_dataset.my_table,
    'embedding'
    TABLE my_dataset.my_testdata);

Einschränkungen für gespeicherte Spalten

  • Wenn der Modus, Typ oder das Schema einer Spalte in der Basistabelle geändert wird und es sich um eine gespeicherte Spalte im Vektorindex handelt, kann es zu einer Verzögerung kommen, bevor diese Änderung im Vektorindex berücksichtigt wird. Bis die Aktualisierungen auf den Index angewendet wurden, werden für die Vektorsuchanfragen die geänderten gespeicherten Spalten aus der Basistabelle verwendet.
  • Wenn Sie eine Spalte vom Typ STRUCT aus der query-Ausgabe einer VECTOR_SEARCH-Abfrage für eine Tabelle mit einem Index mit gespeicherten Spalten auswählen, kann die gesamte Abfrage fehlschlagen.

Mit Partitionen vorfiltern

Wenn die Tabelle, für die Sie den Vektorindex erstellen, partitioniert ist, können Sie auch den Vektorindex partitionieren. Die Partitionierung des Vektorindex bietet folgende Vorteile:

  • Die Partitionsbereinigung wird zusätzlich zu den Tabellenpartitionen auch auf die Vektorindexe angewendet. Das Bereinigen von Partitionen erfolgt, wenn bei der Vektorsuche ein qualifizierender Filter für den Wert der Partitionierungsspalte verwendet wird. So kann BigQuery die Partitionen scannen, die dem Filter entsprechen, und die verbleibenden Partitionen überspringen. Durch das Bereinigen von Partitionen können E/A-Kosten gesenkt werden. Weitere Informationen zum Partitionieren finden Sie unter Partitionierte Tabellen abfragen.
  • Bei der Vektorsuche werden weniger Ergebnisse übersehen, wenn Sie die Partitionierungsspalte vorab filtern.

Sie können nur TreeAH-Vektorindexe partitionieren.

Das Partitionieren eines Vektorindex wird nur empfohlen, wenn Sie Vorabfilterung verwenden, um die meisten Ihrer Vektorsuchen auf einige wenige Partitionen zu beschränken.

Verwenden Sie zum Erstellen eines partitionierten Index die PARTITION BY-Klausel der Anweisung CREATE VECTOR INDEX. Die PARTITION BY-Klausel, die Sie in der CREATE VECTOR INDEX-Anweisung angeben, muss mit der PARTITION BY-Klausel übereinstimmen, die in der CREATE TABLE-Anweisung der Tabelle angegeben ist, für die Sie den Vektorindex erstellen, wie im folgenden Beispiel gezeigt:

-- Create a date-partitioned table.
CREATE TABLE my_dataset.my_table(
  embeddings ARRAY
  id INT64,
  date DATE,
)
PARTITION BY date;

-- Create a partitioned vector index on the table.
CREATE VECTOR INDEX my_index ON my_dataset.my_table(embeddings)
PARTITION BY date
OPTIONS(index_type='TREE_AH', distance_type='COSINE');

Wenn für die Tabelle eine Partitionierung nach Ganzzahlbereich oder Zeiteinheitsspalte verwendet wird, wird die Partitionierungsspalte im Vektorindex gespeichert, was die Speicherkosten erhöht. Wenn eine Tabellenspalte sowohl in der STORING- als auch in der PARTITION BY-Klausel der CREATE VECTOR INDEX-Anweisung verwendet wird, wird die Spalte nur einmal gespeichert.

Wenn Sie die Vektorindexpartition verwenden möchten, filtern Sie nach der Partitionierungsspalte in der Unterabfrage der Basistabelle der VECTOR_SEARCH-Anweisung. Im folgenden Beispiel wird die Tabelle samples.items nach der Spalte produced_date partitioniert. Die Unterabfrage der Basistabelle in der VECTOR_SEARCH-Anweisung filtert also nach der Spalte produced_date:

SELECT query.id, base.id, distance
FROM VECTOR_SEARCH(
  (SELECT * FROM my_dataset.my_table WHERE produced_date = '2025-01-01'),
  'embedding',
  TABLE samples.test,
  distance_type => 'COSINE',
  top_k => 10
);

Beispiele

Partitionierten Vektorindex für eine nach Datum/Uhrzeit partitionierte Tabelle erstellen:

-- Create a datetime-partitioned table.
CREATE TABLE my_dataset.my_table(
  id INT64,
  produced_date DATETIME,
  embeddings ARRAY
)
PARTITION BY produced_date;

-- Create a partitioned vector index on the table.
CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings)
PARTITION BY produced_date
OPTIONS(index_type='TREE_AH', distance_type='COSINE');

Partitionierten Vektorindex für eine nach Zeitstempel partitionierte Tabelle erstellen:

-- Create a timestamp-partitioned table.
CREATE TABLE my_dataset.my_table(
  id INT64,
  produced_time TIMESTAMP,
  embeddings ARRAY
)
PARTITION BY TIMESTAMP_TRUNC(produced_time, HOUR);

-- Create a partitioned vector index on the table.
CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings)
PARTITION BY TIMESTAMP_TRUNC(produced_time, HOUR)
OPTIONS(index_type='TREE_AH', distance_type='COSINE');

So erstellen Sie einen partitionierten Vektorindex für eine nach Ganzzahlbereich partitionierte Tabelle:

-- Create a integer range-partitioned table.
CREATE TABLE my_dataset.my_table(
  id INT64,
  embeddings ARRAY
)
PARTITION BY RANGE_BUCKET(id, GENERATE_ARRAY(-100, 100, 20));

-- Create a partitioned vector index on the table.
CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings)
PARTITION BY RANGE_BUCKET(id, GENERATE_ARRAY(-100, 100, 20))
OPTIONS(index_type='TREE_AH', distance_type='COSINE');

So erstellen Sie einen partitionierten Vektorindex für eine nach Aufnahmezeit partitionierte Tabelle:

-- Create a ingestion time-partitioned table.
CREATE TABLE my_dataset.my_table(
  id INT64,
  embeddings ARRAY
)
PARTITION BY TIMESTAMP_TRUNC(_PARTITIONTIME, DAY);

-- Create a partitioned vector index on the table.
CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings)
PARTITION BY TIMESTAMP_TRUNC(_PARTITIONTIME, DAY)
OPTIONS(index_type='TREE_AH', distance_type='COSINE');

Einschränkungen beim Vorfiltern

  • Sie können logische Ansichten nicht in Ihrem Vorfilter verwenden.
  • Wenn Ihr Vorfilter eine Unterabfrage enthält, kann dies die Indexnutzung beeinträchtigen.

Wann werden Daten indexiert?

Vektorindexe werden vollständig von BigQuery verwaltet und automatisch aktualisiert, wenn sich die indexierte Tabelle ändert.

Die Indexierung erfolgt asynchron. Zwischen dem Hinzufügen neuer Zeilen zur Basistabelle und dem Zeitpunkt, zu dem die neuen Zeilen im Index angezeigt werden, gibt es eine Verzögerung. Die Funktion VECTOR_SEARCH berücksichtigt jedoch weiterhin alle Zeilen und lässt keine nicht indexierten Zeilen aus. Die Funktion sucht mithilfe des Index nach indexierten Datensätzen und verwendet die Brute-Force-Suche für die Datensätze, die noch nicht indexiert sind.

Wenn Sie einen Vektorindex für eine Tabelle erstellen, die kleiner als 10 MB ist, wird der Vektorindex nicht ausgefüllt. Dies gilt auch umgekehrt: Wenn Sie Daten aus einer indexierten Tabelle löschen und die Tabellengröße unter 10 MB liegt, wird der Vektorindex vorübergehend deaktiviert. In diesem Fall verwenden Vektorsuchanfragen nicht den Index und den indexUnusedReasons-Code im Abschnitt vectorSearchStatistics der Ressource Job ist BASE_TABLE_TOO_SMALL. Ohne den Index greift VECTOR_SEARCH automatisch auf Brute-Force-Angriffe zurück, um die nächsten Nachbarn von Einbettungen zu finden.

Wenn Sie die indexierte Spalte in einer Tabelle löschen oder die Tabelle selbst umbenennen, wird der Vektorindex automatisch gelöscht.

Status von Vektorindexen überwachen

Sie können den Zustand Ihrer Vektorindexe überwachen, indem Sie INFORMATION_SCHEMA-Ansichten abfragen. Die folgenden Ansichten enthalten Metadaten zu Vektorindexen:

  • Die Ansicht INFORMATION_SCHEMA.VECTOR_INDEXES enthält Informationen zu den Vektorindexen in einem Dataset.

    Nachdem die CREATE VECTOR INDEX-Anweisung abgeschlossen ist, muss der Index noch gefüllt werden, bevor Sie ihn verwenden können. Sie können die Spalten last_refresh_time und coverage_percentage verwenden, um die Bereitschaft eines Vektorindex zu prüfen. Wenn der Vektorindex noch nicht bereit ist, können Sie die Funktion VECTOR_SEARCH trotzdem für eine Tabelle verwenden. Die Ausführung dauert dann aber möglicherweise länger.

  • Die Ansicht INFORMATION_SCHEMA.VECTOR_INDEX_COLUMNS enthält Informationen zu den vektorindexierten Spalten für alle Tabellen in einem Dataset.

  • Die Ansicht INFORMATION_SCHEMA.VECTOR_INDEX_OPTIONS enthält Informationen zu den Optionen, die von den Vektorindexen in einem Dataset verwendet werden.

Beispiele für Vektorindexe

Das folgende Beispiel zeigt alle aktiven Vektorindexe für Tabellen im Dataset my_dataset, das sich im Projekt my_project befindet. Darin enthalten sind die Namen, die zum Erstellen der Indexe verwendeten DDL-Anweisungen und der Deckungsprozentsatz. Ist eine indexierte Basistabelle kleiner als 10 MB, wird der Index nicht ausgefüllt. In diesem Fall ist der Wert coverage_percentage 0.

SELECT table_name, index_name, ddl, coverage_percentage
FROM my_project.my_dataset.INFORMATION_SCHEMA.VECTOR_INDEXES
WHERE index_status = 'ACTIVE';

Das Ergebnis sieht etwa so aus:

+------------+------------+-------------------------------------------------------------------------------------------------+---------------------+
| table_name | index_name | ddl                                                                                             | coverage_percentage |
+------------+------------+-------------------------------------------------------------------------------------------------+---------------------+
| table1     | indexa     | CREATE VECTOR INDEX `indexa` ON `my_project.my_dataset.table1`(embeddings)                      | 100                 |
|            |            | OPTIONS (distance_type = 'EUCLIDEAN', index_type = 'IVF', ivf_options = '{"num_lists": 100}')   |                     |
+------------+------------+-------------------------------------------------------------------------------------------------+---------------------+
| table2     | indexb     | CREATE VECTOR INDEX `indexb` ON `my_project.my_dataset.table2`(vectors)                         | 42                  |
|            |            | OPTIONS (distance_type = 'COSINE', index_type = 'IVF', ivf_options = '{"num_lists": 500}')      |                     |
+------------+------------+-------------------------------------------------------------------------------------------------+---------------------+
| table3     | indexc     | CREATE VECTOR INDEX `indexc` ON `my_project.my_dataset.table3`(vectors)                         | 98                  |
|            |            | OPTIONS (distance_type = 'DOT_PRODUCT', index_type = 'TREE_AH',                                 |                     |
|            |            |          tree_ah_options = '{"leaf_node_embedding_count": 1000, "normalization_type": "NONE"}') |                     |
+------------+------------+-------------------------------------------------------------------------------------------------+---------------------+

Beispiele für Spalten für Vektorindex

Die folgende Abfrage extrahiert Informationen zu Spalten mit Vektorindexen:

SELECT table_name, index_name, index_column_name, index_field_path
FROM my_project.dataset.INFORMATION_SCHEMA.VECTOR_INDEX_COLUMNS;

Das Ergebnis sieht etwa so aus:

+------------+------------+-------------------+------------------+
| table_name | index_name | index_column_name | index_field_path |
+------------+------------+-------------------+------------------+
| table1     | indexa     | embeddings        | embeddings       |
| table2     | indexb     | vectors           | vectors          |
| table3     | indexc     | vectors           | vectors          |
+------------+------------+-------------------+------------------+

Beispiele für Optionen für Vektorindexe

Die folgende Abfrage extrahiert Informationen zu Vektorindexoptionen:

SELECT table_name, index_name, option_name, option_type, option_value
FROM my_project.dataset.INFORMATION_SCHEMA.VECTOR_INDEX_OPTIONS;

Das Ergebnis sieht etwa so aus:

+------------+------------+------------------+------------------+-------------------------------------------------------------------+
| table_name | index_name | option_name      | option_type      | option_value                                                      |
+------------+------------+------------------+------------------+-------------------------------------------------------------------+
| table1     | indexa     | index_type       | STRING           | IVF                                                               |
| table1     | indexa     | distance_type    | STRING           | EUCLIDEAN                                                         |
| table1     | indexa     | ivf_options      | STRING           | {"num_lists": 100}                                                |
| table2     | indexb     | index_type       | STRING           | IVF                                                               |
| table2     | indexb     | distance_type    | STRING           | COSINE                                                            |
| table2     | indexb     | ivf_options      | STRING           | {"num_lists": 500}                                                |
| table3     | indexc     | index_type       | STRING           | TREE_AH                                                           |
| table3     | indexc     | distance_type    | STRING           | DOT_PRODUCT                                                       |
| table3     | indexc     | tree_ah_options  | STRING           | {"leaf_node_embedding_count": 1000, "normalization_type": "NONE"} |
+------------+------------+------------------+------------------+-------------------------------------------------------------------+

Verwendung von Vektorindexen prüfen

Informationen zur Verwendung des Vektorindex sind in den Jobmetadaten des Jobs verfügbar, in dem die Vektorsuchanfrage ausgeführt wurde. Sie können Jobmetadaten aufrufen über die Google Cloud Console, das bq-Befehlszeilentool, die BigQuery API oder die Clientbibliotheken.

Wenn Sie die Google Cloud Konsole verwenden, finden Sie Informationen zur Verwendung von Vektorindexen in den Feldern Nutzungsmodus für Vektorindex und Gründe für nicht verwendeten Vektorindex.

Wenn Sie das bq-Tool oder die BigQuery API verwenden, finden Sie Informationen zur Verwendung von Vektorindexen im Abschnitt VectorSearchStatistics der Ressource Job.

Der Nutzungsmodus für den Index gibt an, ob ein Vektorindex verwendet wurde. Dazu wird einer der folgenden Werte angegeben:

  • UNUSED: Es wurde kein Vektorindex verwendet.
  • PARTIALLY_USED: Einige VECTOR_SEARCH-Funktionen in der Abfrage haben Vektorindexe verwendet, andere nicht.
  • FULLY_USED: Jede VECTOR_SEARCH-Funktion in der Abfrage hat einen Vektorindex verwendet.

Wenn der Wert für den Indexnutzungsmodus UNUSED oder PARTIALLY_USED ist, geben die Gründe für nicht verwendete Indexe an, warum Vektorindexe in der Abfrage nicht verwendet wurden.

Die folgenden Ergebnisse, die von bq show --format=prettyjson -j my_job_id zurückgegeben werden, zeigen beispielsweise, dass der Index nicht verwendet wurde, weil die Option use_brute_force in der Funktion VECTOR_SEARCH angegeben wurde:

"vectorSearchStatistics": {
  "indexUnusedReasons": [
    {
      "baseTable": {
        "datasetId": "my_dataset",
        "projectId": "my_project",
        "tableId": "my_table"
      },
      "code": "INDEX_SUPPRESSED_BY_FUNCTION_OPTION",
      "message": "No vector index was used for the base table `my_project:my_dataset.my_table` because use_brute_force option has been specified."
    }
  ],
  "indexUsageMode": "UNUSED"
}

Optionen für die Indexverwaltung

Sie haben zwei Möglichkeiten, Indexe zu erstellen und von BigQuery verwalten zu lassen:

  • Standardmäßigen freigegebenen Slot-Pool verwenden: Wenn die zu indexierenden Daten unter dem Limit pro Organisation liegen, können Sie den kostenlosen freigegebenen Slot-Pool für die Indexverwaltung verwenden.
  • Eigene Reservierung verwenden: Um einen vorhersehbaren und konsistenten Fortschritt bei der Indexierung für Ihre größeren Produktionsarbeitslasten zu erreichen, können Sie Ihre eigenen Reservierungen für die Indexverwaltung verwenden.

Freigegebene Slots verwenden

Wenn Sie Ihr Projekt nicht für die Verwendung einer dedizierten Reservierung für die Indexierung konfiguriert haben, wird die Indexverwaltung im kostenlosen, freigegebenen Slot-Pool durchgeführt, wobei die folgenden Einschränkungen gelten.

Wenn Sie einer Tabelle Daten hinzufügen, wodurch die Gesamtgröße der indexierten Tabelle das Limit Ihrer Organisation überschreitet, pausiert BigQuery die Indexverwaltung für alle indexierten Tabellen. In diesem Fall wird im Feld index_status in der Ansicht INFORMATION_SCHEMA.VECTOR_INDEXES PENDING DISABLEMENT angezeigt und der Index wird zum Löschen in die Warteschlange gestellt. Solange die Deaktivierung des Index aussteht, wird er noch in Anfragen verwendet und Indexspeicher wird Ihnen weiterhin in Rechnung gestellt. Nachdem ein Index gelöscht wurde, wird er im Feld index_status als TEMPORARILY DISABLED angezeigt. In diesem Zustand wird der Index nicht für Anfragen verwendet und Ihnen wird der Indexspeicher nicht in Rechnung gestellt. In diesem Fall lautet der IndexUnusedReason-Code BASE_TABLE_TOO_LARGE.

Wenn Sie Daten aus der Tabelle löschen und die Gesamtgröße der indexierten Tabelle unter das Limit pro Organisation fällt, wird die Indexverwaltung für alle indexierten Tabellen fortgesetzt. Das Feld index_status in der Ansicht INFORMATION_SCHEMA.VECTOR_INDEXES ist ACTIVE. Anfragen können den Index verwenden und Ihnen wird der Indexspeicher in Rechnung gestellt.

Mit der Ansicht INFORMATION_SCHEMA.SEARCH_INDEXES_BY_ORGANIZATION können Sie Ihren aktuellen Verbrauch im Hinblick auf das organisationsbezogene Limit in einer bestimmten Region aufgeschlüsselt nach Projekten und Tabellen nachvollziehen.

BigQuery gibt keine Garantien für die verfügbaren Kapazitäten des gemeinsamen Pools oder den angezeigten Durchsatz der Indexierung. Für Produktionsanwendungen kann die Verwendung dedizierter Slots für die Indexverarbeitung sinnvoll sein.

Eigene Reservierung verwenden

Anstatt den standardmäßigen freigegebenen Slot-Pool zu verwenden, können Sie optional eine eigene Reservierung festlegen, um Ihre Tabellen zu indexieren. Die Verwendung Ihrer eigenen Reservierung sorgt für eine vorhersagbare und konsistente Leistung von Indexverwaltungsjobs, z. B. Erstellungs-, Aktualisierungs- und Hintergrundoptimierungen.

  • Wenn ein Indexjob in Ihrer Reservierung ausgeführt wird, gibt es keine Größenbeschränkungen für Tabellen.
  • Mit der eigenen Reservierung können Sie Ihre Indexverwaltung flexibel verwalten. Wenn Sie einen sehr großen Index erstellen oder eine wichtige Aktualisierung einer indexierten Tabelle vornehmen müssen, können Sie der Zuweisung vorübergehend weitere Slots hinzufügen.

Um die Tabelle in einem Projekt mit einer bestimmten Reservierung zu indexieren, erstellen Sie eine Reservierung in der Region, in der sich Ihre Tabellen befinden. Weisen Sie der Reservierung dann das Projekt zu, wobei job_type auf BACKGROUND gesetzt ist:

SQL

Verwenden Sie die DDL-Anweisung CREATE ASSIGNMENT.

  1. Rufen Sie in der Google Cloud Console die Seite BigQuery auf.

    BigQuery aufrufen

  2. Geben Sie im Abfrageeditor die folgende Anweisung ein:

    CREATE ASSIGNMENT
      `ADMIN_PROJECT_ID.region-LOCATION.RESERVATION_NAME.ASSIGNMENT_ID`
    OPTIONS (
      assignee = 'projects/PROJECT_ID',
      job_type = 'BACKGROUND');

    Ersetzen Sie Folgendes:

    • ADMIN_PROJECT_ID: die Projekt-ID des Administrationsprojekts, dem die Reservierungsressource gehört
    • LOCATION: der Standort der Reservierung
    • RESERVATION_NAME: der Name der Reservierung
    • ASSIGNMENT_ID: die ID der Zuweisung

      Die ID muss für das Projekt und den Standort eindeutig sein, mit einem Kleinbuchstaben oder einer Zahl beginnen und enden und darf nur Kleinbuchstaben, Zahlen und Bindestriche enthalten.

    • PROJECT_ID: die ID des Projekts, das die zu indexierenden Tabellen enthält. Dieses Projekt wird der Reservierung zugewiesen.

  3. Klicken Sie auf Ausführen.

Informationen zum Ausführen von Abfragen finden Sie unter Interaktive Abfrage ausführen.

bq

Führen Sie den Befehl bq mk aus:

bq mk \
    --project_id=ADMIN_PROJECT_ID \
    --location=LOCATION \
    --reservation_assignment \
    --reservation_id=RESERVATION_NAME \
    --assignee_id=PROJECT_ID \
    --job_type=BACKGROUND \
    --assignee_type=PROJECT

Ersetzen Sie Folgendes:

  • ADMIN_PROJECT_ID: die Projekt-ID des Administrationsprojekts, dem die Reservierungsressource gehört
  • LOCATION: der Standort der Reservierung
  • RESERVATION_NAME: der Name der Reservierung
  • PROJECT_ID: die ID des Projekts, das der Reservierung zugewiesen werden soll

Indexierungsjobs ansehen

Bei jeder Erstellung oder Aktualisierung eines Index für eine einzelne Tabelle wird ein neuer Indexierungsjob erstellt. Fragen Sie die Ansichten INFORMATION_SCHEMA.JOBS* ab, um Informationen zum Job anzuzeigen. Sie können nach Indexierungsjobs filtern, indem Sie job_type IS NULL AND SEARCH(job_id, '`search_index`') in der WHERE-Klausel Ihrer Abfrage festlegen. Im folgenden Beispiel werden die fünf neuesten Indexierungsjobs im Projekt my_project aufgelistet:

SELECT *
FROM
 region-us.INFORMATION_SCHEMA.JOBS
WHERE
  project_id  = 'my_project'
  AND job_type IS NULL
  AND SEARCH(job_id, '`search_index`')
ORDER BY
 creation_time DESC
LIMIT 5;

Reservierungsgröße auswählen

Wenn Sie die richtige Anzahl von Slots für Ihre Reservierung auswählen möchten, sollten Sie berücksichtigen, wann Jobs mit Indexverwaltung ausgeführt werden, wie viele Slots sie verwenden und wie Ihre Nutzung im Laufe der Zeit aussieht. BigQuery löst in den folgenden Situationen einen Indexverwaltungsjob aus:

  • Sie erstellen einen Index für eine Tabelle.
  • Daten werden in einer indexierten Tabelle geändert.
  • Das Schema einer Tabelle ändert sich, was sich darauf auswirkt, welche Spalten indexiert werden.
  • Indexdaten und Metadaten werden regelmäßig optimiert oder aktualisiert.

Die Anzahl der Slots, die Sie für einen Indexverwaltungsjob in einer Tabelle benötigen, hängt von den folgenden Faktoren ab:

  • Die Größe der Tabelle
  • Die Rate der Datenerfassung in der Tabelle
  • Die Rate der DML-Anweisungen, die auf die Tabelle angewendet werden
  • Die akzeptable Verzögerung zum Erstellen und Verwalten des Index
  • Die Komplexität des Index; normalerweise bestimmt durch Attribute der Daten, z. B. die Anzahl doppelter Begriffe
Nutzung und Fortschritt im Blick behalten

Die beste Methode, um die Anzahl der Slots zu ermitteln, die Sie zum effizienten Ausführen Ihrer Jobs mit Indexverwaltung benötigen, besteht darin, die Slotnutzung zu beobachten und die Reservierungsgröße entsprechend anzupassen. Die folgende Abfrage gibt die tägliche Slot-Nutzung für Indexverwaltungsjobs zurück. In der Region us-west1 sind nur die letzten 30 Tage enthalten:

SELECT
  TIMESTAMP_TRUNC(job.creation_time, DAY) AS usage_date,
  -- Aggregate total_slots_ms used for index-management jobs in a day and divide
  -- by the number of milliseconds in a day. This value is most accurate for
  -- days with consistent slot usage.
  SAFE_DIVIDE(SUM(job.total_slot_ms), (1000 * 60 * 60 * 24)) AS average_daily_slot_usage
FROM
  `region-us-west1`.INFORMATION_SCHEMA.JOBS job
WHERE
  project_id = 'my_project'
  AND job_type IS NULL
  AND SEARCH(job_id, '`search_index`')
GROUP BY
  usage_date
ORDER BY
  usage_date DESC
limit 30;

Wenn nicht genügend Slots zum Ausführen von Indexverwaltungsjobs vorhanden sind, ist der Index möglicherweise nicht mehr mit seiner Tabelle synchron und Indexierungsjobs können fehlschlagen. In diesem Fall wird der Index in BigQuery von Grund auf neu erstellt. Achten Sie darauf, dass genügend Slots vorhanden sind, um Indexaktualisierungen aus der Datenaufnahme und -optimierung zu unterstützen, damit kein nicht synchronisierter Index. Weitere Informationen zur Überwachung der Slot-Nutzung finden Sie unter Diagramme zu administrativen Ressourcen.

Vektorindex löschen

Wenn Sie einen Vektorindex nicht mehr benötigen oder die in einer Tabelle indexierte Spalte ändern möchten, können Sie den Index für diese Tabelle mit der DDL-Anweisung DROP VECTOR INDEX löschen.

Beispiel:

DROP VECTOR INDEX my_index ON my_dataset.indexed_table;

Wenn eine indexierte Tabelle gelöscht wird, wird ihr Index automatisch gelöscht.

Nächste Schritte