توضّح لك هذه الصفحة كيفية استخدام Cloud Firestore لإجراء عمليات بحث متجهة عن أقرب جار K باستخدام التقنيات التالية:
- قيم المتّجه للمتجر
- إنشاء فهارس متجهات KNN وإدارتها
- إجراء طلب بحث عن الجار الأقرب (KNN) باستخدام أحد مقاييس مسافة المتجهات المتوافقة
قبل البدء
قبل تخزين التضمينات في Cloud Firestore، عليك إنشاء تضمينات متّجهة. Cloud Firestore لا تنشئ التضمينات. يمكنك استخدام خدمة مثل Vertex AI لإنشاء قيم متجهة، مثل تضمينات نصية من بيانات Cloud Firestore. يمكنك بعد ذلك تخزين هذه التضمينات مرة أخرى في مستندات Cloud Firestore.
لمزيد من المعلومات حول التضمينات، يمكنك الاطّلاع على المقالة ما هي التضمينات؟
للتعرّف على كيفية الحصول على تضمينات نصية باستخدام Vertex AI، راجِع الحصول على تضمينات نصية.
تخزين تضمينات المتجهات
توضّح الأمثلة التالية كيفية تخزين تضمينات المتجهات في 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]) });
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 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, }); }
Go
// 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 Console، انتقِل إلى صفحة قواعد البيانات.
- اختَر قاعدة البيانات المطلوبة من قائمة قواعد البيانات.
- في قائمة التنقّل، انقر على الفهارس، ثمّ انقر على علامة التبويب يدوي.
- انقر على إنشاء فهرس.
لفهرسة حقل متّجه لعمليات البحث المتّجهة، اختَر إنشاء فهرس متّجه.
-
أدخِل معرّف مجموعة. أدخِل مسار حقل المتّجه وعدد أبعاد تضمين المتّجه. أضِف أسماء أي حقول إضافية تريد فهرستها ووضع فهرس لكل حقل.
انقر على حفظ الفهرس.
سيظهر الفهرس الجديد في قائمة الفهارس اليدوية، وسيبدأ 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
where:
- 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 Console، انتقِل إلى صفحة قواعد البيانات.
- اختَر قاعدة البيانات المطلوبة من قائمة قواعد البيانات.
-
في قائمة التنقّل، انقر على الفهارس، ثمّ انقر على علامة التبويب يدوي.
يسرد جدول الفهارس جميع فهارس قاعدة البيانات. تتضمّن فهارس المتجهات حقل متجهات مع رمز .
gcloud
لعرض جميع الفهارس واسترداد أرقام تعريف الفهارس، اتّبِع الخطوات التالية:
gcloud firestore indexes composite list --database=database-id
استبدِل database-id بمعرّف قاعدة البيانات.
يمكنك استخدام رقم تعريف الفهرس للاطّلاع على مزيد من التفاصيل حول الفهرس:
gcloud firestore indexes composite describe index-id --database=database-id
where:
- index-id هو رقم تعريف الفهرس المطلوب وصفه.
- database-id هو رقم تعريف قاعدة البيانات.
حذف فهرس متّجه
Google Cloud Console
- في Google Cloud Console، انتقِل إلى صفحة قواعد البيانات.
- اختَر قاعدة البيانات المطلوبة من قائمة قواعد البيانات.
-
في قائمة التنقّل، انقر على الفهارس، ثمّ انقر على علامة التبويب يدوي.
- في قائمة الفهارس اليدوية، انقر على زر المزيد للفهرس الذي تريد حذفه. انقر على حذف.
- أكِّد رغبتك في حذف هذا الفهرس من خلال النقر على حذف الفهرس من التنبيه.
gcloud
gcloud firestore indexes composite delete index-id --database=database-id
where:
- 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();
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();
مسافات المتجهات
تتيح طلبات البحث عن الجيران الأقرب الخيارات التالية لمسافة المتجهات:
EUCLIDEAN: تقيس مسافةEUCLIDEANبين المتجهات. لمزيد من المعلومات، يُرجى الاطّلاع على المسافة الإقليدية.COSINE: تقارن هذه الطريقة المتّجهات استنادًا إلى الزاوية بينها، ما يتيح لك قياس التشابه الذي لا يستند إلى مقدار المتّجهات. ننصحك باستخدامDOT_PRODUCTمع الخطوط المتجهة الموحّدة بدلاً من مسافة COSINE، لأنّها مكافئة رياضيًا وتوفّر أداءً أفضل. لمزيد من المعلومات، اطّلِع على مقالة التشابه الجيب التمامي.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();
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();
استرداد مسافة المتّجه المحسوبة
يمكنك استرداد مسافة المتّجه المحسوبة من خلال تعيين اسم خاصية إخراج 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')); });
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")); }
إذا كنت تريد استخدام قناع حقل لعرض مجموعة فرعية من حقول المستند مع 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' });
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")); }
تحديد حدّ أدنى للمسافة
يمكنك تحديد حدّ تشابه لا يعرض سوى المستندات التي تقع ضمن هذا الحدّ. يعتمد سلوك حقل الحدّ الأدنى على مقياس المسافة الذي تختاره:
- تضع مسافتا
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); });
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()); }
القيود
أثناء العمل مع تضمينات المتجهات، يُرجى ملاحظة القيود التالية:
- الحد الأقصى لأبعاد التضمين المسموح بها هو 2048. لتخزين فهارس أكبر، استخدِم تقنية خفض الأبعاد.
- الحد الأقصى لعدد المستندات التي يمكن عرضها من طلب بحث عن أقرب تطابق هو 1000 مستند.
- لا تتيح ميزة "البحث المتّجه" برامج معالجة اللقطات في الوقت الفعلي.
- تتيح مكتبات برامج Python وNode.js وGo وJava للعملاء البحث المستند إلى المتجهات فقط.
الخطوات التالية
- اطّلِع على أفضل الممارسات المتعلّقة بـ Cloud Firestore.
- فهم عمليات القراءة والكتابة على نطاق واسع