Wyszukiwanie za pomocą wektorów dystrybucyjnych

Na tej stronie dowiesz się, jak używać Cloud Firestore do wyszukiwania wektorów KNN przy użyciu tych technik:

  • Zapisz wartości wektorów
  • Tworzenie indeksów wektorów KNN i zarządzanie nimi
  • Utwórz zapytanie KNN (k-najbliższy sąsiad) przy użyciu jednej z obsługiwanych funkcji odległości wektorowych

Wektory dystrybucyjne sklepów

Wartości wektorowe, takie jak wektory dystrybucyjne tekstu, możesz tworzyć z danych Cloud Firestore i przechowywać je w dokumentach Cloud Firestore.

Operacja zapisu z wektorem dystrybucyjnym wektorowym

Poniższy przykład pokazuje, jak zapisać wektorowy wektor w dokumencie Cloud Firestore:

Python
from google.cloud import firestore
from google.cloud.firestore_v1.vector import Vector

firestore_client = firestore.Client()
collection = firestore_client.collection("coffee-beans")
doc = {
  "name": "Kahawa coffee beans",
  "description": "Information about the Kahawa coffee beans.",
  "embedding_field": Vector([1.0 , 2.0, 3.0])
}

collection.add(doc)
    
Node.js
import {
  Firestore,
  FieldValue,
} from "@google-cloud/firestore";

const db = new Firestore();
const coll = db.collection('coffee-beans');
await coll.add({
  name: "Kahawa coffee beans",
  description: "Information about the Kahawa coffee beans.",
  embedding_field: FieldValue.vector([1.0 , 2.0, 3.0])
});
    

Wektory dystrybucyjne obliczeniowe za pomocą funkcji w Cloud Functions

Aby obliczać i przechowywać wektory dystrybucyjne wektorów dystrybucyjnych za każdym razem, gdy dokument jest aktualizowany lub tworzony, możesz skonfigurować funkcję w Cloud Functions:

Python
@functions_framework.cloud_event
def store_embedding(cloud_event) -> None:
  """Triggers by a change to a Firestore document.
  """
  firestore_payload = firestore.DocumentEventData()
  payload = firestore_payload._pb.ParseFromString(cloud_event.data)

  collection_id, doc_id = from_payload(payload)
  # Call a function to calculate the embedding
  embedding = calculate_embedding(payload)
  # Update the document
  doc = firestore_client.collection(collection_id).document(doc_id)
  doc.set({"embedding_field": embedding}, merge=True)
    
Node.js
/**
 * A vector embedding will be computed from the
 * value of the `content` field. The vector value
 * will be stored in the `embedding` field. The
 * field names `content` and `embedding` are arbitrary
 * field names chosen for this example.
 */
async function storeEmbedding(event: FirestoreEvent<any>): Promise<void> {
  // Get the previous value of the document's `content` field.
  const previousDocumentSnapshot = event.data.before as QueryDocumentSnapshot;
  const previousContent = previousDocumentSnapshot.get("content");

  // Get the current value of the document's `content` field.
  const currentDocumentSnapshot = event.data.after as QueryDocumentSnapshot;
  const currentContent = currentDocumentSnapshot.get("content");

  // Don't update the embedding if the content field did not change
  if (previousContent === currentContent) {
    return;
  }

  // Call a function to calculate the embedding for the value
  // of the `content` field.
  const embeddingVector = calculateEmbedding(currentContent);

  // Update the `embedding` field on the document.
  await currentDocumentSnapshot.ref.update({
    embedding: embeddingVector,
  });
}
    

Tworzenie indeksów wektorów i zarządzanie nimi

Zanim będzie można przeprowadzić wyszukiwanie najbliższych sąsiadów z użyciem wektorów dystrybucyjnych wektorowych, musisz utworzyć odpowiedni indeks. Poniższe przykłady pokazują, jak tworzyć indeksy wektorów i nimi zarządzać.

Utwórz indeks wektora pojedynczego pola

Aby utworzyć indeks wektorów w jednym polu, użyj gcloud alpha firestore indexes composite create:

gcloud
gcloud alpha firestore indexes composite create \
--collection-group=collection-group \
--query-scope=COLLECTION \
--field-config field-path=vector-field,vector-config='vector-configuration' \
--database=database-id
    

gdzie:

  • collection-group to identyfikator grupy kolekcji.
  • vector-field to nazwa pola zawierającego wektor dystrybucyjny.
  • database-id to identyfikator bazy danych.
  • vector-configuration obejmuje wektor dimension i typ indeksu. dimension jest liczbą całkowitą do 2048. Typ indeksu musi być ustawiony na flat. Sformatuj konfigurację indeksu w ten sposób: {"dimension":"DIMENSION", "flat": "{}"}.

Utwórz indeks wektorów złożonych

Poniższy przykład tworzy indeks wektorów złożonych dla pola color i pola wektora dystrybucyjnego.

gcloud
gcloud alpha firestore indexes composite create \
--collection-group=collection-group \
--query-scope=COLLECTION \
--field-config=order=ASCENDING,field-path="color" \
--field-config field-path=field,vector-config='{"dimension":"1024", "flat": "{}"}' \
--database=database-id
    

Wyświetl wszystkie indeksy wektorów

gcloud
gcloud alpha firestore indexes composite list --database=database-id

Zastąp database-id identyfikatorem bazy danych.

Usuń indeks wektorów

gcloud
gcloud alpha firestore indexes composite delete index-id --database=database-id
    

gdzie:

  • index-id to identyfikator indeksu do usunięcia. Użyj narzędzia indexes composite list, aby pobrać identyfikator indeksu.
  • database-id to identyfikator bazy danych.

Opisz indeks wektorów

gcloud
gcloud alpha firestore indexes composite describe index-id --database=database-id
    

gdzie:

  • index-id to identyfikator indeksu do opisania. Użyj kodu lub indexes composite list, aby pobrać identyfikator indeksu.
  • database-id to identyfikator bazy danych.

Utwórz zapytanie o najbliższych sąsiadów

Możesz przeprowadzić wyszukiwanie podobieństwa, aby znaleźć najbliższych sąsiadów wektora dystrybucyjnego wektorowego. Wyszukiwanie podobieństw wymaga indeksów wektorów. Jeśli indeks nie istnieje, Cloud Firestore zaproponuje indeks do utworzenia przy użyciu interfejsu wiersza poleceń gcloud.

Python
from google.cloud.firestore_v1.base_vector_query import DistanceMeasure

collection = collection("coffee-beans")

# Requires vector index
collection.find_nearest(
   vector_field="embedding_field",
   query_vector=Vector([3.0, 1.0, 2.0]),
   distance_measure=DistanceMeasure.EUCLIDEAN,
   limit=5)
    
Node.js
import {
  Firestore,
  FieldValue,
  VectorQuery,
  VectorQuerySnapshot,
} from "@google-cloud/firestore";

// Requires single-field vector index
const vectorQuery: VectorQuery = coll.findNearest('embedding_field', FieldValue.vector([3.0, 1.0, 2.0]), {
  limit: 5,
  distanceMeasure: 'EUCLIDEAN'
});

const vectorQuerySnapshot: VectorQuerySnapshot = await vectorQuery.get();
    

Odległości wektorowe

Zapytania o najbliższy sąsiad obsługują następujące opcje odległości wektora:

  • EUCLIDEAN: mierzy odległość UECLIDEAN między wektorami. Więcej informacji: euklidesowa.
  • COSINE: porównuje wektory na podstawie kąta między nimi, co pozwala zmierzyć podobieństwo, które nie jest oparte na wielkości wektorów. Zalecamy używanie funkcji DOT_PRODUCT z wektorami znormalizowanymi jednostkami zamiast odległości COSINE, która jest odpowiednikiem matematycznym o większej wydajności. Więcej informacji znajdziesz w sekcji Podobieństwo cosinusowe.
  • DOT_PRODUCT: podobny do COSINE, ale zależy od wielkości wektorów. Więcej informacji znajdziesz w artykule Iloczyn skalarny.

Wstępnie filtruj dane

Aby wstępnie przefiltrować dane przed znalezieniem najbliższych sąsiadów, możesz połączyć wyszukiwanie podobieństw z innymi filtrami oprócz filtrów nierówności. Obsługiwane są filtry złożone and i or. W przypadku filtrów pól obsługiwane są te filtry:

  • == równa się
  • in
  • array_contains
  • array_contains_any
Python
# Similarity search with pre-filter
# Requires composite vector index
collection.where("color", "==", "red").find_nearest(
   vector_field="embedding_field",
   query_vector=Vector([3.0, 1.0, 2.0]),
   distance_measure=DistanceMeasure.EUCLIDEAN,
   limit=5)
    
Node.js
// Similarity search with pre-filter
// Requires composite vector index
const preFilteredVectorQuery: VectorQuery = coll
  .where("color", "==", "red")
  .findNearest("embedding_field", FieldValue.vector([3.0, 1.0, 2.0]), {
    limit: 5,
    distanceMeasure: "EUCLIDEAN",
  });

vectorQueryResults = await preFilteredVectorQuery.get();
    

Ograniczenia

Korzystając z wektorów dystrybucyjnych wektorowych, pamiętaj o następujących ograniczeniach:

  • Maksymalny obsługiwany wymiar wektora dystrybucyjnego to 2048. Aby przechowywać większe indeksy, użyj redukcji wymiarów.
  • Maksymalna liczba dokumentów do zwrócenia z zapytania o najbliższych sąsiadów to 1000.
  • Wyszukiwanie wektorowe nie obsługuje detektorów zrzutów w czasie rzeczywistym.
  • Do wstępnego filtrowania danych nie można używać filtrów nierówności.
  • Tylko biblioteki klienta Python i Node.js obsługują wyszukiwanie wektorowe.

Co dalej?