این صفحه به شما نشان میدهد که چگونه از Cloud Firestore برای انجام جستجوهای برداری K-نزدیکترین همسایه (KNN) با استفاده از تکنیکهای زیر استفاده کنید:
- ذخیره مقادیر برداری
- نمایه های برداری KNN را ایجاد و مدیریت کنید
- با استفاده از یکی از اندازه گیری های فاصله برداری پشتیبانی شده، یک جستار K-nearest-neighbor (KNN) ایجاد کنید
جاسازی های وکتور فروشگاهی
می توانید مقادیر برداری مانند جاسازی متن را از داده های Cloud Firestore خود ایجاد کنید و آنها را در اسناد Cloud Firestore ذخیره کنید.
عملیات را با جاسازی برداری بنویسید
مثال زیر نحوه ذخیره وکتور تعبیه شده در یک سند Cloud Firestore را نشان می دهد:
پایتون
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]) });
برو
جاوا
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 Function را تنظیم کنید:
پایتون
@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, }); }
برو
// Not yet supported in the Go client library
جاوا
// Not yet supported in the Java client library
نمایه های برداری را ایجاد و مدیریت کنید
قبل از اینکه بتوانید نزدیکترین همسایه را با جاسازی های برداری خود انجام دهید، باید یک نمایه مربوطه ایجاد کنید. مثالهای زیر نحوه ایجاد و مدیریت نمایههای برداری با Google Cloud CLI را نشان میدهند. نمایه های برداری را می توان با Firebase CLI و Terraform نیز مدیریت کرد .
یک نمایه برداری ایجاد کنید
قبل از ایجاد یک نمایه برداری، به آخرین نسخه Google Cloud CLI ارتقا دهید:
gcloud components update
برای ایجاد یک نمایه برداری، از gcloud firestore indexes composite create
استفاده کنید:
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
کجا:
- collection-group شناسه گروه مجموعه است.
- vector-field نام فیلدی است که حاوی جاسازی برداری است.
- database-id شناسه پایگاه داده است.
- vector-configuration شامل
dimension
برداری و نوع شاخص است.dimension
یک عدد صحیح تا 2048 است. نوع شاخص بایدflat
باشد. پیکربندی فهرست را به صورت زیر قالب بندی کنید:{"dimension":" DIMENSION ", "flat": "{}"}
.
مثال زیر یک شاخص ترکیبی، شامل یک شاخص برداری برای vector-field
و یک شاخص صعودی برای color
فیلد ایجاد می کند. می توانید از این نوع شاخص برای پیش فیلتر کردن داده ها قبل از جستجوی نزدیکترین همسایه استفاده کنید.
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
فهرست تمام نمایه های برداری
gcloud
gcloud firestore indexes composite list --database=database-id
شناسه پایگاه داده را جایگزین database-id کنید.
یک شاخص برداری را حذف کنید
gcloud
gcloud firestore indexes composite delete index-id --database=database-id
کجا:
- index-id شناسه ایندکس برای حذف است.
indexes composite list
برای بازیابی شناسه فهرست استفاده کنید. - database-id شناسه پایگاه داده است.
یک شاخص برداری را توصیف کنید
gcloud
gcloud firestore indexes composite describe index-id --database=database-id
کجا:
- index-id شناسه ایندکس برای توصیف است. برای بازیابی شناسه
indexes composite list
استفاده کنید. - database-id شناسه پایگاه داده است.
پرس و جوی نزدیکترین همسایه را انجام دهید
برای یافتن نزدیکترین همسایگان یک جاسازی برداری، می توانید یک جستجوی مشابه انجام دهید. جستجوهای مشابه به نمایه های برداری نیاز دارند. اگر فهرستی وجود نداشته باشد، Cloud Firestore نمایهای را برای ایجاد با استفاده از gcloud CLI پیشنهاد میکند.
مثال زیر 10 نزدیکترین همسایه بردار پرس و جو را پیدا می کند.
پایتون
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();
برو
جاوا
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();
فواصل برداری
پرس و جوهای نزدیکترین همسایه از گزینه های زیر برای فاصله برداری پشتیبانی می کنند:
-
EUCLIDEAN
: فاصله EUCLIDEAN بین بردارها را اندازه گیری می کند. برای کسب اطلاعات بیشتر، اقلیدسی را ببینید. -
COSINE
: بردارها را بر اساس زاویه بین آنها مقایسه می کند که به شما امکان می دهد شباهتی را اندازه گیری کنید که بر اساس بزرگی بردارها نیست. توصیه می کنیم ازDOT_PRODUCT
با بردارهای نرمال شده واحد به جای فاصله COSINE استفاده کنید که از نظر ریاضی با عملکرد بهتر معادل است. برای کسب اطلاعات بیشتر به شباهت کسینوس مراجعه کنید تا بیشتر بدانید. -
DOT_PRODUCT
: شبیهCOSINE
است اما تحت تأثیر بزرگی بردارها است. برای کسب اطلاعات بیشتر، محصول Dot را ببینید.
اندازه گیری فاصله را انتخاب کنید
بسته به اینکه آیا همه جاسازیهای برداری شما عادی هستند یا نه، میتوانید تعیین کنید که از کدام اندازهگیری فاصله برای یافتن اندازهگیری فاصله استفاده کنید. یک تعبیه برداری نرمال شده دارای بزرگی (طول) دقیقاً 1.0 است.
علاوه بر این، اگر می دانید مدل شما با کدام اندازه گیری فاصله آموزش داده شده است، از آن اندازه گیری فاصله برای محاسبه فاصله بین جاسازی های برداری خود استفاده کنید.
داده های عادی
اگر مجموعه داده ای دارید که در آن همه جاسازی های برداری عادی شده است، هر سه اندازه گیری فاصله نتایج جستجوی معنایی یکسانی را ارائه می دهند. در اصل، اگرچه هر اندازهگیری فاصله مقدار متفاوتی را برمیگرداند، اما این مقادیر به همان روش مرتب میشوند. وقتی تعبیهها عادی میشوند، DOT_PRODUCT
معمولاً از نظر محاسباتی کارآمدترین است، اما تفاوت در بیشتر موارد ناچیز است. با این حال، اگر برنامه شما به عملکرد بسیار حساس است، DOT_PRODUCT
ممکن است به تنظیم عملکرد کمک کند.
داده های غیر عادی
اگر مجموعه داده ای دارید که در آن جاسازی های برداری عادی نشده است، از نظر ریاضی استفاده DOT_PRODUCT
به عنوان اندازه گیری فاصله درست نیست، زیرا محصول نقطه ای فاصله را اندازه نمی گیرد. بسته به نحوه ایجاد جاسازیها و نوع جستجو ترجیح داده میشود، اندازهگیری فاصله COSINE
یا EUCLIDEAN
نتایج جستجویی را تولید میکند که به طور ذهنی بهتر از سایر اندازهگیریهای فاصله است. آزمایش با COSINE
یا EUCLIDEAN
ممکن است برای تعیین اینکه کدام یک برای مورد استفاده شما بهترین است، ضروری باشد.
مطمئن نیستید که داده ها نرمال یا غیر عادی هستند
اگر مطمئن نیستید که دادههایتان عادی هستند یا نه و میخواهید از DOT_PRODUCT
استفاده کنید، توصیه میکنیم به جای آن از COSINE
استفاده کنید. COSINE
مانند DOT_PRODUCT
با نرمال سازی داخلی است. فاصله اندازه گیری شده با استفاده از COSINE
از 0
تا 2
متغیر است. نتیجه نزدیک به 0
نشان می دهد که بردارها بسیار شبیه هستند.
اسناد از پیش فیلتر
برای پیش فیلتر کردن اسناد قبل از یافتن نزدیکترین همسایگان، می توانید جستجوی مشابه را با سایر عملگرهای پرس و جو ترکیب کنید. فیلترهای and
و or
ترکیبی پشتیبانی می شوند. برای اطلاعات بیشتر درباره فیلترهای فیلد پشتیبانی شده، به عملگرهای Query مراجعه کنید.
پایتون
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();
برو
جاوا
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();
فاصله برداری محاسبه شده را بازیابی کنید
همانطور که در مثال زیر نشان داده شده است، می توانید فاصله برداری محاسبه شده را با اختصاص نام ویژگی خروجی distance_result_field
در پرس و جو FindNearest
بازیابی کنید:
پایتون
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')); });
برو
جاوا
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")); }
اگر میخواهید از یک فیلد ماسک برای برگرداندن زیرمجموعهای از فیلدهای سند به همراه distanceResultField
استفاده کنید، باید مقدار distanceResultField
را نیز در ماسک فیلد وارد کنید، همانطور که در مثال زیر نشان داده شده است:
پایتون
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' });
برو
جاوا
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")); }
یک آستانه فاصله را مشخص کنید
شما می توانید یک آستانه تشابه را تعیین کنید که فقط اسناد داخل آستانه را برمی گرداند. رفتار فیلد آستانه به اندازه گیری فاصله ای که انتخاب می کنید بستگی دارد:
- فاصله
EUCLIDEAN
وCOSINE
آستانه را محدود به اسنادی می کند که فاصله آنها کمتر یا مساوی آستانه مشخص شده باشد. این اندازه گیری های فاصله با شبیه شدن بردارها کاهش می یابد. - فاصله
DOT_PRODUCT
آستانه را به اسنادی محدود می کند که فاصله آنها بیشتر یا مساوی آستانه تعیین شده است. فاصله محصول نقطه ای با شبیه شدن بردارها افزایش می یابد.
مثال زیر نشان میدهد که چگونه با استفاده از متریک فاصله EUCLIDEAN
یک آستانه فاصله را برای بازگرداندن حداکثر 10 سند که حداکثر 4.5 واحد دورتر هستند، تعیین کنید:
پایتون
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); });
برو
جاوا
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()); }
محدودیت ها
همانطور که با جاسازی های برداری کار می کنید، به محدودیت های زیر توجه کنید:
- حداکثر بعد تعبیه پشتیبانی شده 2048 است. برای ذخیره نمایه های بزرگتر، از کاهش ابعاد استفاده کنید.
- حداکثر تعداد اسنادی که باید از یک جستار نزدیکترین همسایه بازگردانده شود 1000 است.
- جستجوی برداری از شنوندگان لحظهای فوری پشتیبانی نمیکند.
- فقط کتابخانه های کلاینت Python، Node.js، Go و Java از جستجوی برداری پشتیبانی می کنند.
بعدش چی
- درباره بهترین روشها برای Cloud Firestore بخوانید.
- خواندن و نوشتن را در مقیاس درک کنید.