Cercare con i vector embedding

Questa pagina mostra come utilizzare Cloud Firestore per eseguire ricerche vettoriali K-Nearest Neighbor (KNN) utilizzando le seguenti tecniche:

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

Prima di iniziare

Prima di archiviare gli embedding in Cloud Firestore, devi generare vector embedding. Cloud Firestore non genera gli embedding. Puoi utilizzare un servizio come Agent Platform per creare valori vettoriali, ad esempio text embedding dai tuoi dati Cloud Firestore. Puoi quindi archiviare questi embedding nei documenti Cloud Firestore.

Per saperne di più sugli embedding, consulta Cosa sono gli embedding?

Per scoprire come ottenere text embedding con Agent Platform, consulta Ottieni text embedding.

Archivia i vector embedding

I seguenti esempi mostrano come archiviare i vector embedding in Cloud Firestore.

Operazione di scrittura con un vector embedding

L'esempio seguente mostra come archiviare un vector embedding in un documento 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([0.18332680, 0.24160706, 0.3416704]),
}

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])
});
Go
import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/firestore"
)

type CoffeeBean struct {
	Name           string             `firestore:"name,omitempty"`
	Description    string             `firestore:"description,omitempty"`
	EmbeddingField firestore.Vector32 `firestore:"embedding_field,omitempty"`
	Color          string             `firestore:"color,omitempty"`
}

func storeVectors(w io.Writer, projectID string) error {
	ctx := context.Background()

	// Create client
	client, err := firestore.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("firestore.NewClient: %w", err)
	}
	defer client.Close()

	// Vector can be represented by Vector32 or Vector64
	doc := CoffeeBean{
		Name:           "Kahawa coffee beans",
		Description:    "Information about the Kahawa coffee beans.",
		EmbeddingField: []float32{1.0, 2.0, 3.0},
		Color:          "red",
	}
	ref := client.Collection("coffee-beans").NewDoc()
	if _, err = ref.Set(ctx, doc); err != nil {
		fmt.Fprintf(w, "failed to upsert: %v", err)
		return err
	}

	return nil
}
Java
import com.google.cloud.firestore.CollectionReference;
import com.google.cloud.firestore.DocumentReference;
import com.google.cloud.firestore.FieldValue;
import com.google.cloud.firestore.VectorQuery;

CollectionReference coll = firestore.collection("coffee-beans");

Map<String, Object> docData = new HashMap<>();
docData.put("name", "Kahawa coffee beans");
docData.put("description", "Information about the Kahawa coffee beans.");
docData.put("embedding_field", FieldValue.vector(new double[] {1.0, 2.0, 3.0}));

ApiFuture<DocumentReference> future = coll.add(docData);
DocumentReference documentReference = future.get();

Calcola i vector embedding con una funzione Cloud Functions

Per calcolare e archiviare i vector embedding 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,
  });
}
Go
  // Not yet supported in the Go client library
Java
  // Not yet supported in the Java client library

Crea e gestisci gli indici vettoriali

Prima di poter eseguire una ricerca del vicino più prossimo con i vector embedding, devi creare un indice corrispondente. Gli esempi seguenti mostrano come creare e gestire gli indici vettoriali con Google Cloud CLI e la console. Puoi anche gestire gli indici vettoriali con l'interfaccia a riga di comando di Firebase e Terraform.

Crea un indice vettoriale

Console Google Cloud

Per creare manualmente un nuovo indice dalla console Google Cloud:

  1. Nella console Google Cloud, vai alla pagina Database.

    Vai a Database

  2. Seleziona il database richiesto dall'elenco dei database.
  3. Nel menu di navigazione, fai clic su Indici, quindi sulla scheda Manuale.
  4. Fai clic su Crea indice.

    Per indicizzare un campo vettoriale per le ricerche vettoriali, seleziona Crea indice vettoriale.

  5. Inserisci un ID raccolta. Inserisci un percorso del campo vettoriale e il numero di dimensioni di vector embedding. Aggiungi i nomi di eventuali campi aggiuntivi che vuoi indicizzare e una modalità di indicizzazione per ogni campo.

    Fai clic su Salva indice.

Il nuovo indice verrà visualizzato nell'elenco degli indici manuali e Cloud Firestore inizierà a crearlo. Al termine della creazione dell'indice, accanto a quest'ultimo verrà visualizzato un segno di spunta verde.

gcloud

Prima di creare un indice vettoriale, esegui l'upgrade all'ultima versione di Google Cloud CLI:

gcloud components update

Per creare un indice vettoriale, utilizza gcloud firestore indexes composite create:

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 il vector embedding.
  • 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, che include un indice vettoriale per il campo vector-field e un indice crescente per il campo color. Puoi utilizzare questo tipo di indice per prefiltrare i dati prima di una ricerca dei vicini più prossimi.

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

Console Google Cloud

  1. Nella console Google Cloud, vai alla pagina Database.

    Vai a Database

  2. Seleziona il database richiesto dall'elenco dei database.
  3. Nel menu di navigazione, fai clic su Indici, quindi sulla scheda Manuale.

    La tabella degli indici elenca tutti gli indici del database. Gli indici vettoriali includono un campo vettoriale con un'icona .

gcloud

Per elencare tutti gli indici e recuperare gli ID indice:

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

Sostituisci database-id con l'ID del database.

Puoi utilizzare l'ID indice per visualizzare ulteriori dettagli su un indice:

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

dove:

  • index-id è l'ID dell'indice da descrivere.
  • database-id è l'ID del database.

Elimina un indice vettoriale

Console Google Cloud

  1. Nella console Google Cloud, vai alla pagina Database.

    Vai a Database

  2. Seleziona il database richiesto dall'elenco dei database.
  3. Nel menu di navigazione, fai clic su Indici, quindi sulla scheda Manuale.

  4. Nell'elenco degli indici manuali, fai clic sul pulsante Altro per l'indice che vuoi eliminare. Fai clic su Elimina.
  5. Conferma di voler eliminare questo indice facendo clic su Elimina indice nell'avviso.
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.

Esegui una query sui vicini più prossimi

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

L'esempio seguente trova i 10 vicini più prossimi del vettore di query.

Python
from google.cloud.firestore_v1.base_vector_query import DistanceMeasure
from google.cloud.firestore_v1.vector import Vector

collection = db.collection("coffee-beans")

# Requires a single-field vector index
vector_query = collection.find_nearest(
    vector_field="embedding_field",
    query_vector=Vector([0.3416704, 0.18332680, 0.24160706]),
    distance_measure=DistanceMeasure.EUCLIDEAN,
    limit=5,
)
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();
Go
import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/firestore"
)

func vectorSearchBasic(w io.Writer, projectID string) error {
	ctx := context.Background()

	// Create client
	client, err := firestore.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("firestore.NewClient: %w", err)
	}
	defer client.Close()

	collection := client.Collection("coffee-beans")

	// Requires a vector index
	// https://firebase.google.com/docs/firestore/vector-search#create_and_manage_vector_indexes
	vectorQuery := collection.FindNearest("embedding_field",
		[]float32{3.0, 1.0, 2.0},
		5,
		// More info: https://firebase.google.com/docs/firestore/vector-search#vector_distances
		firestore.DistanceMeasureEuclidean,
		nil)

	docs, err := vectorQuery.Documents(ctx).GetAll()
	if err != nil {
		fmt.Fprintf(w, "failed to get vector query results: %v", err)
		return err
	}

	for _, doc := range docs {
		fmt.Fprintln(w, doc.Data()["name"])
	}
	return nil
}
Java
import com.google.cloud.firestore.VectorQuery;
import com.google.cloud.firestore.VectorQuerySnapshot;

VectorQuery vectorQuery = coll.findNearest(
        "embedding_field",
        new double[] {3.0, 1.0, 2.0},
        /* limit */ 10,
        VectorQuery.DistanceMeasure.EUCLIDEAN);

ApiFuture<VectorQuerySnapshot> future = vectorQuery.get();
VectorQuerySnapshot vectorQuerySnapshot = future.get();

Distanze tra vettori

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

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

Scegli la misura della distanza

A seconda che tutti i vector embedding siano normalizzati o meno, puoi determinare quale misura di distanza utilizzare per trovare la misura di distanza. Un vector embedding normalizzato ha una grandezza (lunghezza) esattamente pari a 1,0.

Inoltre, se sai con quale misura di distanza è stato addestrato il tuo modello, utilizza questa misura per calcolare la distanza tra i tuoi vector embedding.

Dati normalizzati

Se hai un set di dati in cui tutti i vector embedding sono normalizzati, tutte e tre le misure di distanza forniscono gli stessi risultati di ricerca semantica. In sostanza, sebbene ogni misura di distanza restituisca un valore diverso, questi 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 la tua applicazione è molto sensibile alle prestazioni, DOT_PRODUCT potrebbe aiutarti a ottimizzarle.

Dati non normalizzati

Se hai un set di dati in cui i vector embedding non sono normalizzati, non è matematicamente corretto utilizzare DOT_PRODUCT come misura della distanza perché il prodotto scalare non misura la distanza. A seconda di come sono stati generati gli embedding e del tipo di ricerca preferito, la misura della distanza COSINE o EUCLIDEAN produce risultati di ricerca soggettivamente migliori rispetto alle altre misure della distanza. Potrebbe essere necessario sperimentare con COSINE o EUCLIDEAN per determinare quale sia la soluzione migliore per il tuo caso d'uso.

Non sai se i dati sono normalizzati o meno

Se non sai 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 varia da 0 a 2. Un risultato vicino a 0 indica che i vettori sono molto simili.

Prefiltra i documenti

Per eseguire il pre-filtraggio dei documenti prima di trovare i vicini più prossimi, puoi combinare una ricerca di somiglianza con altri operatori di query. Sono supportati i filtri compositi and e or. Per ulteriori informazioni sui filtri dei campi supportati, consulta Operatori di query.

Python
from google.cloud.firestore_v1.base_vector_query import DistanceMeasure
from google.cloud.firestore_v1.vector import Vector

collection = db.collection("coffee-beans")

# Similarity search with pre-filter
# Requires a composite vector index
vector_query = collection.where("color", "==", "red").find_nearest(
    vector_field="embedding_field",
    query_vector=Vector([0.3416704, 0.18332680, 0.24160706]),
    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({
      vectorField: "embedding_field",
      queryVector: [3.0, 1.0, 2.0],
      limit: 5,
      distanceMeasure: "EUCLIDEAN",
    });

const vectorQueryResults = await preFilteredVectorQuery.get();
Go
import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/firestore"
)

func vectorSearchPrefilter(w io.Writer, projectID string) error {
	ctx := context.Background()

	// Create client
	client, err := firestore.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("firestore.NewClient: %w", err)
	}
	defer client.Close()

	collection := client.Collection("coffee-beans")

	// Similarity search with pre-filter
	// Requires a composite vector index
	vectorQuery := collection.Where("color", "==", "red").
		FindNearest("embedding_field",
			[]float32{3.0, 1.0, 2.0},
			5,
			// More info: https://firebase.google.com/docs/firestore/vector-search#vector_distances
			firestore.DistanceMeasureEuclidean,
			nil)

	docs, err := vectorQuery.Documents(ctx).GetAll()
	if err != nil {
		fmt.Fprintf(w, "failed to get vector query results: %v", err)
		return err
	}

	for _, doc := range docs {
		fmt.Fprintln(w, doc.Data()["name"])
	}
	return nil
}
Java
import com.google.cloud.firestore.VectorQuery;
import com.google.cloud.firestore.VectorQuerySnapshot;

VectorQuery preFilteredVectorQuery = coll
        .whereEqualTo("color", "red")
        .findNearest(
                "embedding_field",
                new double[] {3.0, 1.0, 2.0},
                /* limit */ 10,
                VectorQuery.DistanceMeasure.EUCLIDEAN);

ApiFuture<VectorQuerySnapshot> future = preFilteredVectorQuery.get();
VectorQuerySnapshot vectorQuerySnapshot = future.get();

Recupera la distanza del vettore calcolata

Puoi recuperare la distanza vettoriale calcolata assegnando un nome alla proprietà di output distance_result_field nella query FindNearest, come mostrato nell'esempio seguente:

Python
from google.cloud.firestore_v1.base_vector_query import DistanceMeasure
from google.cloud.firestore_v1.vector import Vector

collection = db.collection("coffee-beans")

vector_query = collection.find_nearest(
    vector_field="embedding_field",
    query_vector=Vector([0.3416704, 0.18332680, 0.24160706]),
    distance_measure=DistanceMeasure.EUCLIDEAN,
    limit=10,
    distance_result_field="vector_distance",
)

docs = vector_query.stream()

for doc in docs:
    print(f"{doc.id}, Distance: {doc.get('vector_distance')}")
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'));
});
Go
import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/firestore"
)

func vectorSearchDistanceResultField(w io.Writer, projectID string) error {
	ctx := context.Background()

	client, err := firestore.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("firestore.NewClient: %w", err)
	}
	defer client.Close()

	collection := client.Collection("coffee-beans")

	// Requires a vector index
	// https://firebase.google.com/docs/firestore/vector-search#create_and_manage_vector_indexes
	vectorQuery := collection.FindNearest("embedding_field",
		[]float32{3.0, 1.0, 2.0},
		10,
		firestore.DistanceMeasureEuclidean,
		&firestore.FindNearestOptions{
			DistanceResultField: "vector_distance",
		})

	docs, err := vectorQuery.Documents(ctx).GetAll()
	if err != nil {
		fmt.Fprintf(w, "failed to get vector query results: %v", err)
		return err
	}

	for _, doc := range docs {
		fmt.Fprintf(w, "%v, Distance: %v\n", doc.Data()["name"], doc.Data()["vector_distance"])
	}
	return nil
}
Java
import com.google.cloud.firestore.VectorQuery;
import com.google.cloud.firestore.VectorQueryOptions;
import com.google.cloud.firestore.VectorQuerySnapshot;

VectorQuery vectorQuery = coll.findNearest(
        "embedding_field",
        new double[] {3.0, 1.0, 2.0},
        /* limit */ 10,
        VectorQuery.DistanceMeasure.EUCLIDEAN,
        VectorQueryOptions.newBuilder().setDistanceResultField("vector_distance").build());

ApiFuture<VectorQuerySnapshot> future = vectorQuery.get();
VectorQuerySnapshot vectorQuerySnapshot = future.get();

for (DocumentSnapshot document : vectorQuerySnapshot.getDocuments()) {
    System.out.println(document.getId() + " Distance: " + document.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 di distanceResultField nella maschera di campo, come mostrato nell'esempio seguente:

Python
vector_query = collection.select(["color", "vector_distance"]).find_nearest(
    vector_field="embedding_field",
    query_vector=Vector([0.3416704, 0.18332680, 0.24160706]),
    distance_measure=DistanceMeasure.EUCLIDEAN,
    limit=10,
    distance_result_field="vector_distance",
)
Node.js
const vectorQuery: VectorQuery = coll
    .select('name', 'description', 'vector_distance')
    .findNearest({
      vectorField: 'embedding_field',
      queryVector: [3.0, 1.0, 2.0],
      limit: 10,
      distanceMeasure: 'EUCLIDEAN',
      distanceResultField: 'vector_distance'
    });
Go
import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/firestore"
)

func vectorSearchDistanceResultFieldMasked(w io.Writer, projectID string) error {
	ctx := context.Background()

	client, err := firestore.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("firestore.NewClient: %w", err)
	}
	defer client.Close()

	collection := client.Collection("coffee-beans")

	// Requires a vector index
	// https://firebase.google.com/docs/firestore/vector-search#create_and_manage_vector_indexes
	vectorQuery := collection.Select("color", "vector_distance").
		FindNearest("embedding_field",
			[]float32{3.0, 1.0, 2.0},
			10,
			firestore.DistanceMeasureEuclidean,
			&firestore.FindNearestOptions{
				DistanceResultField: "vector_distance",
			})

	docs, err := vectorQuery.Documents(ctx).GetAll()
	if err != nil {
		fmt.Fprintf(w, "failed to get vector query results: %v", err)
		return err
	}

	for _, doc := range docs {
		fmt.Fprintf(w, "%v, Distance: %v\n", doc.Data()["color"], doc.Data()["vector_distance"])
	}
	return nil
}
Java
import com.google.cloud.firestore.VectorQuery;
import com.google.cloud.firestore.VectorQueryOptions;
import com.google.cloud.firestore.VectorQuerySnapshot;

VectorQuery vectorQuery = coll
        .select("name", "description", "vector_distance")
        .findNearest(
          "embedding_field",
          new double[] {3.0, 1.0, 2.0},
          /* limit */ 10,
          VectorQuery.DistanceMeasure.EUCLIDEAN,
          VectorQueryOptions.newBuilder()
            .setDistanceResultField("vector_distance")
            .build());

ApiFuture<VectorQuerySnapshot> future = vectorQuery.get();
VectorQuerySnapshot vectorQuerySnapshot = future.get();

for (DocumentSnapshot document : vectorQuerySnapshot.getDocuments()) {
    System.out.println(document.getId() + " Distance: " + document.get("vector_distance"));
}

Specifica una soglia di distanza

Puoi specificare una soglia di somiglianza che restituisce solo i documenti che rientrano nella soglia. Il comportamento del campo della soglia dipende dalla misura della distanza scelta:

  • Le distanze EUCLIDEAN e COSINE limitano la soglia ai documenti in cui la distanza è inferiore o uguale alla soglia specificata. Queste misure di distanza 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. Le 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
from google.cloud.firestore_v1.base_vector_query import DistanceMeasure
from google.cloud.firestore_v1.vector import Vector

collection = db.collection("coffee-beans")

vector_query = collection.find_nearest(
    vector_field="embedding_field",
    query_vector=Vector([0.3416704, 0.18332680, 0.24160706]),
    distance_measure=DistanceMeasure.EUCLIDEAN,
    limit=10,
    distance_threshold=4.5,
)

docs = vector_query.stream()

for doc in docs:
    print(f"{doc.id}")
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);
});
Go
import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/firestore"
)

func vectorSearchDistanceThreshold(w io.Writer, projectID string) error {
	ctx := context.Background()

	client, err := firestore.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("firestore.NewClient: %w", err)
	}
	defer client.Close()

	collection := client.Collection("coffee-beans")

	// Requires a vector index
	// https://firebase.google.com/docs/firestore/vector-search#create_and_manage_vector_indexes
	vectorQuery := collection.FindNearest("embedding_field",
		[]float32{3.0, 1.0, 2.0},
		10,
		firestore.DistanceMeasureEuclidean,
		&firestore.FindNearestOptions{
			DistanceThreshold: firestore.Ptr[float64](4.5),
		})

	docs, err := vectorQuery.Documents(ctx).GetAll()
	if err != nil {
		fmt.Fprintf(w, "failed to get vector query results: %v", err)
		return err
	}

	for _, doc := range docs {
		fmt.Fprintln(w, doc.Data()["name"])
	}
	return nil
}
Java
import com.google.cloud.firestore.VectorQuery;
import com.google.cloud.firestore.VectorQueryOptions;
import com.google.cloud.firestore.VectorQuerySnapshot;

VectorQuery vectorQuery = coll.findNearest(
        "embedding_field",
        new double[] {3.0, 1.0, 2.0},
        /* limit */ 10,
        VectorQuery.DistanceMeasure.EUCLIDEAN,
        VectorQueryOptions.newBuilder()
          .setDistanceThreshold(4.5)
          .build());

ApiFuture<VectorQuerySnapshot> future = vectorQuery.get();
VectorQuerySnapshot vectorQuerySnapshot = future.get();

for (DocumentSnapshot document : vectorQuerySnapshot.getDocuments()) {
    System.out.println(document.getId());
}

Limitazioni

Quando utilizzi i vector embedding, tieni presente le seguenti limitazioni:

  • La dimensione massima supportata per l'embedding è 2048. Per archiviare indici più grandi, utilizza la riduzione della dimensionalità.
  • Il numero massimo di documenti da restituire da una query di vicini più prossimi è 1000 (limitazione solo per la versione Standard).
  • La ricerca vettoriale non supporta i listener di snapshot in tempo reale.
  • Solo le librerie client Python, Node.js, Go e Java supportano la ricerca vettoriale.

Passaggi successivi