Rechercher à l'aide de représentations vectorielles continues

Cette page explique comment utiliser Cloud Firestore pour effectuer des recherches vectorielles de k plus proches voisins (KNN) à l'aide des techniques suivantes:

  • Stocker les valeurs du vecteur
  • Créer et gérer des index vectoriels KNN
  • Envoyer une requête de type k plus proches voisins (KNN) à l'aide de l'une des mesures de distance vectorielle compatibles

Stocker les embeddings vectoriels

Vous pouvez créer des valeurs vectorielles telles que des embeddings de texte à partir de vos données Cloud Firestore et les stocker dans des documents Cloud Firestore.

Écrire une opération avec un embedding vectoriel

L'exemple suivant montre comment stocker un vecteur d'encapsulation dans un document 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([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])
});
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();

Calculer des représentations vectorielles continues avec une fonction Cloud

Pour calculer et stocker des représentations vectorielles continues chaque fois qu'un document est mis à jour ou créé, vous pouvez configurer une fonction Cloud:

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

Créer et gérer des index vectoriels

Avant de pouvoir effectuer une recherche des plus proches voisins avec vos représentations vectorielles continues, vous devez créer un indice correspondant. Les exemples suivants montrent comment créer et gérer des index vectoriels avec Google Cloud CLI. Vous pouvez également gérer les index vectoriels avec la CLI Firebase et Terraform.

Créer un index vectoriel

Avant de créer un index vectoriel, passez à la dernière version de Google Cloud CLI:

gcloud components update

Pour créer un index vectoriel, utilisez 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

où :

  • collection-group est l'ID du groupe de collections.
  • vector-field correspond au nom du champ contenant l'encapsulation vectorielle.
  • database-id est l'ID de la base de données.
  • vector-configuration inclut le vecteur dimension et le type d'index. dimension est un entier inférieur ou égal à 2 048. Le type d'index doit être flat. Formatez la configuration de l'index comme suit: {"dimension":"DIMENSION", "flat": "{}"}.

L'exemple suivant crée un indice composite, y compris un indice vectoriel pour le champ vector-field et un indice croissant pour le champ color. Vous pouvez utiliser ce type d'index pour préfiltrer les données avant une recherche du voisin le plus proche.

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

Répertorier tous les index vectoriels

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

Remplacez database-id par l'ID de la base de données.

Supprimer un indice vectoriel

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

où :

  • index-id correspond à l'ID de l'index à supprimer. Utilisez indexes composite list pour récupérer l'ID de l'index.
  • database-id est l'ID de la base de données.

Décrire un index vectoriel

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

où :

  • index-id correspond à l'ID de l'index à décrire. Utilisez indexes composite list pour récupérer l'ID de l'index.
  • database-id est l'ID de la base de données.

Envoyer une requête de type plus proches voisins

Vous pouvez effectuer une recherche de similarité pour trouver les voisins les plus proches d'un embedding vectoriel. Les recherches de similarité nécessitent des index vectoriels. Si un indice n'existe pas, Cloud Firestore suggère un indice à créer à l'aide de gcloud CLI.

L'exemple suivant trouve les 10 voisins les plus proches du vecteur de requête.

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([3.0, 1.0, 2.0]),
    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();

Distances vectorielles

Les requêtes de voisin le plus proche acceptent les options de distance vectorielle suivantes:

  • EUCLIDEAN: mesure la distance EUCLIDENNE entre les vecteurs. Pour en savoir plus, consultez la section Euclidienne.
  • COSINE: compare les vecteurs en fonction de l'angle qui les sépare, ce qui vous permet de mesurer la similarité qui n'est pas basée sur la magnitude des vecteurs. Nous vous recommandons d'utiliser DOT_PRODUCT avec des vecteurs normalisés unitaires plutôt que la distance COSINE, qui est mathématiquement équivalente avec de meilleures performances. Pour en savoir plus, consultez la section Similitude cosinus.
  • DOT_PRODUCT: semblable à COSINE, mais affecté par la magnitude des vecteurs. Pour en savoir plus, consultez la section Produit scalaire.

Choisir la mesure de distance

Selon que tous vos représentations vectorielles continues sont normalisées ou non, vous pouvez déterminer la mesure de distance à utiliser pour trouver la mesure de distance. Un embedding vectoriel normalisé a une magnitude (longueur) exacte de 1,0.

De plus, si vous savez avec quelle mesure de distance votre modèle a été entraîné, utilisez-la pour calculer la distance entre vos représentations vectorielles continues.

Données normalisées

Si vous disposez d'un ensemble de données dans lequel toutes les représentations vectorielles continues sont normalisées, les trois mesures de distance fournissent les mêmes résultats de recherche sémantique. En substance, bien que chaque mesure de distance renvoie une valeur différente, ces valeurs sont triées de la même manière. Lorsque les représentations vectorielles continues sont normalisées, DOT_PRODUCT est généralement la plus efficace en termes de calcul, mais la différence est négligeable dans la plupart des cas. Toutefois, si votre application est très sensible aux performances, DOT_PRODUCT peut vous aider à les optimiser.

Données non normalisées

Si vous disposez d'un ensemble de données dont les représentations vectorielles continues ne sont pas normalisées, il n'est pas mathématiquement correct d'utiliser DOT_PRODUCT comme mesure de distance, car le produit scalaire ne mesure pas la distance. Selon la manière dont les représentations vectorielles continues ont été générées et le type de recherche privilégié, la mesure de distance COSINE ou EUCLIDEAN produit des résultats de recherche subjectivement meilleurs que les autres mesures de distance. Vous devrez peut-être tester COSINE ou EUCLIDEAN pour déterminer laquelle est la plus adaptée à votre cas d'utilisation.

Vous ne savez pas si les données sont normalisées ou non.

Si vous ne savez pas si vos données sont normalisées et que vous souhaitez utiliser DOT_PRODUCT, nous vous recommandons d'utiliser COSINE à la place. COSINE est semblable à DOT_PRODUCT, avec une normalisation intégrée. La distance mesurée à l'aide de COSINE varie de 0 à 2. Un résultat proche de 0 indique que les vecteurs sont très similaires.

Préfiltrer les documents

Pour préfiltrer les documents avant de trouver les voisins les plus proches, vous pouvez combiner une recherche de similarité avec d'autres opérateurs de requête. Les filtres composites and et or sont acceptés. Pour en savoir plus sur les filtres de champ compatibles, consultez la section Opérateurs de requête.

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

Récupérez la distance vectorielle calculée

Vous pouvez récupérer la distance vectorielle calculée en attribuant un nom de propriété de sortie distance_result_field à la requête FindNearest, comme illustré dans l'exemple suivant:

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([3.0, 1.0, 2.0]),
    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"));
}

Si vous souhaitez utiliser un masque de champ pour renvoyer un sous-ensemble de champs de document avec un distanceResultField, vous devez également inclure la valeur de distanceResultField dans le masque de champ, comme illustré dans l'exemple suivant:

Python
vector_query = collection.select(["color", "vector_distance"]).find_nearest(
    vector_field="embedding_field",
    query_vector=Vector([3.0, 1.0, 2.0]),
    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"));
}

Spécifier un seuil de distance

Vous pouvez spécifier un seuil de similarité qui ne renvoie que les documents qui le respectent. Le comportement du champ de seuil dépend de la mesure de distance que vous choisissez:

  • Les distances EUCLIDEAN et COSINE limitent le seuil aux documents dont la distance est inférieure ou égale au seuil spécifié. Ces mesures de distance diminuent à mesure que les vecteurs deviennent plus similaires.
  • La distance DOT_PRODUCT limite le seuil aux documents dont la distance est supérieure ou égale au seuil spécifié. Les distances de produit scalaire augmentent à mesure que les vecteurs deviennent plus similaires.

L'exemple suivant montre comment spécifier un seuil de distance pour renvoyer jusqu'à 10 documents les plus proches, situés à 4, 5 unités maximum à l'aide de la métrique de distance 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([3.0, 1.0, 2.0]),
    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());
}

Limites

Lorsque vous utilisez des embeddings vectoriels, tenez compte des limites suivantes:

  • La dimension d'encapsulation maximale acceptée est de 2 048. Pour stocker des index plus volumineux, utilisez la réduction de la dimensionnalité.
  • Le nombre maximal de documents à renvoyer à partir d'une requête de voisin le plus proche est de 1 000.
  • La recherche vectorielle n'est pas compatible avec les écouteurs d'instantanés en temps réel.
  • Seules les bibliothèques clientes Python, Node.js, Go et Java sont compatibles avec la recherche vectorielle.

Étape suivante