חיפוש באמצעות הטמעות וקטוריות

בדף הזה מוסבר איך להשתמש ב-Cloud Firestore כדי לבצע חיפושי וקטורים של K-nearest neighbor ‏ (KNN) באמצעות הטכניקות הבאות:

  • ערכי וקטורים של חנויות
  • יצירה וניהול של אינדקסים של וקטורים מסוג KNN
  • שליחת שאילתת K-nearest-neighbor ‏ (KNN) באמצעות אחד ממדדי המרחק בין וקטורים הנתמכים

אחסון הטמעות וקטוריות

אתם יכולים ליצור ערכים וקטוריים כמו הטמעות טקסט מנתוני Cloud Firestore ולאחסן אותם במסמכי 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 CLI:

gcloud components update

כדי ליצור אינדקס וקטורי, משתמשים בפקודה gcloud firestore indexes composite create:

gcloud
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
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

הצגת רשימה של כל מדדי הווקטורים

gcloud
gcloud firestore indexes composite list --database=database-id

מחליפים את database-id במזהה של מסד הנתונים.

מחיקת אינדקס וקטורי

gcloud
gcloud firestore indexes composite delete index-id --database=database-id

where:‎

  • index-id הוא המזהה של האינדקס שרוצים למחוק. כדי לאחזר את מזהה האינדקס, משתמשים ב-indexes composite list.
  • database-id הוא המזהה של מסד הנתונים.

תארו אינדקס וקטורי

gcloud
gcloud firestore indexes composite describe index-id --database=database-id

where:‎

  • index-id הוא המזהה של האינדקס שרוצים לתאר. משתמשים ב-or 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: מדידת המרחק האוקלידי בין הווקטורים. מידע נוסף זמין במאמר בנושא מרחק אוקלידי.
  • COSINE: השוואה בין וקטורים על סמך הזווית ביניהם, שמאפשרת למדוד דמיון שלא מבוסס על גודל הווקטורים. מומלץ להשתמש ב-DOT_PRODUCT עם וקטורים מנורמלים של יחידות במקום במרחק COSINE, שהוא שווה מבחינה מתמטית אבל מניב ביצועים טובים יותר. מידע נוסף זמין במאמר בנושא דמיון קוסינוס.
  • DOT_PRODUCT: דומה ל-COSINE אבל מושפע מגודל הווקטורים. מידע נוסף על מכפלה סקלרית

בחירת מדד המרחק

בהתאם לכך שכל ההטמעות של הווקטורים מנורמלות או לא, אפשר לקבוע באיזה מדד מרחק להשתמש כדי למצוא את מדד המרחק. ל-vector embedding מנורמל יש גודל (אורך) של 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 distance מגביל את ערך הסף למסמכים שבהם המרחק גדול מערך הסף שצוין או שווה לו. המרחקים של המכפלה הסקלרית גדלים ככל שהווקטורים דומים יותר.

בדוגמה הבאה מוצג אופן השימוש במדד המרחק EUCLIDEAN כדי לציין סף מרחק להחזרת עד 10 מסמכים קרובים ביותר שנמצאים במרחק של עד 4.5 יחידות.

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. כדי לאחסן אינדקסים גדולים יותר, משתמשים בצמצום ממדים.
  • המספר המקסימלי של מסמכים שיוחזרו משאילתת השכן הקרוב ביותר הוא 1,000.
  • חיפוש וקטורי לא תומך במאזינים של תמונות מצב בזמן אמת.
  • רק ספריות הלקוח של Python,‏ Node.js,‏ Go ו-Java תומכות בחיפוש וקטורי.

המאמרים הבאים