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 Vektorähnlichkeitssuche durchführen. Dazu verwenden Sie die Vektorfunktionen für Kosinus-Distanz, euklidische Distanz und Punktprodukt, um die k-nächsten Nachbarn zu finden. Diese Informationen gelten sowohl für Datenbanken im GoogleSQL-Dialekt als auch für Datenbanken im PostgreSQL-Dialekt. Bevor Sie diese Seite lesen, sollten Sie die folgenden Konzepte kennen:

  • Euklidische Distanz: Misst die kürzeste Distanz zwischen zwei Vektoren.
  • Kosinus-Distanz: Misst den Kosinus des Winkels zwischen zwei Vektoren.
  • Punktprodukt: Berechnet den Kosinus des Winkels multipliziert mit dem Produkt der entsprechenden Vektor größen. 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 Vektordistanzfunktionen verwenden, um eine 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 auf Vektoreinbettungen angewendet werden. So können Sie die KNN der Eingabeeinbettung finden.

Nachdem Sie beispielsweise Ihre betrieblichen Spanner-Daten als Vektoreinbettungen generiert und gespeichert haben, können Sie diese Vektoreinbettungen als Eingabeparameter in Ihrer Abfrage verwenden, um die nächsten 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<>. Sie müssen dieselben Dimensionen und dieselbe Länge haben. Weitere Informationen zu diesen Funktionen finden Sie unter:

Beispiele

In den folgenden Beispielen werden die KNN-Suche, die KNN-Suche in partitionierten Daten und die Verwendung eines sekundären Index mit KNN gezeigt.

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 Byte-Spalte DocContents.

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 Eingabeeinbettung für „Baseball, aber nicht professioneller Baseball“ ist das Array [0.3, 0.3, 0.7, 0.7]. Mit der folgenden Abfrage können Sie die fünf nächstgelegenen 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;

Erwartete 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 Sie der WHERE-Klausel Bedingungen hinzufügen, um die Vektorsuche auf eine Teilmenge Ihrer Daten zu beschränken. Ein häufiger Anwendungsfall ist die Suche in partitionierten Daten, z. B. Zeilen, die zu einer 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;

Erwartete Ergebnisse dieses Beispiels:

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

Beispiel 3: KNN-Suche in sekundären Indexbereichen

Wenn der WHERE Klausel-Filter, den Sie verwenden, nicht Teil des Primärschlüssels der Tabelle ist, können Sie einen sekundären Index erstellen, um den Vorgang mit einer reinen Indexsuche 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;

Erwartete 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