البحث باستخدام تضمينات المتّجهات

توضّح لك هذه الصفحة كيفية استخدام Cloud Firestore لإجراء عمليات بحث متجهة عن أقرب جار K باستخدام التقنيات التالية:

  • قيم المتّجه للمتجر
  • إنشاء فهارس متجهات KNN وإدارتها
  • إجراء طلب بحث عن الجار الأقرب (KNN) باستخدام أحد مقاييس مسافة المتجهات المتوافقة

قبل البدء

قبل تخزين التضمينات في Cloud Firestore، عليك إنشاء تضمينات متّجهة. Cloud Firestore لا تنشئ التضمينات. يمكنك استخدام خدمة مثل Vertex AI لإنشاء قيم متجهة، مثل تضمينات نصية من بيانات Cloud Firestore. يمكنك بعد ذلك تخزين هذه التضمينات مرة أخرى في مستندات Cloud Firestore.

لمزيد من المعلومات حول التضمينات، يمكنك الاطّلاع على المقالة ما هي التضمينات؟

للتعرّف على كيفية الحصول على تضمينات نصية باستخدام Vertex AI، راجِع الحصول على تضمينات نصية.

تخزين تضمينات المتجهات

توضّح الأمثلة التالية كيفية تخزين تضمينات المتجهات في Cloud Firestore.

عملية الكتابة باستخدام تضمين متّجه

يوضّح المثال التالي كيفية تخزين تضمين متّجهي في مستند Cloud Firestore:

Python
from google.cloud import firestore
from google.cloud.firestore_v1.vector import Vector

firestore_client = firestore.Client()
collection = firestore_client.collection("coffee-beans")
doc = {
    "name": "Kahawa coffee beans",
    "description": "Information about the Kahawa coffee beans.",
    "embedding_field": Vector([0.18332680, 0.24160706, 0.3416704]),
}

collection.add(doc)
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
import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/firestore"
)

type CoffeeBean struct {
	Name           string             `firestore:"name,omitempty"`
	Description    string             `firestore:"description,omitempty"`
	EmbeddingField firestore.Vector32 `firestore:"embedding_field,omitempty"`
	Color          string             `firestore:"color,omitempty"`
}

func storeVectors(w io.Writer, projectID string) error {
	ctx := context.Background()

	// Create client
	client, err := firestore.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("firestore.NewClient: %w", err)
	}
	defer client.Close()

	// Vector can be represented by Vector32 or Vector64
	doc := CoffeeBean{
		Name:           "Kahawa coffee beans",
		Description:    "Information about the Kahawa coffee beans.",
		EmbeddingField: []float32{1.0, 2.0, 3.0},
		Color:          "red",
	}
	ref := client.Collection("coffee-beans").NewDoc()
	if _, err = ref.Set(ctx, doc); err != nil {
		fmt.Fprintf(w, "failed to upsert: %v", err)
		return err
	}

	return nil
}
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، اتّبِع الخطوات التالية:

  1. في Google Cloud Console، انتقِل إلى صفحة قواعد البيانات.

    الانتقال إلى "قواعد البيانات"

  2. اختَر قاعدة البيانات المطلوبة من قائمة قواعد البيانات.
  3. في قائمة التنقّل، انقر على الفهارس، ثمّ انقر على علامة التبويب يدوي.
  4. انقر على إنشاء فهرس.

    لفهرسة حقل متّجه لعمليات البحث المتّجهة، اختَر إنشاء فهرس متّجه.

  5. أدخِل معرّف مجموعة. أدخِل مسار حقل المتّجه وعدد أبعاد تضمين المتّجه. أضِف أسماء أي حقول إضافية تريد فهرستها ووضع فهرس لكل حقل.

    انقر على حفظ الفهرس.

سيظهر الفهرس الجديد في قائمة الفهارس اليدوية، وسيبدأ 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

  1. في Google Cloud Console، انتقِل إلى صفحة قواعد البيانات.

    الانتقال إلى "قواعد البيانات"

  2. اختَر قاعدة البيانات المطلوبة من قائمة قواعد البيانات.
  3. في قائمة التنقّل، انقر على الفهارس، ثمّ انقر على علامة التبويب يدوي.

    يسرد جدول الفهارس جميع فهارس قاعدة البيانات. تتضمّن فهارس المتجهات حقل متجهات مع رمز .

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

  1. في Google Cloud Console، انتقِل إلى صفحة قواعد البيانات.

    الانتقال إلى "قواعد البيانات"

  2. اختَر قاعدة البيانات المطلوبة من قائمة قواعد البيانات.
  3. في قائمة التنقّل، انقر على الفهارس، ثمّ انقر على علامة التبويب يدوي.

  4. في قائمة الفهارس اليدوية، انقر على زر المزيد للفهرس الذي تريد حذفه. انقر على حذف.
  5. أكِّد رغبتك في حذف هذا الفهرس من خلال النقر على حذف الفهرس من التنبيه.
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
from google.cloud.firestore_v1.base_vector_query import DistanceMeasure
from google.cloud.firestore_v1.vector import Vector

collection = db.collection("coffee-beans")

# Requires a single-field vector index
vector_query = collection.find_nearest(
    vector_field="embedding_field",
    query_vector=Vector([0.3416704, 0.18332680, 0.24160706]),
    distance_measure=DistanceMeasure.EUCLIDEAN,
    limit=5,
)
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
import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/firestore"
)

func vectorSearchBasic(w io.Writer, projectID string) error {
	ctx := context.Background()

	// Create client
	client, err := firestore.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("firestore.NewClient: %w", err)
	}
	defer client.Close()

	collection := client.Collection("coffee-beans")

	// Requires a vector index
	// https://firebase.google.com/docs/firestore/vector-search#create_and_manage_vector_indexes
	vectorQuery := collection.FindNearest("embedding_field",
		[]float32{3.0, 1.0, 2.0},
		5,
		// More info: https://firebase.google.com/docs/firestore/vector-search#vector_distances
		firestore.DistanceMeasureEuclidean,
		nil)

	docs, err := vectorQuery.Documents(ctx).GetAll()
	if err != nil {
		fmt.Fprintf(w, "failed to get vector query results: %v", err)
		return err
	}

	for _, doc := range docs {
		fmt.Fprintln(w, doc.Data()["name"])
	}
	return nil
}
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
from google.cloud.firestore_v1.base_vector_query import DistanceMeasure
from google.cloud.firestore_v1.vector import Vector

collection = db.collection("coffee-beans")

# Similarity search with pre-filter
# Requires a composite vector index
vector_query = collection.where("color", "==", "red").find_nearest(
    vector_field="embedding_field",
    query_vector=Vector([0.3416704, 0.18332680, 0.24160706]),
    distance_measure=DistanceMeasure.EUCLIDEAN,
    limit=5,
)
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
import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/firestore"
)

func vectorSearchPrefilter(w io.Writer, projectID string) error {
	ctx := context.Background()

	// Create client
	client, err := firestore.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("firestore.NewClient: %w", err)
	}
	defer client.Close()

	collection := client.Collection("coffee-beans")

	// Similarity search with pre-filter
	// Requires a composite vector index
	vectorQuery := collection.Where("color", "==", "red").
		FindNearest("embedding_field",
			[]float32{3.0, 1.0, 2.0},
			5,
			// More info: https://firebase.google.com/docs/firestore/vector-search#vector_distances
			firestore.DistanceMeasureEuclidean,
			nil)

	docs, err := vectorQuery.Documents(ctx).GetAll()
	if err != nil {
		fmt.Fprintf(w, "failed to get vector query results: %v", err)
		return err
	}

	for _, doc := range docs {
		fmt.Fprintln(w, doc.Data()["name"])
	}
	return nil
}
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
from google.cloud.firestore_v1.base_vector_query import DistanceMeasure
from google.cloud.firestore_v1.vector import Vector

collection = db.collection("coffee-beans")

vector_query = collection.find_nearest(
    vector_field="embedding_field",
    query_vector=Vector([0.3416704, 0.18332680, 0.24160706]),
    distance_measure=DistanceMeasure.EUCLIDEAN,
    limit=10,
    distance_result_field="vector_distance",
)

docs = vector_query.stream()

for doc in docs:
    print(f"{doc.id}, Distance: {doc.get('vector_distance')}")
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
import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/firestore"
)

func vectorSearchDistanceResultField(w io.Writer, projectID string) error {
	ctx := context.Background()

	client, err := firestore.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("firestore.NewClient: %w", err)
	}
	defer client.Close()

	collection := client.Collection("coffee-beans")

	// Requires a vector index
	// https://firebase.google.com/docs/firestore/vector-search#create_and_manage_vector_indexes
	vectorQuery := collection.FindNearest("embedding_field",
		[]float32{3.0, 1.0, 2.0},
		10,
		firestore.DistanceMeasureEuclidean,
		&firestore.FindNearestOptions{
			DistanceResultField: "vector_distance",
		})

	docs, err := vectorQuery.Documents(ctx).GetAll()
	if err != nil {
		fmt.Fprintf(w, "failed to get vector query results: %v", err)
		return err
	}

	for _, doc := range docs {
		fmt.Fprintf(w, "%v, Distance: %v\n", doc.Data()["name"], doc.Data()["vector_distance"])
	}
	return nil
}
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
vector_query = collection.select(["color", "vector_distance"]).find_nearest(
    vector_field="embedding_field",
    query_vector=Vector([0.3416704, 0.18332680, 0.24160706]),
    distance_measure=DistanceMeasure.EUCLIDEAN,
    limit=10,
    distance_result_field="vector_distance",
)
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
import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/firestore"
)

func vectorSearchDistanceResultFieldMasked(w io.Writer, projectID string) error {
	ctx := context.Background()

	client, err := firestore.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("firestore.NewClient: %w", err)
	}
	defer client.Close()

	collection := client.Collection("coffee-beans")

	// Requires a vector index
	// https://firebase.google.com/docs/firestore/vector-search#create_and_manage_vector_indexes
	vectorQuery := collection.Select("color", "vector_distance").
		FindNearest("embedding_field",
			[]float32{3.0, 1.0, 2.0},
			10,
			firestore.DistanceMeasureEuclidean,
			&firestore.FindNearestOptions{
				DistanceResultField: "vector_distance",
			})

	docs, err := vectorQuery.Documents(ctx).GetAll()
	if err != nil {
		fmt.Fprintf(w, "failed to get vector query results: %v", err)
		return err
	}

	for _, doc := range docs {
		fmt.Fprintf(w, "%v, Distance: %v\n", doc.Data()["color"], doc.Data()["vector_distance"])
	}
	return nil
}
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
from google.cloud.firestore_v1.base_vector_query import DistanceMeasure
from google.cloud.firestore_v1.vector import Vector

collection = db.collection("coffee-beans")

vector_query = collection.find_nearest(
    vector_field="embedding_field",
    query_vector=Vector([0.3416704, 0.18332680, 0.24160706]),
    distance_measure=DistanceMeasure.EUCLIDEAN,
    limit=10,
    distance_threshold=4.5,
)

docs = vector_query.stream()

for doc in docs:
    print(f"{doc.id}")
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
import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/firestore"
)

func vectorSearchDistanceThreshold(w io.Writer, projectID string) error {
	ctx := context.Background()

	client, err := firestore.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("firestore.NewClient: %w", err)
	}
	defer client.Close()

	collection := client.Collection("coffee-beans")

	// Requires a vector index
	// https://firebase.google.com/docs/firestore/vector-search#create_and_manage_vector_indexes
	vectorQuery := collection.FindNearest("embedding_field",
		[]float32{3.0, 1.0, 2.0},
		10,
		firestore.DistanceMeasureEuclidean,
		&firestore.FindNearestOptions{
			DistanceThreshold: firestore.Ptr[float64](4.5),
		})

	docs, err := vectorQuery.Documents(ctx).GetAll()
	if err != nil {
		fmt.Fprintf(w, "failed to get vector query results: %v", err)
		return err
	}

	for _, doc := range docs {
		fmt.Fprintln(w, doc.Data()["name"])
	}
	return nil
}
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 للعملاء البحث المستند إلى المتجهات فقط.

الخطوات التالية