Cerca con incorporamenti vettoriali

La pagina mostra come utilizzare Firestore per eseguire la query K-più vicina le ricerche di vettori di vicini (KNN) utilizzando le seguenti tecniche:

  • Archivia i valori dei vettori
  • Crea e gestisci indici vettoriali KNN
  • Esegui una query K-Neighbor (KNN) utilizzando uno dei vettori supportati funzioni di distanza

Archivia gli incorporamenti vettoriali

Puoi creare valori vettoriali come gli incorporamenti di testo dal tuo Firestore e archiviali in 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 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 dimostrano come creare e gestire gli indici vettoriali.

Crea un indice vettoriale

Per creare un indice vettoriale, 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": "{}"}.

L'esempio seguente crea un indice composto, incluso un indice vettoriale per il campo vector-field e un indice crescente per il campo color. Puoi utilizzare questo tipo di indice per pre-filtrare dati prima della ricerca del vicino più prossimo.

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=vector-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 una all'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 saperne di più, vedi Euclidea.
  • COSINE: confronta i vettori in base all'angolo tra di loro, consentendoti di misurare la somiglianza che non si basa sulla grandezza del vettore. Ti consigliamo di utilizzare DOT_PRODUCT con vettori normalizzati dell'unità anziché la distanza COSINE, che è matematicamente equivalente con una delle prestazioni. Per saperne di più, vedi Somiglianza della coseno da imparare altro ancora.
  • DOT_PRODUCT: simile a COSINE, ma è influenzata dalla grandezza della vettori di rete. Per saperne di più, vedi Prodotto Dot.

Dati prefiltro

Per prefiltrare i dati prima di trovare i vicini più prossimi, puoi combinare una ricerca di somiglianze con altri filtri, ad eccezione dei filtri di disuguaglianze. Le and e Sono supportati or filtri compositi. Per i filtri di campo, quanto segue 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 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