Menelusuri dengan embedding vektor

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

  • 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 embedding teks dari data Cloud Firestore, dan menyimpannya di dokumen Cloud Firestore.

Operasi tulis dengan embedding vektor

Contoh berikut menunjukkan cara menyimpan embedding vektor dalam dokumen 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])
});
    

Embedding vektor komputasi 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 penyematan vektor.
  • database-id adalah ID database.
  • vector-configuration menyertakan 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 gabungan

Contoh berikut membuat indeks vektor gabungan untuk kolom color dan kolom penyematan 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 kesamaan memerlukan indeks vektor. Jika indeks tidak ada, Cloud 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 antar-vektor. Untuk mempelajari lebih lanjut, lihat Euclidean.
  • COSINE: Membandingkan vektor berdasarkan sudut antar-vektor sehingga Anda dapat mengukur kesamaan yang tidak berdasarkan pada besaran vektor. Sebaiknya gunakan DOT_PRODUCT dengan vektor yang dinormalisasi satuan, bukan jarak COSINE, yang secara matematis setara dengan performa yang lebih baik. Untuk mempelajari lebih lanjut, lihat Kesamaan Cosine untuk mempelajari lebih lanjut.
  • DOT_PRODUCT: Serupa dengan COSINE, tetapi terpengaruh oleh besarnya vektor. Untuk mempelajari lebih lanjut, lihat Produk titik.

Data pra-filter

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:

  • Dimensi penyematan maksimum yang didukung adalah 2048. Untuk menyimpan indeks yang lebih besar, gunakan pengurangan dimensiitas.
  • Jumlah maksimum dokumen yang akan 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