Cerca con incorporamenti vettoriali

La pagina mostra come utilizzare Firestore per eseguire ricerche vettoriali K-Neighbor (KNN) utilizzando queste tecniche:

  • Archivia i valori dei vettori
  • Crea e gestisci indici vettoriali KNN
  • Esegui una query K-Neighbor (KNN) usando una delle funzioni di distanza vettoriale supportate

Archivia gli incorporamenti vettoriali

Puoi creare valori vettoriali come incorporamenti di testo dai tuoi dati Firestore e archiviarli nei documenti Firestore.

Operazione di scrittura con un incorporamento vettoriale

L'esempio seguente mostra come archiviare un incorporamento vettoriale in un documento 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])
});
    

Calcola gli incorporamenti vettoriali con una Cloud Function

Per calcolare e archiviare gli incorporamenti vettoriali ogni volta che un documento viene aggiornato o creato, puoi configurare una funzione 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,
  });
}
    

Crea e gestisci indici vettoriali

Prima di poter eseguire una ricerca per il vicino più prossimo con gli incorporamenti vettoriali, devi creare un indice corrispondente. I seguenti esempi mostrano come creare e gestire gli indici vettoriali.

Creare un indice vettoriale a campo singolo

Per creare un indice vettoriale a campo singolo, utilizza 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
    

dove:

  • collection-group è l'ID del gruppo di raccolte.
  • vector-field è il nome del campo che contiene l'incorporamento vettoriale.
  • database-id è l'ID del database.
  • vector-configuration include il vettore dimension e il tipo di indice. dimension è un numero intero fino a 2048. Il tipo di indice deve essere flat. Formatta la configurazione dell'indice come segue: {"dimension":"DIMENSION", "flat": "{}"}.

Creare un indice vettoriale composto

L'esempio seguente crea un indice vettoriale composto per il campo color e un campo di incorporamento vettoriale.

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
    

Elenca tutti gli indici vettoriali

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

Sostituisci database-id con l'ID del database.

Eliminare un indice vettoriale

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

dove:

  • index-id è l'ID dell'indice da eliminare. Utilizza indexes composite list per recuperare l'ID indice.
  • database-id è l'ID del database.

Descrivere un indice vettoriale

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

dove:

  • index-id è l'ID dell'indice da descrivere. Utilizza o indexes composite list per recuperare l'ID indice.
  • database-id è l'ID del database.

Eseguire una query per il vicino più prossimo

Puoi eseguire una ricerca di somiglianza per trovare i vicini più prossimi di un incorporamento vettoriale. Le ricerche di analogie richiedono indici vettoriali. Se non esiste un indice, Firestore suggerisce un indice da creare utilizzando gcloud CLI.

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

Distanze vettoriali

Le query per il vicino più vicino supportano le seguenti opzioni per la distanza vettoriale:

  • EUCLIDEAN: misura la distanza EUCLIDEAN tra i vettori. Per scoprire di più, vedi Euclidea.
  • COSINE: confronta i vettori in base all'angolo tra di loro, il che consente di misurare la somiglianza che non si basa sulla grandezza dei vettori. Ti consigliamo di utilizzare DOT_PRODUCT con vettori normalizzati dell'unità anziché la distanza COSINE, che è matematicamente equivalente con prestazioni migliori. Per saperne di più, consulta Somiglianza tra coseno.
  • DOT_PRODUCT: simile a COSINE, ma è influenzata dalla grandezza dei vettori. Per scoprire di più, vedi Prodotto Dot.

Dati prefiltro

Per prefiltrare i dati prima di trovare i vicini più prossimi, puoi combinare una ricerca di similitudine con altri filtri, ad eccezione dei filtri di disuguaglianza. Sono supportati i filtri composti and e or. Per i filtri di campo, sono supportati i seguenti filtri:

  • == uguale a
  • 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();
    

Limitazioni

Quando lavori con gli incorporamenti vettoriali, tieni presente le seguenti limitazioni:

  • La dimensione di incorporamento massima supportata è 2048. Per archiviare indici più grandi, utilizza la riduzione della dimensionalità.
  • Il numero massimo di documenti da restituire da una query al vicino più prossimo è 1000.
  • La ricerca vettoriale non supporta i listener di snapshot in tempo reale.
  • Non puoi utilizzare i filtri di disuguaglianze per prefiltrare i dati.
  • Solo le librerie client Python e Node.js supportano la ricerca vettoriale.

Passaggi successivi