En la página, se muestra cómo usar Cloud Firestore para realizar la busca vectores de vecinos K-nearest (KNN) con estas técnicas:
- Almacena valores vectoriales
- Crea y administra índices de vectores de KNN
- Haz una consulta de K-vecino más cercano (KNN) mediante una de las funciones de distancia compatibles con vectores
Almacena embeddings de vectores
Puedes crear valores vectoriales, como incorporaciones de texto desde tus datos de Cloud Firestore y almacenarlos en documentos de Cloud Firestore.
Operación de escritura con una embedding de vector
En el siguiente ejemplo se muestra cómo almacenar una embedding de vector en un documento de 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]) });
Calcula incorporaciones vectoriales con una Cloud Function
Para calcular y almacenar incorporaciones vectoriales cada vez que se actualiza o crea un documento puedes configurar 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, }); }
Crea y administra índices vectoriales
Antes de realizar una búsqueda de vecino más cercano con tus incorporaciones vectoriales, debes crear un índice correspondiente. En los siguientes ejemplos, se muestran cómo crear y administrar índices vectoriales.
Crea un índice vectorial
Para crear un índice de vectores, usa
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
Donde:
- collection-group es el ID del grupo de colecciones.
- vector-field es el nombre del campo que contiene la embedding de vector.
- database-id es el ID de la base de datos.
- vector-configuration incluye el vector
dimension
y el tipo de índice.dimension
es un número entero hasta 2,048. El tipo de índice debe serflat
. Da formato a la configuración del índice de la siguiente manera:{"dimension":"DIMENSION", "flat": "{}"}
.
En el siguiente ejemplo, se crea un índice compuesto, que incluye un índice de vectores para el campo vector-field
y un índice ascendente para el campo color
. Puedes usar este tipo de índice para realizar un filtro previo de datos
antes de buscar un vecino más cercano.
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
Enumerar todos los índices vectoriales
gcloud
gcloud alpha firestore indexes composite list --database=database-id
Reemplaza database-id por el ID de la base de datos.
Borra un índice vectorial
gcloud
gcloud alpha firestore indexes composite delete index-id --database=database-id
Donde:
- index-id es el ID del índice que se borrará.
Usa
indexes composite list
para recuperar el ID del índice. - database-id es el ID de la base de datos.
Describir un índice vectorial
gcloud
gcloud alpha firestore indexes composite describe index-id --database=database-id
Donde:
- index-id es el ID del índice que se describirá. Usar o
indexes composite list
para recuperar el ID del índice. - database-id es el ID de la base de datos.
Haz una consulta de vecino más cercano
Puedes realizar una búsqueda de similitud para encontrar los vecinos más cercanos de la embedding de vector. Las búsquedas de similitud requieren índices vectoriales. Si no existe un índice, Cloud Firestore sugiere que crees un índice con 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();
Distancias vectoriales
Las consultas de vecino más cercano admiten las siguientes opciones para la distancia vectorial:
EUCLIDEAN
: Mide la distancia de EUCLIDEAN entre los vectores. Para obtener más información, consulta Euclidea.COSINE
: Compara vectores según el ángulo entre ellos, lo que te permite medir la similitud que no se basa en la magnitud de los vectores. Recomendamos usarDOT_PRODUCT
con vectores normalizados de unidades en lugar de la distancia de COSINE, que es matemáticamente equivalente con un mejor rendimiento. Para obtener más información, consulta Similitud coseno para obtener más información.DOT_PRODUCT
: Es similar aCOSINE
, pero se ve afectado por la magnitud de laos vectores. Para obtener más información, consulta Producto de punto.
Aplica un filtro previo a los datos
Para filtrar previamente los datos antes de encontrar los vecinos más cercanos, puedes combinar
la búsqueda de similitud con otros filtros, excepto los filtros de desigualdad. Se admiten los filtros compuestos and
y or
. Para los filtros de campo, se admiten los siguientes
filtros:
==
igual quein
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();
Limitaciones
Cuando trabajes con incorporaciones vectoriales, ten en cuenta las siguientes limitaciones:
- La dimensión de incorporación máxima admitida es 2,048. Para almacenar índices más grandes, usa reducción de dimensiones.
- La cantidad máxima de documentos que se pueden mostrar con una consulta de vecino más cercano es de 1,000.
- La búsqueda vectorial no admite objetos de escucha de instantáneas en tiempo real.
- No puedes usar filtros de desigualdad para prefiltrar los datos.
- Solo las bibliotecas cliente de Python y Node.js admiten la búsqueda vectorial.
Próximos pasos
- Obtén información sobre las prácticas recomendadas para Cloud Firestore.
- Comprende las operaciones de lectura y escritura a gran escala