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 mithilfe der Kosinus-Distanz, der euklidischen Distanz und der Vektorfunktionen für das Punktprodukt ausführen, um die k nächsten Nachbarn zu ermitteln. Diese Informationen gelten sowohl für GoogleSQL- als auch für PostgreSQL-Datenbanken. Bevor Sie diese Seite lesen, sollten Sie sich mit den folgenden Konzepten vertraut machen:

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

Mithilfe von Vektordistanzfunktionen können Sie eine KNN-Vektorsuche (K-Nearest-Neighbor) für Anwendungsfälle wie Ähnlichkeitssuche oder die durch Abruf erweiterte Generierung ausführen. Spanner unterstützt die Funktionen COSINE_DISTANCE(), EUCLIDEAN_DISTANCE() und DOT_PRODUCT(), die auf Vektoreinbettungen angewendet werden und mit denen Sie den KNN der Eingabeeinbettung ermitteln können.

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

Alle drei Distanzfunktionen nehmen die Argumente vector1 und vector2 vom Typ array<> an. Sie müssen dieselben Abmessungen haben und gleich lang sein. Weitere Informationen zu diesen Funktionen finden Sie unter:

Beispiele

Die folgenden Beispiele zeigen die KNN-Suche, die KNN-Suche in partitionierten Daten und die Verwendung eines sekundären Index mit KNN.

In den Beispielen wird immer EUCLIDEAN_DISTANCE() verwendet. Sie können aber auch COSINE_DISTANCE() verwenden. Wenn alle Vektor-Embeddings in Ihrem Dataset normalisiert sind, können Sie DOT_PRODUCT() auch als Distanzfunktion verwenden.

Angenommen, eine Tabelle Documents enthält eine Spalte (DocEmbedding) mit vorab berechneten Texteinbettungen aus der Spalte DocContents mit Bytes.

CREATE TABLE Documents (
UserId       INT64 NOT NULL,
DocId        INT64 NOT NULL,
Author       STRING(1024),
DocContents  BYTES,
DocEmbedding ARRAY<FLOAT32>
) PRIMARY KEY (UserId, DocId);
CREATE TABLE Documents (
UserId       bigint NOT NULL,
DocId        bigint NOT NULL,
Author       varchar(1024),
DocContents  bytea,
DocEmbedding float4[],
PRIMARY KEY  (UserId, DocId)
);

Angenommen, die Eingabe-Embedding für „Baseball, aber kein professioneller Baseball“ ist das Array [0.3, 0.3, 0.7, 0.7]. Mit der folgenden Abfrage können Sie die fünf am besten passenden Dokumente finden:

SELECT DocId, DocEmbedding FROM Documents
ORDER BY EUCLIDEAN_DISTANCE(DocEmbedding,
ARRAY<FLOAT32>[0.3, 0.3, 0.7, 0.8])
LIMIT 5;
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 gängige Anwendung ist die Suche in partitionierten Daten, z. B. in Zeilen, die zu einer bestimmten UserId gehören.

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;
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 Bereiche von sekundären Indizes

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

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;
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