Vectorize インデックスには、いつでもベクトルを挿入できます。新しいベクトルの追加や既存ベクトルの更新があっても、ベクトル検索が効率的なままになるよう、Vectorize が裏側でインデックスを最適化します。
Vectorize は、次の 3 形式でのベクトルの insert / upsert に対応します。
- 浮動小数点数の配列(JavaScript の
number[]配列に変換されます)。 - Float32Array ↗
- Float64Array ↗
ほかの API と連携する場合、多くの場面で number[] 配列が最も扱いやすく、ほとんどの機械学習 API の戻り値の型でもあります。
Vectorize はベクトル次元を Float32 として保存し、返します。Float64 で渡した次元は、保存前に Float32 に変換されます。
メタデータは、insert または upsert 時にベクトルへ付けられる任意のキーと値のペアです。ベクトル自身に関するデータを埋め込んだり、同じ場所に置いたりできます。
メタデータのキーは空にできません。ドット文字(.)、二重引用符(")を含められず、ドル文字($)で始めることもできません。
メタデータの用途は次のとおりです。
- オブジェクトストレージのキー、データベース UUID、そのほかの識別子を含め、ベクトル埋め込みが表すコンテンツを参照します。
- JSON データ(メタデータの上限 まで)を保存し、小さいコンテンツでは追加の参照を省略できます。
- 日付、タイムスタンプ、埋め込みの生成時期や生成方法を表すメタデータを記録します。
たとえば、画像を表すベクトル埋め込みには、生成元の R2 オブジェクト のパス、形式、カテゴリの参照を含められます。
{ id: '1', values: [32.4, 74.1, 3.2, ...], metadata: { path: 'r2://bucket-name/path/to/image.png', format: 'png', category: 'profile_image' } }大きな Vectorize インデックス向けにメタデータインデックスを作るときは、このメタデータでベクトルをどうクエリするかを、あらかじめ計画してください。
クエリとの関係で、メタデータ値のカーディナリティを慎重に検討します。カーディナリティは、集合内の値の一意さの度合いです。カーディナリティが低いとは、一意な値が少ないことです。たとえば、太陽系の惑星の数、世界の国の数です。カーディナリティが高いとは、一意な値が多いことです。UUIDv4 文字列、ミリ秒精度のタイムスタンプなどです。
カーディナリティが高いと、等価($eq)フィルターの選択性が良くなります。たとえば、あるユーザーの id に紐づくベクトルを探す場合です。一方、すべてのベクトルが同じ値だと、フィルターは役に立ちません。これは極端にカーディナリティが低い例です。
カーディナリティの高さは、複数の一意なメタデータ値をまたぐ範囲クエリにも影響します。たとえば、ミリ秒タイムスタンプをインデックスしたメタデータ値は、一意なタイムスタンプを持つ何千ものベクトルが書き込まれた長い期間を範囲がまたぐと、性能が下がります。
内部では、Vectorize は値からベクトル id への逆引きインデックスを使います。ある範囲の一意な値が多すぎると、インデックスの大部分を読む必要があります(最悪の場合はフルインデックススキャンです)。これはメモリ問題につながるため、Vectorize はリクエストを完了させるために、クエリの性能と精度を落とします。
カーディナリティが高いデータへの対処の 1 つは、より多くのベクトルが同じ値にまとまるバケットを作ることです。ミリ秒タイムスタンプの例を続けます。通常、5 分単位の粒度で日付範囲を絞り込むとします。直近の 5 分境界に切り捨てたタイムスタンプを使えます。これでメタデータ値を 5 分単位のウィンドウにまとめられます。元のミリ秒タイムスタンプは、インデックスしない別フィールドとして保存できます。
名前空間は、インデックス内のベクトルを分割する方法です。たとえば、顧客、加盟店、店舗 ID ごとです。
ベクトルを名前空間に関連付けるには、insert または upsert 時に任意で namespace: string 値を渡せます。クエリ時は、検索対象の名前空間を任意のパラメーターとして渡せます。
名前空間は最大 64 文字(バイト)で、インデックスあたり最大 1,000 個まで使えます。詳細は 制限 のドキュメントを参照してください。
クエリ操作で名前空間を指定すると、その名前空間内のベクトルだけが検索に使われます。名前空間による絞り込みはベクトル検索より先に適用されるため、一致結果の精度が上がります。
名前空間付きでベクトルを挿入する例:
// Mock vectors
// Vectors from a machine-learning model are typically ~100 to 1536 dimensions
// wide (or wider still).
const sampleVectors: Array<VectorizeVector> = [
{
id: "1",
values: [32.4, 74.1, 3.2, ...],
namespace: "text",
},
{
id: "2",
values: [15.1, 19.2, 15.8, ...],
namespace: "images",
},
{
id: "3",
values: [0.16, 1.2, 3.8, ...],
namespace: "pdfs",
},
];
// Insert your vectors, returning a count of the vectors inserted and their vector IDs.
let inserted = await env.TUTORIAL_INDEX.insert(sampleVectors);名前空間内のベクトルをクエリする例:
// Your queryVector will be searched against vectors within the namespace (only)
let matches = await env.TUTORIAL_INDEX.query(queryVector, {
namespace: "images",
});クエリで更新が見えるまでの時間を短くするには、より多くのベクトルを、より少ないリクエストにまとめます。書き込みが多いワークロードでは、これが重要です。1 回のリクエストで書き込めるベクトル数は、制限 のページを参照してください。
耐久性のため、Vectorize は変更をすぐにライトアヘッドログ(write-ahead log)へ書き込みます。これらの書き込みを読み取りに反映するには、非同期ジョブが R2 から現在のインデックスファイルを読み、更新したインデックスを作成し、新しいインデックスファイルを R2 に書き戻し、変更をコミットする必要があります。書き込みのオーバーヘッドを抑え、スループットを上げるため、Vectorize は複数の変更を 1 つのバッチにまとめます。バッチの上限は、合計 200,000 ベクトル、または個別更新 1,000 回のいずれか先に達した方です。
たとえば、インデックスへ挿入したいベクトルが 250,000 件あるとします。1 件ずつ挿入し、insert API を 250,000 回呼び出すことにします。Vectorize は各ジョブで 1,000 ベクトルしか処理せず、合計 250 ジョブが必要です。これには少なくとも 1 時間かかることがあります。
より良い方法は、更新をバッチにすることです。たとえば、250,000 ベクトルを 100 ファイルに分割し、各ファイルに 2,500 ベクトルを入れます。insert HTTP API の呼び出しは 100 回です。Vectorize は 2 または 3 ジョブでインデックスを更新します。250,000 件のベクトルは、数分以内にクエリで見えるようになります。
Cloudflare Worker 内から、インデックスの insert() と upsert() メソッドを使い、現在のインデックスへベクトルを挿入します。
// Mock vectors
// Vectors from a machine-learning model are typically ~100 to 1536 dimensions
// wide (or wider still).
const sampleVectors: Array<VectorizeVector> = [
{
id: "1",
values: [32.4, 74.1, 3.2, ...],
metadata: { url: "/products/sku/13913913" },
},
{
id: "2",
values: [15.1, 19.2, 15.8, ...],
metadata: { url: "/products/sku/10148191" },
},
{
id: "3",
values: [0.16, 1.2, 3.8, ...],
metadata: { url: "/products/sku/97913813" },
},
];
// Insert your vectors, returning a count of the vectors inserted and their vector IDs.
let inserted = await env.TUTORIAL_INDEX.insert(sampleVectors);追加の例は Vectorize API を参照してください。
ベクトル埋め込みを直接一括アップロードできます。
- ファイルは改行区切り JSON(NDJSON 形式)である必要があります。各ベクトルは完結した 1 行で、配列やオブジェクトの中に入れません。
- ベクトルは完結しており、ベクトルごとに一意の文字列
idが必要です。
NDJSON 形式のファイルの例:
{ "id": "4444", "values": [175.1, 167.1, 129.9], "metadata": {"url": "/products/sku/918318313"}}
{ "id": "5555", "values": [158.8, 116.7, 311.4], "metadata": {"url": "/products/sku/183183183"}}
{ "id": "6666", "values": [113.2, 67.5, 11.2], "metadata": {"url": "/products/sku/717313811"}}wrangler vectorize insert <your-index-name> --file=embeddings.ndjsonVectorize は REST API 経由のベクトル挿入にも対応しています。既存の機械学習ツールや言語(Python を含む)から Vectorize インデックスを操作できます。
たとえば、Python スクリプトから NDJSON 形式 の埋め込みを直接挿入します。
import requests
url = "https://api.cloudflare.com/client/v4/accounts/{}/vectorize/v2/indexes/{}/insert".format("your-account-id", "index-name")
headers = {
"Authorization": "Bearer <your-api-token>"
}
with open('embeddings.ndjson', 'rb') as embeddings:
resp = requests.post(url, headers=headers, files=dict(vectors=embeddings))
print(resp)このコードは、embeddings.ndjson で定義したベクトルを、指定したインデックスへ挿入します。Pandas を含む Python ライブラリも、組み込みの read_json メソッドで NDJSON 形式に対応しています。
import pandas as pd
data = pd.read_json('embeddings.ndjson', lines=True)