Suche nach Vektorähnlichkeiten in Spanner durchführen, indem die K-nächsten Nachbarn ermittelt werden

Auf dieser Seite wird beschrieben, wie Sie in Spanner eine Suche nach Vektorähnlichkeit durchführen, indem Sie die Vektorfunktionen für Kosinus-Abstand, euklidischen Abstand und Punktprodukt verwenden, um die K-nächsten Nachbarn zu finden. Diese Informationen gelten sowohl für Datenbanken mit GoogleSQL-Dialekt als auch für Datenbanken mit PostgreSQL-Dialekt. Bevor Sie diese Seite lesen, sollten Sie sich mit den folgenden Konzepten vertraut machen:

  • Euklidischer Abstand: Misst den kürzesten Abstand zwischen zwei Vektoren.
  • Kosinus-Distanz: Hier wird der Kosinus des Winkels zwischen zwei Vektoren gemessen.
  • Skalarprodukt: Hier wird der Kosinus des Winkels multipliziert mit dem Produkt der entsprechenden Vektormagnituden berechnet. Wenn Sie wissen, dass alle Vektoreinbettungen in Ihrem Dataset normalisiert sind, können Sie DOT_PRODUCT() als Distanzfunktion verwenden.
  • K-Nearest Neighbors (KNN): Ein Algorithmus für überwachtes maschinelles Lernen, der zur Lösung von Klassifizierungs- oder Regressionsproblemen verwendet wird.

Sie können Vektorentfernungsfunktionen verwenden, um die KNN-Vektorsuche (K-Nearest Neighbors) für Anwendungsfälle wie die Ähnlichkeitssuche oder die Retrieval-Augmented Generation durchzuführen. Spanner unterstützt die Funktionen COSINE_DISTANCE(), EUCLIDEAN_DISTANCE() und DOT_PRODUCT(), die für Vektoreinbettungen verwendet werden. Damit können Sie die KNN der Eingabeeinbettung ermitteln.

Nachdem Sie beispielsweise Ihre operativen Spanner-Daten als Vektoreinbettungen generiert und gespeichert haben, können Sie diese Vektoreinbettungen als Eingabeparameter in Ihrer Abfrage angeben, um die nächstgelegenen Vektoren im N-dimensionalen Raum zu finden und nach semantisch ähnlichen oder verwandten Elementen zu suchen.

Alle drei Distanzfunktionen verwenden die Argumente vector1 und vector2 vom Typ array<>, die aus denselben Dimensionen bestehen und dieselbe Länge haben müssen. Weitere Informationen zu diesen Funktionen finden Sie hier:

Beispiele

Die folgenden Beispiele zeigen die KNN-Suche, die KNN-Suche über partitionierte Daten und die Verwendung eines sekundären Index mit KNN.

In allen Beispielen wird EUCLIDEAN_DISTANCE() verwendet. Sie können auch COSINE_DISTANCE() verwenden. Wenn alle Vektoreinbettungen in Ihrem Dataset normalisiert sind, können Sie außerdem DOT_PRODUCT() als Distanzfunktion verwenden.

Angenommen, es gibt eine Tabelle Documents mit einer Spalte (DocEmbedding) mit vorab berechneten Texteinbettungen aus der Spalte DocContents (Bytes).

GoogleSQL

CREATE TABLE Documents (
UserId       INT64 NOT NULL,
DocId        INT64 NOT NULL,
Author       STRING(1024),
DocContents  BYTES(MAX),
DocEmbedding ARRAY<FLOAT32>
) PRIMARY KEY (UserId, DocId);

PostgreSQL

CREATE TABLE Documents (
UserId       bigint NOT NULL,
DocId        bigint NOT NULL,
Author       varchar(1024),
DocContents  bytea,
DocEmbedding float4[],
PRIMARY KEY  (UserId, DocId)
);

Angenommen, eine Eingabe-Einbettung für „Baseball, aber nicht professioneller Baseball“ ist das Array [0.3, 0.3, 0.7, 0.7]. Mit der folgenden Anfrage können Sie die fünf ähnlichsten Dokumente finden, die übereinstimmen:

GoogleSQL

SELECT DocId, DocEmbedding FROM Documents
ORDER BY EUCLIDEAN_DISTANCE(DocEmbedding,
ARRAY<FLOAT32>[0.3, 0.3, 0.7, 0.8])
LIMIT 5;

PostgreSQL

SELECT DocId, DocEmbedding FROM Documents
ORDER BY spanner.euclidean_distance(DocEmbedding,
'{0.3, 0.3, 0.7, 0.8}'::float4[])
LIMIT 5;

Die erwarteten Ergebnisse dieses Beispiels:

Documents
+---------------------------+-----------------+
| DocId                     | DocEmbedding    |
+---------------------------+-----------------+
| 24                        | [8, ...]        |
+---------------------------+-----------------+
| 25                        | [6, ...]        |
+---------------------------+-----------------+
| 26                        | [3.2, ...]      |
+---------------------------+-----------------+
| 27                        | [38, ...]       |
+---------------------------+-----------------+
| 14229                     | [1.6, ...]      |
+---------------------------+-----------------+

Beispiel 2: KNN-Suche in partitionierten Daten

Die Abfrage im vorherigen Beispiel kann geändert werden, indem der WHERE-Klausel Bedingungen hinzugefügt werden, um die Vektorsuche auf eine Teilmenge Ihrer Daten zu beschränken. Eine häufige Anwendung ist die Suche in partitionierten Daten, z. B. in Zeilen, die zu einem bestimmten UserId gehören.

GoogleSQL

SELECT UserId, DocId, DocEmbedding FROM Documents
WHERE UserId=18
ORDER BY EUCLIDEAN_DISTANCE(DocEmbedding,
ARRAY<FLOAT32>[0.3, 0.3, 0.7, 0.8])
LIMIT 5;

PostgreSQL

SELECT UserId, DocId, DocEmbedding FROM Documents
WHERE UserId=18
ORDER BY spanner.euclidean_distance(DocEmbedding,
'{0.3, 0.3, 0.7, 0.8}'::float4[])
LIMIT 5;

Die erwarteten Ergebnisse dieses Beispiels:

Documents
+-----------+-----------------+-----------------+
| UserId    | DocId           | DocEmbedding    |
+-----------+-----------------+-----------------+
| 18        | 234             | [12, ...]       |
+-----------+-----------------+-----------------+
| 18        | 12              | [1.6, ...]      |
+-----------+-----------------+-----------------+
| 18        | 321             | [22, ...]       |
+-----------+-----------------+-----------------+
| 18        | 432             | [3, ...]        |
+-----------+-----------------+-----------------+

Beispiel 3: KNN-Suche über sekundäre Indexbereiche

Wenn der Filter der WHERE-Klausel, die Sie verwenden, nicht Teil des Primärschlüssels der Tabelle ist, können Sie einen sekundären Index erstellen, um den Vorgang mit einem Index-Only-Scan zu beschleunigen.

GoogleSQL

CREATE INDEX DocsByAuthor
ON Documents(Author)
STORING (DocEmbedding);

SELECT Author, DocId, DocEmbedding FROM Documents
WHERE Author="Mark Twain"
ORDER BY EUCLIDEAN_DISTANCE(DocEmbedding,
   <embeddings for "book about the time traveling American">)
LIMIT 5;

PostgreSQL

CREATE INDEX DocsByAuthor
ON Documents(Author)
INCLUDE (DocEmbedding);

SELECT Author, DocId, DocEmbedding FROM Documents
WHERE Author="Mark Twain"
ORDER BY spanner.euclidean_distance(DocEmbedding,
   <embeddings for "that book about the time traveling American">)
LIMIT 5;

Die erwarteten Ergebnisse dieses Beispiels:

Documents
+------------+-----------------+-----------------+
| Author     | DocId           | DocEmbedding    |
+------------+-----------------+-----------------+
| Mark Twain | 234             | [12, ...]       |
+------------+-----------------+-----------------+
| Mark Twain | 12              | [1.6, ...]      |
+------------+-----------------+-----------------+
| Mark Twain | 321             | [22, ...]       |
+------------+-----------------+-----------------+
| Mark Twain | 432             | [3, ...]        |
+------------+-----------------+-----------------+
| Mark Twain | 375             | [9, ...]        |
+------------+-----------------+-----------------+

Nächste Schritte