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

בדף הזה מוסבר איך להשתמש ב-Cloud Firestore כדי לבצע חיפושים של וקטורים של השכן הקרוב ביותר (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([1.0, 2.0, 3.0]),
}

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. אפשר גם לנהל את האינדקסים של הווקטורים באמצעות CLI של Firebase ו-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

כאשר:

  • 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

כאשר:

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

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

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

כאשר:

  • 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([3.0, 1.0, 2.0]),
    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 בדיוק.

בנוסף, אם אתם יודעים באיזו מדד מרחק המודלים שלכם הוכשרו, תוכלו להשתמש במדד המרחק הזה כדי לחשב את המרחק בין הטמעות הווקטורים.

נתונים מנורמלים

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

בדוגמה הבאה מוסבר איך לציין ערך סף של מרחק כדי להציג עד 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([3.0, 1.0, 2.0]),
    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 תומכות בחיפוש וקטורים.

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