Поиск с помощью векторных эмбеддингов

На этой странице показано, как использовать Cloud Firestore для выполнения векторного поиска K-ближайших соседей (KNN) с помощью следующих методов:

  • Сохранение значений векторов
  • Создание векторных индексов KNN и управление ими
  • Выполните запрос K-ближайших соседей (KNN), используя одну из поддерживаемых мер расстояния между векторами.

Подготовка

Прежде чем сохранять эмбеддинги в Cloud Firestore, необходимо сгенерировать векторные эмбеддинги. Cloud Firestore не генерирует эмбеддинги. Для создания векторных значений, например текстовых эмбеддингов из данных Cloud Firestore, можно использовать такой сервис, как Agent Platform. Затем вы можете сохранить эти эмбеддинги обратно в документы 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 Functions

Чтобы вычислять и сохранять векторные эмбеддинги при каждом обновлении или создании документа, можно настроить функцию Cloud Functions:

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 и Terraform.

Создание векторного индекса

Консоль Google Cloud

Чтобы вручную создать индекс в консоли Google Cloud, выполните следующие действия:

  1. В консоли Google Cloud перейдите на страницу Databases (Базы данных).

    Перейти к базам данных

  2. Выберите нужную базу данных из списка.
  3. В меню навигации нажмите Индексы, а затем выберите вкладку Вручную.
  4. Нажмите Create Index (Создать индекс).

    Чтобы проиндексировать векторное поле для векторного поиска, выберите Создать векторный индекс.

  5. Введите идентификатор коллекции. Укажите путь к векторному полю и количество измерений векторного эмбеддинга. Добавьте названия дополнительных полей, которые нужно индексировать, и режим индексирования для каждого поля.

    Нажмите Save Index (Сохранить индекс).

Новый индекс появится в списке индексов, созданных вручную, и 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

  1. В консоли Google Cloud перейдите на страницу Databases (Базы данных).

    Перейти к базам данных

  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

  1. В консоли Google Cloud перейдите на страницу Databases (Базы данных).

    Перейти к базам данных

  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 (ограничение только для версии Standard).
  • Векторный поиск не поддерживает прослушиватели снимков в реальном времени.
  • Векторный поиск поддерживают только клиентские библиотеки Python, Node.js, Go и Java.

Дальнейшие действия