Sayfada, aşağıdaki teknikleri kullanarak K en yakın komşu (KNN) vektör aramaları yapmak için Cloud Firestore'ü nasıl kullanacağınız gösterilmektedir:
- Vektör değerlerini depolama
- KNN vektör dizinleri oluşturma ve yönetme
- Desteklenen vektör mesafe ölçümlerinden birini kullanarak K en yakın komşu (KNN) sorgusu oluşturma
Vektör yerleştirmelerini depolama
Cloud Firestore verilerinizden metin yerleştirilmiş öğeleri gibi vektör değerleri oluşturabilir ve bunları Cloud Firestore dokümanlarına kaydedebilirsiniz.
Vektör yerleştirmeyle yazma işlemi
Aşağıdaki örnekte, bir vektör yerleştirmenin Cloud Firestore belgesinde nasıl depolanacağı gösterilmektedir:
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();
Cloud Functions ile vektör yerleştirmelerini hesaplama
Bir doküman güncellendiğinde veya oluşturulduğunda vektör yerleştirmelerini hesaplamak ve depolamak için bir Cloud Functions işlevi oluşturabilirsiniz:
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
Vektör dizinleri oluşturma ve yönetme
Vektör gömmelerinizle en yakın komşu araması yapabilmek için ilgili bir dizin oluşturmanız gerekir. Aşağıdaki örneklerde, Google Cloud CLI ile vektör dizinlerinin nasıl oluşturulacağı ve yönetileceği gösterilmektedir. Vektör dizini, Firebase CLI ve Terraform ile de yönetilebilir.
Vektör dizini oluşturma
Vektör dizini oluşturmadan önce Google Cloud CLI'ün en son sürümüne geçin:
gcloud components update
Vektör dizini oluşturmak için gcloud firestore indexes composite create
simgesini kullanın:
gcloud
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
Bu örnekte:
- collection-group, koleksiyon grubunun kimliğidir.
- vector-field, vektör yerleştirmesini içeren alanın adıdır.
- database-id, veritabanının kimliğidir.
- vector-configuration,
dimension
vektörünü ve dizin türünü içerir.dimension
, 2048'e kadar olan bir tam sayıdır. Dizin türüflat
olmalıdır. Dizin yapılandırmasını şu şekilde biçimlendirin:{"dimension":"DIMENSION", "flat": "{}"}
.
Aşağıdaki örnekte, vector-field
alanı için bir vektör dizini ve color
alanı için artan bir dizin içeren bir birleşik dizin oluşturulmaktadır. En yakın komşu aramasından önce verileri önceden filtrelemek için bu tür bir dizini kullanabilirsiniz.
gcloud
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
Tüm vektör dizinlerini listeleme
gcloud
gcloud firestore indexes composite list --database=database-id
database-id yerine veritabanının kimliğini yazın.
Vektör dizinini silme
gcloud
gcloud firestore indexes composite delete index-id --database=database-id
Bu örnekte:
- index-id, silinecek dizinin kimliğidir.
Dizin kimliğini almak için
indexes composite list
değerini kullanın. - database-id, veritabanının kimliğidir.
Vektör dizini tanımlama
gcloud
gcloud firestore indexes composite describe index-id --database=database-id
Bu örnekte:
- index-id, açıklanacak dizinin kimliğidir. Dizin kimliğini almak için
indexes composite list
değerini kullanın. - database-id, veritabanının kimliğidir.
En yakın komşu sorgusu yapma
Bir vektör yerleştirmenin en yakın komşularını bulmak için benzerlik araması yapabilirsiniz. Benzerlik aramaları için vektör dizini gerekir. Dizin yoksa Cloud Firestore, gcloud CLI kullanılarak oluşturulacak bir dizin önerir.
Aşağıdaki örnekte, sorgu vektörünün en yakın 10 komşusu bulunur.
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();
Vektör mesafeleri
En yakın komşu sorguları, vektör mesafesi için aşağıdaki seçenekleri destekler:
EUCLIDEAN
: Vektörler arasındaki ÖKLEDİK uzaklığı ölçer. Daha fazla bilgi için Euclidean başlıklı makaleyi inceleyin.COSINE
: Vektörleri aralarındaki açıya göre karşılaştırır. Bu sayede, vektörlerin büyüklüğüne göre değil benzerliği ölçebilirsiniz. Daha iyi performansa matematiksel olarak eşdeğer olan KOSİNÜS mesafesi yerine birim normalleştirilmiş vektörlerleDOT_PRODUCT
kullanmanızı öneririz. Daha fazla bilgi için Kosinüs benzerliği başlıklı makaleyi inceleyin.DOT_PRODUCT
:COSINE
'e benzer ancak vektörlerin büyüklüğünden etkilenir. Daha fazla bilgi edinmek için Nokta çarpımı başlıklı makaleyi inceleyin.
Mesafe ölçümünü seçme
Tüm vektör yerleştirmelerinizin normalleştirilip normalleştirilmediğine bağlı olarak, mesafe ölçümünü bulmak için hangi mesafe ölçümünün kullanılacağını belirleyebilirsiniz. Normalleştirilmiş bir vektör yerleştirmesinin büyüklüğü (uzunluğu) tam olarak 1,0'dur.
Ayrıca, modelinizin hangi mesafe ölçümüyle eğitildiğini biliyorsanız vektör yerleştirmeleriniz arasındaki mesafeyi hesaplamak için bu mesafe ölçümünü kullanın.
Normalleştirilmiş veriler
Tüm vektör yerleştirmelerinin normalleştirildiği bir veri kümeniz varsa üç mesafe ölçümünün tümü aynı semantik arama sonuçlarını sağlar. Özünde, her mesafe ölçümü farklı bir değer döndürse de bu değerler aynı şekilde sıralanır. Yerleşimler normalleştirildiğinde DOT_PRODUCT
genellikle en yüksek hesaplama verimliliğine sahiptir ancak çoğu durumda bu fark önemsizdir. Ancak uygulamanız performansa çok duyarlıysa DOT_PRODUCT
, performans ayarlamasında yardımcı olabilir.
Normalleştirilmemiş veriler
Vektör yerleştirmelerinin normalleştirilmediği bir veri kümeniz varsa nokta çarpımı mesafeyi ölçmediği için mesafe ölçümü olarak DOT_PRODUCT
kullanmak matematiksel olarak doğru değildir. Yerleşimlerin nasıl oluşturulduğuna ve tercih edilen arama türüne bağlı olarak COSINE
veya EUCLIDEAN
mesafe ölçümü, diğer mesafe ölçümlerinden öznel olarak daha iyi arama sonuçları üretir.
Kullanım alanınız için hangisinin en iyi olduğunu belirlemek amacıyla COSINE
veya EUCLIDEAN
ile deneme yapmanız gerekebilir.
Verilerin normalleştirilip normalleştirilmediğinden emin değilseniz
Verilerinizin normalleştirilip normalleştirilmediğinden emin değilseniz ve DOT_PRODUCT
kullanmak istiyorsanız bunun yerine COSINE
kullanmanızı öneririz.
COSINE
, normalleştirme özelliğinin yerleşik olduğu DOT_PRODUCT
gibidir.
COSINE
kullanılarak ölçülen mesafe 0
ile 2
aralığındadır. 0
'e yakın bir sonuç, vektörlerin çok benzer olduğunu gösterir.
Belgeleri ön filtreleme
En yakın komşuları bulmadan önce dokümanları önceden filtrelemek için benzerlik aramasını diğer sorgu operatörleriyle birleştirebilirsiniz. and
ve
or
birleşik filtreleri desteklenir. Desteklenen alan filtreleri hakkında daha fazla bilgi için Sorgu operatörleri başlıklı makaleyi inceleyin.
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();
Hesaplanan vektör mesafesini alma
Aşağıdaki örnekte gösterildiği gibi, FindNearest
sorgusunda bir distance_result_field
çıkış mülk adı atayarak hesaplanan vektör mesafesini alabilirsiniz:
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")); }
Bir distanceResultField
ile birlikte doküman alanlarının bir alt kümesini döndürmek için alan maskesi kullanmak istiyorsanız aşağıdaki örnekte gösterildiği gibi distanceResultField
değerini de alan maskesine eklemeniz gerekir:
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")); }
Mesafe eşiği belirtin
Yalnızca eşiğin altındaki dokümanları döndüren bir benzerlik eşiği belirtebilirsiniz. Eşik alanının davranışı, seçtiğiniz mesafe ölçümüne bağlıdır:
EUCLIDEAN
veCOSINE
mesafeleri, eşiği mesafenin belirtilen eşiğe eşit veya eşiğin altında olduğu belgelerle sınırlandırır. Vektörler birbirine daha benzer hale geldikçe bu mesafe ölçümleri azalır.DOT_PRODUCT
mesafe, eşiği mesafenin belirtilen eşiğe eşit veya eşiğin üzerinde olduğu belgelerle sınırlandırır. Vektörler birbirine daha benzer hale geldikçe nokta çarpımı mesafeleri artar.
Aşağıdaki örnekte, EUCLIDEAN
mesafe metriği kullanılarak en fazla 4, 5 birim uzaklıktaki en yakın 10 belgeyi döndürmek için mesafe eşiğinin nasıl belirtileceği gösterilmektedir:
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()); }
Sınırlamalar
Vektör yerleştirmeleriyle çalışırken aşağıdaki sınırlamalara dikkat edin:
- Desteklenen maksimum yerleştirme boyutu 2048'dir. Daha büyük dizinler depolamak için boyut azaltma özelliğini kullanın.
- En yakın komşu sorgusunda döndürülecek maksimum doküman sayısı 1.000'dir.
- Vektör arama, anlık görüntü dinleyicilerini desteklemez.
- Vektör aramayı yalnızca Python, Node.js, Go ve Java istemci kitaplıkları destekler.
Sırada ne var?
- Cloud Firestore ile ilgili en iyi uygulamalar hakkında bilgi edinin.
- Geniş ölçekte okuma ve yazma işlemlerini anlama