Cercare con i vector embedding

Questa pagina mostra come utilizzare Cloud Firestore per eseguire ricerche vettoriali del vicino più prossimo (KNN) utilizzando le seguenti tecniche:

  • Archivia i valori dei vettori
  • Crea e gestisci gli indici vettoriali KNN
  • Esegui una query del vicino più prossimo (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 dati di Cloud Firestore. Puoi quindi archiviare questi embedding nei Cloud Firestore documenti.

Per saperne di più sugli embedding, vedi Che cosa sono gli embedding?

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

Archivia i vector embedding

Gli esempi seguenti 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 Cloud Firestore documento:

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 Cloud Function

Per calcolare e archiviare i vector embedding ogni volta che un documento viene aggiornato o creato, puoi configurare una Cloud Function:

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 del vector embedding. Aggiungi i nomi di tutti i campi aggiuntivi che vuoi indicizzare e una modalità di indice 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, vedrai un segno di spunta verde accanto all'indice.

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. La dimension è un numero intero fino a 2048. Il tipo di indice deve essere flat. Formatta la configurazione dell'indice nel seguente modo: {"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 prefiltrare i dati prima di una ricerca del vicino più prossimo.

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 che vuoi 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 del vicino più prossimo

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

L'esempio seguente trova 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 vettoriali

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ù, vedi Distanza 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 i vettori normalizzati dell'unità anziché la distanza COSINE, che è matematicamente equivalente con un rendimento migliore. Per saperne di più, vedi Somiglianza del coseno.
  • DOT_PRODUCT: simile a COSINE, ma è influenzato dalla grandezza dei vettori. Per saperne di più, vedi Prodotto scalare.

Scegli la misura di distanza

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

Inoltre, se conosci la misura di distanza con cui è stato addestrato il modello, utilizzala per calcolare la distanza tra i 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, anche se ogni misura di distanza restituisce 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 al rendimento, DOT_PRODUCT potrebbe aiutarti a ottimizzare il rendimento.

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 di 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 di distanza COSINE o EUCLIDEAN produce risultati di ricerca soggettivamente migliori rispetto alle altre misure di distanza. Potrebbe essere necessario sperimentare con COSINE o EUCLIDEAN per determinare quale sia la migliore per il tuo caso d'uso.

Non sai se i dati sono normalizzati o non normalizzati

Se non sai se i dati sono normalizzati e vuoi utilizzare DOT_PRODUCT, ti consigliamo di utilizzare invece COSINE. COSINE è simile a 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 prefiltrare i documenti prima di trovare i vicini più prossimi, puoi combinare una ricerca di somiglianze con altri operatori di query. Sono supportati i filtri composti and e or. Per saperne di più sui filtri dei campi supportati, vedi 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 vettoriale calcolata

Puoi recuperare la distanza vettoriale calcolata assegnando un nome di proprietà di output distance_result_field alla 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 all'interno della soglia. Il comportamento del campo soglia dipende dalla misura di distanza scelta:

  • Le distanze EUCLIDEAN e COSINE limitano la soglia ai documenti in cui la distanza è minore 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 del 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 lavori con 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 del vicino più prossimo è 1000 (limitazione solo per la Standard Edition).
  • 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