Vectorize 索引允许您随时插入向量:Vectorize 会在后台优化索引,确保即使添加新向量或更新现有向量,向量搜索仍然高效。
Vectorize 支持以三种格式 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 索引创建元数据索引时,我们建议提前规划如何查询带有这些元数据过滤器的向量。
仔细考虑元数据值的基数与查询的关系。基数是数据集中唯一值的数量级别。低基数意味着只有少数唯一值:例如,太阳系中的行星数量;世界上的国家数量。高基数意味着有许多唯一值:UUID v4 字符串;毫秒精度的时间戳。
高基数对 equal($eq)过滤器的选择性很有利。例如,如果您想查找与某个用户 id 关联的向量。但如果所有向量都有相同的值,过滤器就没有帮助。这是极端低基数的例子。
高基数也会影响范围查询,范围查询会搜索多个唯一元数据值。例如,使用毫秒时间戳的索引元数据值,如果范围跨越写入数千个具有唯一时间戳的向量的长时间段,性能会降低。
在后台,Vectorize 使用倒排索引将值映射到向量 id。如果特定范围内的唯一值数量过高,则需要读取索引的大部分(最坏情况下为全索引扫描)。这会导致内存问题,因此 Vectorize 会降低性能和查询准确性以完成请求。
对于高基数数据,一种方法是将更多向量分组到相同的值。继续毫秒时间戳的例子,假设我们通常以 5 分钟为粒度过滤日期范围。我们可以使用向下舍入到最后 5 分钟点的时间戳。这将元数据值"窗口化"为 5 分钟增量。我们仍然可以将原始毫秒时间戳存储为单独的非索引字段。
Namespace 提供了一种在索引内分割向量的方式。例如,按客户、商户或商店 ID。
要将向量与 namespace 关联,您可以在执行 insert 或 upsert 操作时可选地提供 namespace: string 值。查询时,您可以将要搜索的 namespace 作为可选参数传递给查询。
namespace 最长可达 64 个字符(字节),每个索引最多可有 1,000 个 namespace。请参阅 限制 文档了解更多详情。
在查询操作中指定 namespace 时,仅使用该 namespace 内的向量进行搜索。Namespace 过滤在向量搜索之前应用,提高匹配结果的精度。
插入带 namespace 的向量:
// 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);在 namespace 内查询向量:
// Your queryVector will be searched against vectors within the namespace (only)
let matches = await env.TUTORIAL_INDEX.query(queryVector, {
namespace: "images",
});减少更新在查询中可见所需时间的一种方法是在更少的请求中批量处理更多向量。这对写入密集型工作负载很重要。要了解单个请求中可以写入多少向量,请参阅 限制 页面。
Vectorize 立即将更改写入预写日志以保证持久性。要使这些写入对读取可见,异步作业需要从 R2 读取当前索引文件、创建更新的索引、将新索引文件写回 R2 并提交更改。为保持写入开销低并提高写入吞吐量,Vectorize 会将多个更改合并为单个批次。它将批次的最大大小设置为 200,000 个向量总数或 1,000 次单独更新,以先达到的限制为准。
例如,假设我们要向索引插入 250,000 个向量。我们决定逐个插入,调用 insert API 250,000 次。Vectorize 每个作业只处理 1000 个向量,需要处理 250 个作业。这可能至少需要一个小时。
更好的方法是批量更新。例如,我们可以将 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 格式):每个完整向量必须换行分隔,不能在数组或对象内。
- 向量必须完整,每个向量包含唯一的字符串
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 中定义的向量插入提供的索引。Python 库(包括 Pandas)也支持通过内置 read_json 方法使用 NDJSON 格式:
import pandas as pd
data = pd.read_json('embeddings.ndjson', lines=True)