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

توضّح لك هذه الصفحة كيفية استخدام 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])
});
متابعة
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,
  });
}
متابعة
  // 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، انتقِل إلى صفحة قواعد البيانات.

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

  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، انتقِل إلى صفحة قواعد البيانات.

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

  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، انتقِل إلى صفحة قواعد البيانات.

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

  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();
متابعة
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 مع متجهات الوحدة التي تمت تسويتها بدلاً من مسافة جيب التمام، والتي تعادلها رياضيًا مع أداء أفضل. لمزيد من المعلومات، يُرجى الاطّلاع على تشابه جيب التمام.
  • ‫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();
متابعة
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'));
});
متابعة
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'
    });
متابعة
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);
});
متابعة
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 فقط البحث بالمتّجهات.

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