Menelusuri dengan embedding vektor

Halaman ini menunjukkan cara menggunakan Firestore untuk melakukan penelusuran vektor K-nearest Neighbor (KNN) menggunakan teknik berikut:

  • Menyimpan nilai vektor
  • Membuat dan mengelola indeks vektor KNN
  • Membuat kueri K-nearest-neighbor (KNN) menggunakan salah satu fungsi jarak vektor yang didukung

Menyimpan embedding vektor

Anda dapat membuat nilai vektor seperti embeds teks dari data Firestore, dan menyimpannya di dokumen Firestore.

Operasi tulis dengan embedding vektor

Contoh berikut menunjukkan cara menyimpan embedding vektor dalam dokumen Firestore:

Python
from google.cloud import firestore
from google.cloud.firestore_v1.vector import Vector

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])
});
    

Menghitung embedding vektor dengan Cloud Function

Untuk menghitung dan menyimpan embedding vektor setiap kali dokumen diperbarui atau dibuat, Anda dapat menyiapkan 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,
  });
}
    

Membuat dan mengelola indeks vektor

Sebelum dapat melakukan penelusuran tetangga terdekat dengan embedding vektor, Anda harus membuat indeks yang sesuai. Contoh berikut menunjukkan cara membuat dan mengelola indeks vektor.

Membuat indeks vektor kolom tunggal

Untuk membuat indeks vektor kolom tunggal, gunakan 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
    

dengan:

  • collection-group adalah ID grup koleksi.
  • vector-field adalah nama kolom yang berisi embedding vektor.
  • database-id adalah ID database.
  • vector-configuration mencakup vektor dimension dan jenis indeks. dimension adalah bilangan bulat hingga 2048. Jenis indeks harus flat. Format konfigurasi indeks sebagai berikut: {"dimension":"DIMENSION", "flat": "{}"}.

Membuat indeks vektor komposit

Contoh berikut membuat indeks vektor komposit untuk kolom color dan kolom embedding vektor.

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=field,vector-config='{"dimension":"1024", "flat": "{}"}' \
--database=database-id
    

Mencantumkan semua indeks vektor

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

Ganti database-id dengan ID database.

Menghapus indeks vektor

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

dengan:

  • index-id adalah ID indeks yang akan dihapus. Gunakan indexes composite list untuk mengambil ID indeks.
  • database-id adalah ID database.

Menjelaskan indeks vektor

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

dengan:

  • index-id adalah ID indeks yang akan dijelaskan. Gunakan atau indexes composite list untuk mengambil ID indeks.
  • database-id adalah ID database.

Membuat kueri tetangga terdekat

Anda dapat melakukan penelusuran kesamaan untuk menemukan tetangga terdekat dari penyematan vektor. Penelusuran kemiripan memerlukan indeks vektor. Jika indeks tidak ada, Firestore akan menyarankan indeks untuk dibuat menggunakan 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();
    

Jarak vektor

Kueri tetangga terdekat mendukung opsi berikut untuk jarak vektor:

  • EUCLIDEAN: Mengukur jarak EUCLIDEAN antarvektor. Untuk mempelajari lebih lanjut, lihat Euclidean.
  • COSINE: Membandingkan vektor berdasarkan sudut antarvektor, yang memungkinkan Anda mengukur kesamaan yang tidak berdasarkan magnitudo vektor. Sebaiknya gunakan DOT_PRODUCT dengan vektor yang dinormalisasi unit, bukan jarak COSINE, yang secara matematis setara dengan performa yang lebih baik. Untuk mempelajari lebih lanjut, lihat Kesamaan kosinus dan mempelajari lebih lanjut.
  • DOT_PRODUCT: Serupa dengan COSINE tetapi dipengaruhi oleh besarnya vektor. Untuk mempelajari lebih lanjut, lihat Produk Dot.

Filter data terlebih dahulu

Untuk memfilter data terlebih dahulu sebelum menemukan tetangga terdekat, Anda dapat menggabungkan penelusuran kemiripan dengan filter lain, kecuali filter ketidaksetaraan. Filter gabungan and dan or didukung. Untuk filter kolom, filter berikut didukung:

  • == sama dengan
  • 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();
    

Batasan

Saat Anda bekerja dengan embedding vektor, perhatikan batasan berikut ini:

  • Dimensi penyematan maksimum yang didukung adalah 2048. Untuk menyimpan indeks yang lebih besar, gunakan pengurangan dimensi.
  • Jumlah maksimum dokumen untuk ditampilkan dari kueri tetangga terdekat adalah 1.000.
  • Penelusuran vektor tidak mendukung pemroses snapshot real-time.
  • Anda tidak dapat menggunakan filter ketidaksetaraan untuk memfilter data terlebih dahulu.
  • Hanya library klien Python dan Node.js yang mendukung penelusuran vektor.

Langkah selanjutnya