توضّح لك هذه الصفحة كيفية استخدام Cloud Firestore لإجراء عمليات بحث عن المتجهات باستخدام خوارزمية "أقرب جار" (KNN) باستخدام الأساليب التالية:
- تخزين قيم المتّجهات
- إنشاء فهارس متجهات KNN وإدارتها
- إجراء طلب بحث عن الجار الأقرب (KNN) باستخدام أحد مقاييس المسافة المتجهة المتوافقة
قبل البدء
قبل تخزين التضمينات في Cloud Firestore، عليك إنشاء تضمينات متّجهات. لا ينشئ Cloud Firestore التضمينات. يمكنك استخدام خدمة مثل Agent Platform لإنشاء قيم متّجهات، مثل تضمينات النص من بيانات Cloud Firestore. يمكنك بعد ذلك تخزين هذه التضمينات في مستندات "Cloud Firestore".
لمزيد من المعلومات حول التضمينات، يُرجى الاطّلاع على ما هي التضمينات؟
لمعرفة كيفية الحصول على تضمينات نصية باستخدام Agent Platform، يُرجى الاطّلاع على الحصول على تضمينات نصية.
تخزين تضمينات المتّجهات
توضّح الأمثلة التالية كيفية تخزين تضمينات المتّجهات في Cloud Firestore.
عملية كتابة مع تضمين متجه
يوضّح المثال التالي كيفية تخزين تضمين متجه في مستند Cloud Firestore:
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]) });
متابعة
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 Function
لاحتساب تضمينات المتجهات وتخزينها عند تعديل مستند أو إنشائه، يمكنك إعداد دالة Cloud:
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, }); }
متابعة
// Not yet supported in the Go client library
Java
// Not yet supported in the Java client library
إنشاء فهارس المتجهات وإدارتها
قبل أن تتمكّن من إجراء بحث عن أقرب جار باستخدام تضمينات المتّجهات، عليك إنشاء فهرس مقابل. توضّح الأمثلة التالية كيفية إنشاء فهارس المتجهات وإدارتها باستخدام Google Cloud CLI ووحدة التحكّم. يمكنك أيضًا إدارة فهارس المتجهات باستخدام Firebase CLI وTerraform.
إنشاء فهرس متّجه
Google Cloud Console
لإنشاء فهرس جديد يدويًا من Google Cloud Console، اتّبِع الخطوات التالية:
- في وحدة تحكّم 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عددًا صحيحًا يصل إلى 2048. يجب أن يكون نوع الفهرس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 Console
- في وحدة تحكّم 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 Console
- في وحدة تحكّم Google Cloud، انتقِل إلى صفحة قواعد البيانات.
- اختَر قاعدة البيانات المطلوبة من قائمة قواعد البيانات.
-
في قائمة التنقّل، انقر على الفهارس، ثم انقر على علامة التبويب يدوي.
- في قائمة الفهارس اليدوية، انقر على الزر المزيد للفهرس الذي تريد حذفه. انقر على حذف.
- أكِّد رغبتك في حذف هذا الفهرس بالنقر على حذف الفهرس من التنبيه.
gcloud
gcloud firestore indexes composite delete index-id --database=database-id
حيث:
- index-id هو معرّف الفهرس المطلوب حذفه.
استخدِم
indexes composite listلاسترداد معرّف الفهرس. - database-id هو معرّف قاعدة البيانات.
إجراء طلب بحث عن النقطة الأقرب
يمكنك إجراء بحث عن التشابه للعثور على أقرب النقاط المجاورة لتضمين متجه. تتطلّب عمليات البحث عن التشابه فهارس متّجهات. إذا لم يكن هناك فهرس، يقترح Cloud Firestore فهرسًا لإنشائه باستخدام gcloud CLI.
يعثر المثال التالي على أقرب 10 متجهات مجاورة لمتجه طلب البحث.
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();
متابعة
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();
مسافات المتّجهات
تتيح طلبات البحث عن الجار الأقرب الخيارات التالية لمسافة المتجه:
-
EUCLIDEAN: تقيس المسافةEUCLIDEANبين المتّجهات. لمزيد من المعلومات، يُرجى الاطّلاع على المسافة الإقليدية. COSINE: يقارن بين المتّجهات استنادًا إلى الزاوية بينها، ما يتيح لك قياس التشابه الذي لا يستند إلى حجم المتّجهات. ننصح باستخدامDOT_PRODUCTمع متجهات الوحدة التي تمت تسويتها بدلاً من مسافة جيب التمام، والتي تعادلها رياضيًا مع أداء أفضل. لمزيد من المعلومات، يُرجى الاطّلاع على تشابه جيب التمام.-
DOT_PRODUCT: تشبهCOSINEولكنها تتأثر بحجم المتجهات. لمزيد من المعلومات، يُرجى الاطّلاع على الضرب القياسي.
اختيار مقياس المسافة
بناءً على ما إذا كانت جميع تضمينات المتجهات تمت تسويتها أم لا، يمكنك تحديد مقياس المسافة الذي يجب استخدامه للعثور على مقياس المسافة. ويكون حجم (طول) متّجه التضمين الذي تمّت تسويته 1.0 بالضبط.
بالإضافة إلى ذلك، إذا كنت تعرف مقياس المسافة الذي تم تدريب النموذج به، استخدم مقياس المسافة هذا لحساب المسافة بين تضمينات المتجهات.
البيانات التي تمت تسويتها
إذا كانت لديك مجموعة بيانات تم فيها تسوية جميع تضمينات المتّجهات، ستوفّر مقاييس المسافة الثلاثة جميعها نتائج البحث الدلالي نفسها. في الأساس، على الرغم من أن كل مقياس مسافة يعرض قيمة مختلفة، فإن هذه القيم يتم فرزها بنفس الطريقة. عندما
تتم تسوية التضمينات، يكون DOT_PRODUCT عادةً الأكثر كفاءة من الناحية الحسابية،
ولكن الفرق لا يُذكر في معظم الحالات. ومع ذلك، إذا كان تطبيقك حساسًا للغاية للأداء، فقد يساعدك DOT_PRODUCT في ضبط الأداء.
البيانات غير الموحّدة
إذا كانت لديك مجموعة بيانات لا يتم فيها تسوية تضمينات المتجهات،
فمن غير الصحيح رياضيًا استخدام DOT_PRODUCT كمقياس للمسافة
لأنّ الجداء النقطي لا يقيس المسافة. استنادًا إلى طريقة إنشاء التضمينات ونوع البحث المفضّل، ينتج عن مقياس المسافة COSINE أو EUCLIDEAN نتائج بحث أفضل من مقاييس المسافة الأخرى.
قد يكون من الضروري تجربة COSINE أو EUCLIDEAN لتحديد الخيار الأفضل لحالة الاستخدام.
عدم التأكّد مما إذا كانت البيانات منمّطة أو غير منمّطة
إذا لم تكن متأكدًا مما إذا كانت بياناتك قد تمت تسويتها أم لا وأردت استخدام
DOT_PRODUCT، ننصحك باستخدام COSINE بدلاً من ذلك.
COSINE يشبه DOT_PRODUCT مع تضمين التسوية.
تتراوح المسافة التي تم قياسها باستخدام COSINE بين 0 و2. وتشير النتيجة القريبة من 0 إلى أنّ الخطوط المتجهة متشابهة جدًا.
فلترة المستندات مسبقًا
لفلترة المستندات مسبقًا قبل العثور على أقرب العناصر المجاورة، يمكنك الجمع بين
البحث عن التشابه وعوامل تشغيل طلبات البحث الأخرى. يتوفّر الفلتران المركّبان and وor. لمزيد من المعلومات عن فلاتر الحقول المتوافقة، يُرجى الاطّلاع على عوامل تشغيل طلبات البحث.
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();
متابعة
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();
استرداد المسافة المتّجهة المحسوبة
يمكنك استرداد المسافة المتجهة المحسوبة من خلال تحديد اسم سمة ناتج distance_result_field في طلب البحث FindNearest، كما هو موضّح في المثال التالي:
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')); });
متابعة
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")); }
إذا أردت استخدام قناع حقل لعرض مجموعة فرعية من حقول المستندات مع distanceResultField، عليك أيضًا تضمين قيمة distanceResultField في قناع الحقل، كما هو موضّح في المثال التالي:
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' });
متابعة
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")); }
تحديد حدّ المسافة
يمكنك تحديد مستوى تشابه يعرض فقط المستندات التي تقع ضمن مستوى التشابه. يعتمد سلوك حقل الحدّ الأدنى على مقياس المسافة الذي تختاره:
- تحدّد المسافتان
EUCLIDEANوCOSINEالحدّ الأدنى للمستندات التي تكون فيها المسافة أقل من أو تساوي الحدّ الأدنى المحدّد. وتنخفض مقاييس المسافة هذه كلما زاد تشابه المتجهات. - يحدّ
DOT_PRODUCTمن الحدّ الأدنى للمستندات التي تكون المسافة فيها أكبر من أو تساوي الحدّ الأدنى المحدّد. وتزداد مسافات الضرب القياسي كلما زاد تشابه المتجهات.
يوضّح المثال التالي كيفية تحديد حدّ أقصى للمسافة لعرض ما يصل إلى 10 مستندات أقرب تبعد عن بعضها بمسافة 4.5 وحدة كحدّ أقصى باستخدام مقياس المسافة EUCLIDEAN:
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); });
متابعة
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()); }
القيود
عند العمل مع تضمينات المتّجهات، يُرجى مراعاة القيود التالية:
- الحد الأقصى المسموح به لبُعد التضمين هو 2048. لتخزين فهارس أكبر، استخدِم تقنية خفض الأبعاد.
- الحد الأقصى لعدد المستندات التي يمكن عرضها من طلب بحث عن أقرب جار هو 1000 (ينطبق هذا الحد على الإصدار العادي فقط).
- لا يتيح البحث بالمتّجهات استخدام أدوات الاستماع إلى اللقطات في الوقت الفعلي.
- تتيح مكتبات برامج Python وNode.js وGo وJava فقط البحث بالمتّجهات.
الخطوات التالية
- يمكنك الاطّلاع على أفضل الممارسات المتعلّقة بـ "Cloud Firestore".
- التعرّف على عمليات القراءة والكتابة على نطاق واسع