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

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

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

قبل البدء

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

لمزيد من المعلومات عن التضمينات، يُرجى الاطّلاع على مقالة ما هي التضمينات؟

لمعرفة كيفية الحصول على تضمينات النصوص باستخدام Agent Platform، يُرجى الاطّلاع على مقالة الحصول على تضمينات النصوص.

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

توضّح الأمثلة التالية كيفية تخزين تضمينات المتجهات في 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 Function:

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

حيث:

  • 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

حيث:

  • 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

حيث:

  • 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.

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