Auf dieser Seite wird beschrieben, wie Sie mit Cloud Firestore KNN-Vektorsuchen (K-Nearest-Neighbor) mit den folgenden Techniken durchführen:
- Vektorwerte speichern
- KNN-Vektorindizes erstellen und verwalten
- KNN-Abfrage (K-Nearest-Neighbor) mit einem der unterstützten Vektordistanzmaße erstellen
Hinweis
Bevor Sie Einbettungen in Cloud Firestore speichern können, müssen Sie Vektoreinbettungen generieren. Cloud Firestore generiert die Einbettungen nicht. Sie können einen Dienst wie Agent Platform verwenden, um Vektorwerte zu erstellen, z. B. Texteinbettungen aus Ihren Cloud Firestore-Daten. Anschließend können Sie diese Einbettungen wieder in Cloud Firestore-Dokumenten speichern.
Weitere Informationen zu Einbettungen finden Sie unter Was sind Einbettungen?.
Informationen zum Abrufen von Texteinbettungen mit Agent Platform finden Sie unter Texteinbettungen abrufen.
Vektoreinbettungen speichern
Die folgenden Beispiele zeigen, wie Vektoreinbettungen in Cloud Firestore gespeichert werden.
Schreibvorgang mit einer Vektoreinbettung
Im folgenden Beispiel wird gezeigt, wie Sie eine Vektoreinbettung in einem Cloud Firestore-Dokument speichern:
Python
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
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();
Vektoreinbettungen mit einer Cloud Functions-Funktion berechnen
Wenn Sie Vektoreinbettungen berechnen und speichern möchten, wenn ein Dokument aktualisiert oder erstellt wird, können Sie eine Cloud Functions-Funktion einrichten:
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
Vektorindexe erstellen und verwalten
Bevor Sie mit Ihren Vektoreinbettungen eine Suche nach dem nächsten Nachbarn durchführen können, müssen Sie einen entsprechenden Index erstellen. In den folgenden Beispielen wird gezeigt, wie Sie Vektorindexe mit dem Google Cloud CLI und der Console erstellen und verwalten. Sie können Vektorindexe auch mit der Firebase CLI und Terraform verwalten.
Vektorindex erstellen
Google Cloud Console
So erstellen Sie manuell einen neuen Index über die Google Cloud Console:
- Rufen Sie in der Google Cloud Console die Seite Datenbanken auf.
- Wählen Sie die benötigte Datenbank aus der Liste der Datenbanken aus.
- Klicken Sie im Navigationsmenü auf Indexe und dann auf den Tab Manuell.
- Klicken Sie auf Index erstellen.
Wenn Sie ein Vektorfeld für Vektorsuchen indexieren möchten, wählen Sie Vektorindex erstellen aus.
-
Geben Sie eine Sammlungs-ID ein. Geben Sie einen Vektorfeldpfad und die Anzahl der Vektoreinbettungsdimensionen ein. Fügen Sie die Namen aller zusätzlichen Felder, die Sie indexieren möchten, und einen Indexmodus für jedes Feld hinzu.
Klicken Sie auf Index speichern.
Der neue Index wird in der Liste der manuellen Indexe angezeigt und Cloud Firestore beginnt mit der Erstellung des Index. Wenn der Index erstellt wurde, wird neben dem Index ein grünes Häkchen angezeigt.
gcloud
Bevor Sie einen Vektorindex erstellen, führen Sie ein Upgrade auf die aktuelle Version von Google Cloud CLI durch:
gcloud components update
Verwenden Sie zum Erstellen eines Vektorindex 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
Dabei gilt:
- collection-group ist die ID der Sammlungsgruppe.
- vector-field ist der Name des Felds, das die Vektoreinbettung enthält.
- database-id ist die ID der Datenbank.
- vector-configuration enthält den Vektor
dimensionund den Indextyp.dimensionist eine Ganzzahl bis 2048. Der Indextyp mussflatsein. Formatieren Sie die Indexkonfiguration so:{"dimension":"DIMENSION", "flat": "{}"}.
Im folgenden Beispiel wird ein zusammengesetzter Index erstellt, einschließlich eines Vektorindex für das Feld vector-field und eines aufsteigenden Index für das Feld color. Mit diesem Indextyp können Sie Daten vorfiltern, bevor Sie nach dem nächsten Nachbarn suchen.
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
Alle Vektorindexe auflisten
Google Cloud Console
- Rufen Sie in der Google Cloud Console die Seite Datenbanken auf.
- Wählen Sie die benötigte Datenbank aus der Liste der Datenbanken aus.
-
Klicken Sie im Navigationsmenü auf Indexe und dann auf den Tab Manuell.
In der Indextabelle sind alle Indexe für die Datenbank aufgeführt. Vektorindexe enthalten ein Vektorfeld mit dem Symbol .
gcloud
So listen Sie alle Indexe auf und rufen Index-IDs ab:
gcloud firestore indexes composite list --database=database-id
Ersetzen Sie database-id durch die ID der Datenbank.
Sie können die Index-ID verwenden, um weitere Details zu einem Index aufzurufen:
gcloud firestore indexes composite describe index-id --database=database-id
Dabei gilt:
- index-id ist die ID des Index, der beschrieben werden soll.
- database-id ist die ID der Datenbank.
Vektorindex löschen
Google Cloud Console
- Rufen Sie in der Google Cloud Console die Seite Datenbanken auf.
- Wählen Sie die benötigte Datenbank aus der Liste der Datenbanken aus.
-
Klicken Sie im Navigationsmenü auf Indexe und dann auf den Tab Manuell.
- Klicken Sie in der Liste Ihrer manuellen Indexe auf den Button Mehr für den Index, den Sie löschen möchten. Klicken Sie auf Löschen.
- Bestätigen Sie, dass Sie diesen Index löschen möchten, indem Sie in der Benachrichtigung auf Index löschen klicken.
gcloud
gcloud firestore indexes composite delete index-id --database=database-id
Dabei gilt:
- index-id ist die ID des zu löschenden Index.
Verwenden Sie
indexes composite list, um die Index-ID abzurufen. - database-id ist die ID der Datenbank.
Abfrage nach nächsten Nachbarn erstellen
Sie können eine Ähnlichkeitssuche durchführen, um die nächsten Nachbarn einer Vektoreinbettung zu finden. Für Ähnlichkeitssuchen sind Vektorindexe erforderlich. Wenn kein Index vorhanden ist, schlägt Cloud Firestore einen Index vor, der mit dem gcloud CLI erstellt werden soll.
Im folgenden Beispiel werden die 10 nächsten Nachbarn des Abfragevektors ermittelt.
Python
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
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();
Vektorentfernungen
Abfragen nach dem nächsten Nachbarn unterstützen die folgenden Optionen für die Vektordistanz:
EUCLIDEAN: Misst dieEUCLIDEAN-Distanz zwischen den Vektoren. Weitere Informationen finden Sie unter Euklidisch.COSINE: Vergleicht Vektoren anhand des Winkels zwischen ihnen. So können Sie die Ähnlichkeit messen, die nicht auf der Größe der Vektoren basiert. Wir empfehlen,DOT_PRODUCTmit einheitsnormalisierten Vektoren anstelle der KOSINUS-Distanz zu verwenden. Das ist mathematisch äquivalent und bietet eine bessere Leistung. Weitere Informationen finden Sie unter Kosinus-Ähnlichkeit.DOT_PRODUCT: Ähnlich wieCOSINE, wird aber von der Größe der Vektoren beeinflusst. Weitere Informationen finden Sie unter Skalarprodukt.
Entfernungsmaß auswählen
Je nachdem, ob alle Ihre Vektoreinbettungen normalisiert sind, können Sie bestimmen, welches Distanzmaß Sie verwenden möchten, um das Distanzmaß zu finden. Eine normalisierte Vektoreinbettung hat eine Magnitude (Länge) von genau 1,0.
Wenn Sie wissen, mit welchem Distanzmaß Ihr Modell trainiert wurde, verwenden Sie dieses Distanzmaß, um die Distanz zwischen Ihren Vektoreinbettungen zu berechnen.
Normalisierte Daten
Wenn Sie ein Dataset haben, in dem alle Vektoreinbettungen normalisiert sind, liefern alle drei Distanzmessungen dieselben semantischen Suchergebnisse. Im Grunde gibt jedes Distanzmaß zwar einen anderen Wert zurück, aber die Werte werden auf dieselbe Weise sortiert. Wenn Einbettungen normalisiert werden, ist DOT_PRODUCT in der Regel die recheneffizienteste Methode, aber der Unterschied ist in den meisten Fällen vernachlässigbar. Wenn Ihre Anwendung jedoch sehr leistungsempfindlich ist, kann DOT_PRODUCT bei der Leistungsoptimierung helfen.
Nicht normalisierte Daten
Wenn Sie ein Dataset haben, in dem Vektoreinbettungen nicht normalisiert sind, ist es mathematisch nicht korrekt, DOT_PRODUCT als Distanzmaß zu verwenden, da das Skalarprodukt keine Distanz misst. Je nachdem, wie die Einbettungen generiert wurden und welche Art von Suche bevorzugt wird, liefert entweder das Distanzmaß COSINE oder EUCLIDEAN Suchergebnisse, die subjektiv besser sind als die anderen Distanzmaße.
Möglicherweise müssen Sie mit COSINE oder EUCLIDEAN experimentieren, um herauszufinden, was für Ihren Anwendungsfall am besten geeignet ist.
Unklar, ob Daten normalisiert oder nicht normalisiert sind
Wenn Sie sich nicht sicher sind, ob Ihre Daten normalisiert sind, und DOT_PRODUCT verwenden möchten, empfehlen wir stattdessen COSINE.
COSINE ist wie DOT_PRODUCT mit integrierter Normalisierung.
Die mit COSINE gemessene Entfernung liegt zwischen 0 und 2. Ein Ergebnis nahe 0 bedeutet, dass die Vektoren sehr ähnlich sind.
Dokumente vorfiltern
Wenn Sie Dokumente vorfiltern möchten, bevor Sie die nächsten Nachbarn finden, können Sie eine Ähnlichkeitssuche mit anderen Abfrageoperatoren kombinieren. Die zusammengesetzten Filter and und or werden unterstützt. Weitere Informationen zu unterstützten Feldfiltern finden Sie unter Abfrageoperatoren.
Python
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
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();
Berechnete Vektordistanz abrufen
Sie können die berechnete Vektordistanz abrufen, indem Sie der FindNearest-Abfrage einen distance_result_field-Ausgabeattributnamen zuweisen, wie im folgenden Beispiel gezeigt:
Python
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
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")); }
Wenn Sie eine Feldmaske verwenden möchten, um eine Teilmenge von Dokumentfeldern zusammen mit einem distanceResultField zurückzugeben, müssen Sie den Wert von distanceResultField auch in die Feldmaske aufnehmen, wie im folgenden Beispiel gezeigt:
Python
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
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")); }
Entfernungsschwellenwert angeben
Sie können eine Ähnlichkeitsstufe angeben, sodass nur Dokumente innerhalb der Ähnlichkeitsstufe zurückgegeben werden. Das Verhalten des Schwellenwertfelds hängt vom ausgewählten Distanzmaß ab:
- Die Distanzen
EUCLIDEANundCOSINEbeschränken den Schwellenwert auf Dokumente, bei denen die Distanz kleiner oder gleich dem angegebenen Schwellenwert ist. Diese Distanzmaße nehmen ab, je ähnlicher die Vektoren sind. DOT_PRODUCT-Distanz begrenzt den Schwellenwert auf Dokumente, bei denen die Distanz größer oder gleich dem angegebenen Schwellenwert ist. Die Punktprodukt-Distanz nimmt zu, je ähnlicher die Vektoren sind.
Im folgenden Beispiel wird gezeigt, wie Sie einen Distanzgrenzwert angeben, um bis zu 10 nächste Dokumente zurückzugeben, die maximal 4,5 Einheiten entfernt sind.Dabei wird der Distanzmesswert EUCLIDEAN verwendet:
Python
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
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()); }
Beschränkungen
Beachten Sie bei der Arbeit mit Vektoreinbettungen die folgenden Einschränkungen:
- Die maximal unterstützte Einbettungsdimension ist 2048. Wenn Sie größere Indexe speichern möchten, verwenden Sie die Dimensionsreduktion.
- Die maximale Anzahl von Dokumenten, die von einer Abfrage nach dem nächsten Nachbarn zurückgegeben werden können, beträgt 1.000 (nur Einschränkung der Standard-Edition).
- Die Vektorsuche unterstützt keine Echtzeit-Snapshot-Listener.
- Nur die Python-, Node.js-, Go- und Java-Clientbibliotheken unterstützen die Vektorsuche.
Nächste Schritte
- Best Practices für Cloud Firestore
- Lese- und Schreibvorgänge in großem Umfang