این صفحه به شما نشان میدهد که چگونه از Cloud Firestore برای انجام جستجوهای برداری K-نزدیکترین همسایه (KNN) بااستفاده از تکنیکهای زیر استفاده کنید:
- ذخیره مقادیر بردار
- ایجاد و مدیریت نمایههای برداری KNN
- بااستفاده از یکی از معیارهای فاصله برداری پشتیبانیشده، پُرسمان K-نزدیکترین همسایه (KNN) ایجاد کنید
قبل از شروع
قبلاز ذخیره کردن جاسازیها در Cloud Firestore، باید جاسازیهای برداری تولید کنید. Cloud Firestore جاسازیها را تولید نمیکند. میتوانید از سرویسی مثل Agent Platform برای ایجاد مقادیر برداری، مثلاً جاسازیهای نوشتاری از دادههای Cloud Firestore خود استفاده کنید. سپس میتوانید این جاسازیها را دوباره در اسناد Cloud Firestore ذخیره کنید.
برای کسب اطلاعات بیشتر درباره جاسازیها، به جاسازیها چیست؟ مراجعه کنید.
برای آشنایی با نحوه دریافت جاسازیهای نوشتاری با Agent Platform، به دریافت جاسازیهای نوشتاری مراجعه کنید.
ذخیره کردن جاسازیهای برداری
نمونههای زیر نحوه ذخیره جاسازیهای برداری را در 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();
محاسبه جاسازیهای برداری با «تابع ابری»
برای محاسبه و ذخیره جاسازیهای برداری هر زمان که سندی بهروزرسانی یا ایجاد میشود، میتوانید یک تابع ابری راهاندازی کنید:
پایتون
@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 و Terraform مدیریت کنید.
ایجاد نمایه برداری
;کنسول Google Cloud
برای ایجاد دستی نمایه جدید از کنسول Google Cloud:
- در کنسول Google Cloud، به صفحه پایگاههای داده بروید.
- پایگاه داده موردنیاز را از فهرست پایگاههای داده انتخاب کنید.
- در منو پیمایش، روی نمایهها کلیک کنید، سپس روی برگه دستی کلیک کنید.
- روی ایجاد نمایه کلیک کنید.
برای نمایهسازی فیلد برداری برای جستجوهای برداری، ایجاد نمایه برداری را انتخاب کنید.
-
شناسه مجموعه را وارد کنید. مسیر فیلد بردار و تعداد ابعاد جاسازی بردار را وارد کنید. نام فیلدهای دیگری را که میخواهید نمایه کنید و حالت نمایه هر فیلد را اضافه کنید.
روی ذخیره نمایه کلیک کنید.
نمایه جدیدتان در فهرست نمایههای دستی نشان داده خواهد شد و Cloud Firestore شروع به ایجاد نمایه شما خواهد کرد. وقتی ایجاد نمایه تمام شد، علامت تأیید سبزرنگی در کنار نمایه خواهید دید.
gcloud
قبلاز ایجاد نمایه برداری، به جدیدترین نسخه Google Cloud CLI ارتقا دهید:
gcloud components update
برای ایجاد نمایه برداری، از 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
مکان:
- collection-group شناسه گروه مجموعه است.
- vector-field نام فیلدی است که حاوی جاسازی بردار است.
- database-id شناسه پایگاه داده است.
- vector-configuration شامل بردار
dimensionو نوع نمایه است. dimensionعدد صحیحی تا ۲۰۴۸ است. نوع نمایه بایدflatباشد. پیکربندی نمایه را بهصورت زیر قالببندی کنید:{"dimension":"DIMENSION", "flat": "{}"}.
مثال زیر یک نمایه ترکیبی ایجاد میکند، شامل یک نمایه برداری برای فیلد vector-field و یک نمایه صعودی برای فیلد color. میتوانید از این نوع نمایه برای
پیشفیلتر کردن دادهها قبلاز جستجوی نزدیکترین همسایه استفاده کنید.
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
فهرست کردن همه نمایههای برداری
;کنسول Google Cloud
- در کنسول Google Cloud، به صفحه پایگاههای داده بروید.
- پایگاه داده موردنیاز را از فهرست پایگاههای داده انتخاب کنید.
-
در منو پیمایش، روی نمایهها کلیک کنید، سپس روی برگه دستی کلیک کنید.
جدول نمایهها همه نمایههای پایگاه داده را فهرست میکند. نمایههای برداری شامل فیلد برداری با نماد هستند.
gcloud
برای فهرست کردن همه نمایهها و بازیابی شناسههای نمایه:
gcloud firestore indexes composite list --database=database-id
database-id را با شناسه پایگاه داده جایگزین کنید.
میتوانید از شناسه نمایه برای مشاهده جزئیات بیشتر درباره نمایه استفاده کنید:
gcloud firestore indexes composite describe index-id --database=database-id
مکان:
- index-id شناسه نمایهای است که باید شرح داده شود.
- database-id شناسه پایگاه داده است.
حذف نمایه برداری
;کنسول Google Cloud
- در کنسول Google Cloud، به صفحه پایگاههای داده بروید.
- پایگاه داده موردنیاز را از فهرست پایگاههای داده انتخاب کنید.
-
در منو پیمایش، روی نمایهها کلیک کنید، سپس روی برگه دستی کلیک کنید.
- در فهرست نمایههای دستی، روی دکمه بیشتر برای نمایهای که میخواهید حذف کنید کلیک کنید. روی حذف کلیک کنید.
- با کلیک کردن روی حذف نمایه در هشدار، تأیید کنید که میخواهید این نمایه حذف شود.
gcloud
gcloud firestore indexes composite delete index-id --database=database-id
مکان:
- index-id شناسه نمایهای است که باید حذف شود.
از
indexes composite listبرای بازیابی شناسه نمایه استفاده کنید. - database-id شناسه پایگاه داده است.
ایجاد پُرسمان نزدیکترین همسایه
میتوانید جستجوی شباهت انجام دهید تا نزدیکترین موارد همجوار جاسازی بردار را پیدا کنید. جستجوهای شباهت به نمایههای برداری نیاز دارند. اگر نمایهای وجود نداشته باشد، Cloud Firestore نمایهای را برای ایجاد کردن بااستفاده از gcloud CLI پیشنهاد میکند.
مثال زیر ۱۰ مورد از نزدیکترین موارد همجوار بردار پُرسمان را پیدا میکند.
پایتون
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بین بردارها را اندازهگیری میکند. برای اطلاعات بیشتر، Euclidean را ببینید.COSINE: بردارها را براساس زاویه بین آنها مقایسه میکند که به شما امکان میدهد شباهت را بدون توجه به اندازه بردارها اندازهگیری کنید. توصیه میکنیم بهجای فاصله COSINE، ازDOT_PRODUCTبا بردارهای نرمالشده واحد استفاده کنید که ازنظر ریاضی معادل است و عملکرد بهتری دارد. برای اطلاعات بیشتر، شباهت کسینوسی را ببینید.DOT_PRODUCT: شبیه بهCOSINEاما تحتتأثیر اندازه بردارها قرار میگیرد. برای کسب اطلاعات بیشتر، ضرب داخلی را ببینید.
انتخاب واحد اندازهگیری فاصله
بسته به اینکه همه جاسازیهای برداری شما نرمالسازی شده باشند یا نه، میتوانید تعیین کنید که از کدام معیار فاصله برای پیدا کردن معیار فاصله استفاده شود. جاسازی بردار نرمالشده دارای مقدار (طول) دقیقاً ۱٫۰ است.
علاوهبراین، اگر میدانید که مدل شما با کدام معیار فاصله آموزش دیده است، از آن معیار فاصله برای محاسبه فاصله بین جاسازیهای برداری خود استفاده کنید.
دادههای نرمالسازیشده
اگر مجموعه دادهای داشته باشید که در آن همه جاسازیهای برداری نرمالسازی شده باشند، هر سه معیار فاصله نتایج جستجوی معنایی یکسانی ارائه میدهند. در اصل، اگرچه هر
معیار فاصله مقدار متفاوتی را برمیگرداند، اما این مقادیر به یک روش مرتب میشوند. وقتی جاسازیها نرمالسازی میشوند، معمولاً DOT_PRODUCT ازنظر محاسباتی کارآمدترین است، اما تفاوت در اکثر موارد ناچیز است. بااینحال، اگر برنامه شما نسبتبه عملکرد بسیار حساس است، DOT_PRODUCT میتواند به تنظیم عملکرد کمک کند.
دادههای غیرنرمال
اگر مجموعه دادهای دارید که جاسازیهای برداری در آن نرمالسازی نشده است،
استفاده از DOT_PRODUCT بهعنوان معیار فاصله ازنظر ریاضی درست نیست
چون ضرب داخلی فاصله را اندازهگیری نمیکند. بسته به اینکه جاسازیها چگونه تولید شدهاند و چه نوع جستجویی ترجیح داده میشود، معیار فاصله COSINE یا EUCLIDEAN نتایج جستجویی تولید میکند که ازنظر ذهنی بهتر از سایر معیارهای فاصله است.
ممکن است لازم باشد COSINE یا EUCLIDEAN را امتحان کنید تا ببینید کدامیک برای مورد استفاده شما بهتر است.
مطمئن نیستید دادهها نرمالسازی شدهاند یا نه
اگر مطمئن نیستید که دادههایتان نرمالسازی شده است یا نه و میخواهید از
DOT_PRODUCT استفاده کنید، توصیه میکنیم بهجای آن از COSINE استفاده کنید.
COSINE مانند DOT_PRODUCT است که نرمالسازی در آن تعبیه شده است.
فاصله اندازهگیریشده بااستفاده از COSINE از 0 تا 2 است. نتیجهای
که نزدیک به 0 باشد نشان میدهد که بردارها بسیار شبیه هستند.
اسناد پیشفیلتر
برای پیشفیلتر کردن اسناد قبلاز پیدا کردن نزدیکترین همسایهها، میتوانید جستجوی شباهت را با دیگر اپراتورهای پُرسمان ترکیب کنید. فیلترهای ترکیبی and و
or پشتیبانی میشوند. برای اطلاعات بیشتر درباره فیلترهای فیلد پشتیبانیشده، عملگرهای پُرسمان را ببینید.
پایتون
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 برگرداند:
پایتون
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()); }
محدودیتها
هنگام کار با جاسازیهای برداری، محدودیتهای زیر را درنظر داشته باشید:
- حداکثر بُعد جاسازی پشتیبانیشده ۲۰۴۸ است. برای ذخیره کردن نمایههای بزرگتر، از کاهش ابعاد استفاده کنید.
- حداکثر تعداد اسنادی که از پُرسمان نزدیکترین همسایه برگردانده میشود ۱۰۰۰ است (فقط محدودیت نسخه Standard).
- جستجوی برداری از شنوندگان عکس آنی همزمان پشتیبانی نمیکند.
- فقط کتابخانههای کارخواه Python، Node.js، Go، و Java از جستجوی برداری پشتیبانی میکنند.
حالا چه میشود
- درباره روالهای مطلوب برای Cloud Firestore بخوانید.
- خواندن و نوشتن در مقیاس بزرگ را درک کنید.