Effectuer une recherche à l'aide de représentations vectorielles continues
Cette page vous explique comment utiliser Firestore pour effectuer les K-plus proches de voisinage (KNN) à l'aide des techniques suivantes:
- Stocker des valeurs vectorielles
- Créer et gérer des index vectoriels KNN
- Effectuer une requête KNN (le voisin le plus proche) à l'aide de l'un des vecteurs compatibles fonctions de distance
Stocker les embeddings vectoriels
Vous pouvez créer des valeurs vectorielles, telles que des représentations vectorielles continues de texte, à partir de votre et les stocker dans des documents Firestore.
Opération d'écriture avec une représentation vectorielle continue de vecteur
L'exemple suivant montre comment stocker une représentation vectorielle continue de vecteur dans un Document 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]) });
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 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, }); }
Créer et gérer des index vectoriels
Avant de pouvoir effectuer une recherche du voisin le plus proche avec vos représentations vectorielles continues, vous devez créer un index correspondant. Les exemples suivants montrent comment créer et gérer des index vectoriels.
Créer un index vectoriel
Pour créer un index vectoriel, utilisez
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
où :
- collection-group est l'ID du groupe de collections.
- vector-field est le nom du champ qui contient la représentation vectorielle continue du vecteur.
- 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 jusqu'à 2 048. Le type d'index doit êtreflat
. Mettez en forme la configuration d'index comme suit:{"dimension":"DIMENSION", "flat": "{}"}
.
L'exemple suivant crée un index composite, y compris un index vectoriel pour le champ vector-field
.
et un index croissant pour le champ color
. Vous pouvez utiliser ce type d'index pour pré-filtrer
données avant une recherche de voisin le plus proche.
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
Répertorier tous les index vectoriels
gcloud
gcloud alpha firestore indexes composite list --database=database-id
Remplacez database-id par l'ID de la base de données.
Supprimer un index vectoriel
gcloud
gcloud alpha firestore indexes composite delete index-id --database=database-id
où :
- index-id est l'ID de l'index à supprimer.
Utilisez
indexes composite list
pour récupérer l'ID d'index. - database-id est l'ID de la base de données.
Décrire un index vectoriel
gcloud
gcloud alpha firestore indexes composite describe index-id --database=database-id
où :
- index-id est l'ID de l'index à décrire. Utiliser ou
indexes composite list
pour récupérer l'ID d'index. - database-id est l'ID de la base de données.
Effectuer une requête sur le voisin le plus proche
Vous pouvez effectuer une recherche par similarité pour trouver les voisins les plus proches de représentations vectorielles continues. Les recherches de similarité nécessitent des index vectoriels. Si aucun index n'existe, Firestore suggère un index à créer à l'aide de la 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();
Distances vectorielles
Les requêtes des voisins les plus proches acceptent les options suivantes pour la distance vectorielle:
EUCLIDEAN
: mesure la distance EUCLIDEAN entre les vecteurs. Pour en savoir plus, consultez Euclidienne.COSINE
: compare les vecteurs en fonction de l'angle qui les sépare, ce qui vous permet pour mesurer la similarité qui n'est pas basée sur l'amplitude des vecteurs. Nous vous recommandons d'utiliserDOT_PRODUCT
avec des vecteurs normalisés unitaires plutôt que COSINE, ce qui équivaut mathématiquement à des performances. Pour en savoir plus, consultez Similarité cosinus à apprendre plus encore.DOT_PRODUCT
: semblable àCOSINE
, mais il est affecté par la magnitude de l'erreur des vecteurs. Pour en savoir plus, consultez Produit scalaire :
Préfiltrer les données
Pour préfiltrer les données avant de trouver les voisins les plus proches, vous pouvez combiner un
la recherche de similarités avec d'autres filtres à l'exception des filtres d'inégalité. Les and
et
Les filtres composites or
sont acceptés. Pour les filtres de champ :
filtres pris en charge:
==
equal to (égal à)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();
Limites
Lorsque vous utilisez des représentations vectorielles continues, tenez compte des limites suivantes:
- La dimension de représentation vectorielle continue maximale acceptée est de 2 048. Pour stocker des index plus volumineux, utilisez réduction de la dimensionnalité.
- Le nombre maximal de documents à renvoyer à partir d'une requête du 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.
- Vous ne pouvez pas utiliser de filtres d'inégalité pour préfiltrer les données.
- Seules les bibliothèques clientes Python et Node.js sont compatibles avec la recherche vectorielle.
Étape suivante
- Découvrez les bonnes pratiques pour Firestore.
- Comprendre les opérations de lecture et d'écriture à grande échelle