このページでは、Cloud Firestore を使用して、次の手法で K 最近傍(KNN)ベクトル検索を行う方法について説明します。
- ベクター値を保存する
- KNN ベクトル インデックスを作成して管理する
- サポートされているベクトル距離関数のいずれかを使用して K 最近傍(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]) });
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, }); }
ベクトル インデックスを作成して管理する
ベクトル エンベディングで最近傍検索を実行するには、対応するインデックスを作成する必要があります。次の例は、ベクター インデックスの作成方法と管理方法を示しています。
ベクトル インデックスを作成する
ベクトル インデックスを作成するには、gcloud alpha firestore indexes composite create
を使用します。
gcloud
gcloud alpha 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 は、コレクション グループの ID です。
- vector-field は、ベクター エンベディングを含むフィールドの名前です。
- database-id は、データベースの ID です。
- vector-configuration には、ベクトル
dimension
とインデックス タイプが含まれます。dimension
は、2,048 までの整数です。インデックスのタイプはflat
にする必要があります。 インデックス構成を{"dimension":"DIMENSION", "flat": "{}"}
形式にします。
次の例では、フィールド vector-field
のベクトル インデックスとフィールド color
の昇順インデックスを含む複合インデックスを作成します。このタイプのインデックスを使用して、最近傍探索の前にデータを事前にフィルタできます。
gcloud
gcloud alpha 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 alpha firestore indexes composite list --database=database-id
database-id は、データベースの ID に置き換えます。
ベクトル インデックスを削除する
gcloud
gcloud alpha firestore indexes composite delete index-id --database=database-id
ここで
- index-id は、削除するインデックスの ID です。
インデックス ID は
indexes composite list
を使用して取得します。 - database-id は、データベースの ID です。
ベクター インデックスについて説明する
gcloud
gcloud alpha firestore indexes composite describe index-id --database=database-id
ここで
- index-id は、説明するインデックスの ID です。
インデックス ID は
indexes composite list
を使用して取得します。 - database-id は、データベースの ID です。
最近傍クエリを実行する
類似度検索を実行して、ベクター エンベディングの最近傍を見つけることができます。類似性検索にはベクター インデックスが必要です。インデックスが存在しない場合、Cloud Firestore は gcloud CLI を使用して作成するインデックスを提案します。
Python
from google.cloud.firestore_v1.base_vector_query import DistanceMeasure collection = collection("coffee-beans") # Requires vector index 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 single-field vector index const vectorQuery: VectorQuery = coll.findNearest('embedding_field', FieldValue.vector([3.0, 1.0, 2.0]), { limit: 5, distanceMeasure: 'EUCLIDEAN' }); const vectorQuerySnapshot: VectorQuerySnapshot = await vectorQuery.get();
ベクター距離
最近傍クエリでは、ベクトル距離に関する次のオプションがサポートされています。
EUCLIDEAN
: ベクター間のユークリッド距離を測定します。詳細については、ユークリッドをご覧ください。COSINE
: ベクター間の角度に基づいてベクターを比較します。これにより、ベクターの大きさに基づかない類似性を測定できます。コサイン距離ではなく、単位正規化ベクターを使用してDOT_PRODUCT
を使用することをおすすめします。数学的には、パフォーマンスが向上します。詳しくは、学習するコサイン類似度をご覧ください。DOT_PRODUCT
:COSINE
に似ていますが、ベクターの大きさの影響を受けます。詳細については、ドット積をご覧ください。
データの事前フィルタリング
最近傍を検索する前にデータを事前フィルタリングするには、類似度検索を不等式フィルタ以外のフィルタと組み合わせます。and
複合フィルタと or
複合フィルタがサポートされています。フィールド フィルタの場合、以下のフィルタがサポートされています。
==
等しいin
array_contains
array_contains_any
Python
# Similarity search with pre-filter # Requires composite vector index 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("embedding_field", FieldValue.vector([3.0, 1.0, 2.0]), { limit: 5, distanceMeasure: "EUCLIDEAN", }); vectorQueryResults = await preFilteredVectorQuery.get();
制限事項
ベクター エンベディングを使用する場合は、次の制限事項に注意してください。
- サポートされているエンべディング ディメンションの最大値は 2,048 です。サイズの大きいインデックスを保存するには、次元削減を使用します。
- 最近傍クエリから返すドキュメントの最大数は 1,000 です。
- ベクター検索は、リアルタイム スナップショット リスナーをサポートしていません。
- 不等式フィルタを使用してデータを事前にフィルタすることはできません。
- ベクトル検索をサポートしているのは、Python と Node.js のクライアント ライブラリのみです。
次のステップ
- Cloud Firestore のベスト プラクティスを確認する。
- 大規模な読み取りと書き込みについて