Ricerca con incorporamenti vettoriali
La pagina mostra come utilizzare Firestore per eseguire il comando K-più vicino le ricerche del vettore 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 misure 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 riportato di seguito mostra come archiviare un embedding vettoriale in un documento Firestore:
Python
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 Run:
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. Gli esempi riportati di seguito mostrano come creare e gestire gli indici di vettori.
Creare un indice di vettori
Prima di creare un indice vettoriale, esegui l'upgrade alla versione più recente di Google Cloud CLI:
gcloud components update
Per creare un indice vettoriale, utilizza gcloud firestore indexes composite create
:
gcloud
gcloud 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 essereflat
. 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 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 firestore indexes composite list --database=database-id
Sostituisci database-id con l'ID del database.
Eliminare un indice di vettori
gcloud
gcloud 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 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.
Il seguente esempio trova i 10 vicini più prossimi del vettore di query.
Python
Node.js
import { Firestore, FieldValue, VectorQuery, VectorQuerySnapshot, } from "@google-cloud/firestore"; // Requires a single-field vector index const vectorQuery: VectorQuery = coll.findNearest({ vectorField: 'embedding_field', queryVector: [3.0, 1.0, 2.0], limit: 10, 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 EUCLIDEA 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 utilizzareDOT_PRODUCT
con vettori normalizzati dell'unità anziché la distanza COSINE, che è matematicamente equivalente con una le prestazioni dei dispositivi. Per saperne di più, vedi Somiglianza della coseno da imparare altro ancora.DOT_PRODUCT
: simile aCOSINE
, ma è influenzata dalla grandezza della vettori di rete. Per saperne di più, vedi Prodotto Dot.
Scegli la misura della distanza
A seconda che tutti gli embedding vettoriali siano o meno normalizzati, puoi determinare quale misura della distanza utilizzare per trovare la misura della distanza. Un modello l'incorporamento vettoriale ha una grandezza (lunghezza) esattamente 1,0.
Inoltre, se conosci la misura della distanza con cui è stato addestrato il modello, utilizzala per calcolare la distanza tra gli embedding vettore.
Dati normalizzati
Se si dispone di un set di dati in cui tutti gli incorporamenti vettoriali sono normalizzati,
le misure di distanza forniscono gli stessi risultati di ricerca semantici. In sostanza, anche se ogni
distanza misura restituisce un valore diverso, i valori vengono ordinati nello stesso modo. Quando gli embedding sono normalizzati, DOT_PRODUCT
è in genere il più efficiente dal punto di vista computazionale, ma la differenza è trascurabile nella maggior parte dei casi. Tuttavia, se le tue
è molto sensibile alle prestazioni, DOT_PRODUCT
potrebbe aiutarti con
dell'ottimizzazione delle prestazioni.
Dati non normalizzati
Se hai un set di dati in cui gli incorporamenti vettoriali non sono normalizzati,
allora non è matematicamente corretto usare DOT_PRODUCT
come distanza
misurare perché il prodotto scalare non misura la distanza. A seconda
su come sono stati generati gli incorporamenti e
sul tipo di ricerca preferito,
la misura della distanza COSINE
o EUCLIDEAN
produce
risultati di ricerca soggettivamente migliori rispetto alle altre misure di distanza.
La sperimentazione con COSINE
o EUCLIDEAN
potrebbe
per stabilire qual è la migliore per il tuo caso d'uso.
Non so se i dati sono normalizzati o non normalizzati
Se non sai con certezza se i tuoi dati sono normalizzati e vuoi utilizzare
DOT_PRODUCT
, ti consigliamo di utilizzare COSINE
.
COSINE
è come DOT_PRODUCT
con la normalizzazione integrata.
La distanza misurata utilizzando COSINE
va da 0
a 2
. Un risultato
un valore vicino a 0
indica che i vettori sono molto simili.
Prefiltra i documenti
Per prefiltrare i documenti prima di trovare i vicini più vicini, puoi combinare una ricerca di somiglianza con altri operatori di query. Le and
e
Sono supportati or
filtri compositi. Per ulteriori informazioni sui filtri dei campi supportati, consulta Operatori di query.
Python
Node.js
// Similarity search with pre-filter // Requires composite vector index const preFilteredVectorQuery: VectorQuery = coll .where("color", "==", "red") .findNearest({ vectorField: "embedding_field", queryVector: [3.0, 1.0, 2.0], limit: 5, distanceMeasure: "EUCLIDEAN", }); const vectorQueryResults = await preFilteredVectorQuery.get();
Recupera la distanza vettoriale calcolata
Puoi recuperare la distanza vettoriale calcolata assegnando una
distance_result_field
nome della proprietà di output nella query FindNearest
, come
come mostrato nell'esempio seguente:
Python
Node.js
const vectorQuery: VectorQuery = coll.findNearest( { vectorField: 'embedding_field', queryVector: [3.0, 1.0, 2.0], limit: 10, distanceMeasure: 'EUCLIDEAN', distanceResultField: 'vector_distance' }); const snapshot: VectorQuerySnapshot = await vectorQuery.get(); snapshot.forEach((doc) => { console.log(doc.id, ' Distance: ', doc.get('vector_distance')); });
Se vuoi utilizzare una maschera di campo per restituire un sottoinsieme di campi del documento insieme a un distanceResultField
, devi includere anche il valore distanceResultField
nella maschera del campo, come mostrato nell'esempio seguente:
Python
Node.js
const vectorQuery: VectorQuery = coll .select('color', 'vector_distance') .findNearest({ vectorField: 'embedding_field', queryVector: [3.0, 1.0, 2.0], limit: 10, distanceMeasure: 'EUCLIDEAN', distanceResultField: 'vector_distance' });
Specifica una soglia di distanza
Puoi specificare una soglia di somiglianza che restituisce solo i documenti all'interno di soglia. Il comportamento del campo della soglia dipende dalla misura della distanza scegli:
- Le distanze
EUCLIDEAN
eCOSINE
limitano la soglia ai documenti in cui la distanza è minore o uguale alla soglia specificata. Queste distanze diminuiscono man mano che i vettori diventano più simili. - La distanza
DOT_PRODUCT
limita la soglia ai documenti in cui la distanza è maggiore o uguale alla soglia specificata. Distanze prodotto scalare aumentano man mano che i vettori diventano più simili.
L'esempio seguente mostra come specificare una soglia di distanza per restituire fino a 10 documenti più vicini che si trovano a una distanza massima di 4,5 unità utilizzando la metrica di distanza EUCLIDEAN
:
Python
Node.js
const vectorQuery: VectorQuery = coll.findNearest({ vectorField: 'embedding_field', queryVector: [3.0, 1.0, 2.0], limit: 10, distanceMeasure: 'EUCLIDEAN', distanceThreshold: 4.5 }); const snapshot: VectorQuerySnapshot = await vectorQuery.get(); snapshot.forEach((doc) => { console.log(doc.id); });
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.
- Solo le librerie client Python e Node.js supportano la ricerca vettoriale.
Passaggi successivi
- Leggi le best practice per Firestore.
- Comprendere le letture e le scritture su larga scala.