Vectorize 是 Cloudflare 的向量数据库。向量数据库允许您使用机器学习(ML)模型执行语义搜索、推荐、分类和异常检测任务,并为 LLM(Large Language Models)提供上下文。
本指南将指导您:
- 创建第一个 Vectorize 索引。
- 将 Cloudflare Worker 连接到索引。
- 插入向量并通过查询索引执行相似性搜索。
要继续,您需要:
- 如果尚未注册,请注册 Cloudflare 账户 ↗。
- 安装
npm↗。 - 安装
Node.js↗。使用 Node 版本管理器(如 Volta ↗ 或 nvm ↗)以避免权限问题并切换 Node.js 版本。Wrangler 需要 Node 版本16.17.0或更高。
您将创建一个新项目,其中包含一个 Worker,作为 Vectorize 索引的客户端应用。
运行以下命令创建名为 vectorize-tutorial 的新项目:
npm create cloudflare@latest -- vectorize-tutorialyarn create cloudflare vectorize-tutorialpnpm create cloudflare@latest vectorize-tutorial进行设置时,请选择以下选项:
- 对于 What would you like to start with?,选择
Hello World example。 - 对于 Which template would you like to use?,选择
Worker only。 - 对于 Which language do you want to use?,选择
TypeScript。 - 对于 Do you want to use git for version control?,选择
Yes。 - 对于 Do you want to deploy your application?,选择
No(部署前我们还会做一些修改)。
这将创建新的 vectorize-tutorial 目录。新的 vectorize-tutorial 目录将包括:
- 位于
src/index.ts的"Hello World"Worker。 wrangler.jsonc配置文件。wrangler.jsonc是vectorize-tutorialWorker 访问索引的方式。
向量数据库与传统 SQL 或 NoSQL 数据库不同。向量数据库设计用于存储向量嵌入,即数据的表示,而非原始数据本身。
要创建第一个 Vectorize 索引,请进入刚为 Workers 项目创建的目录:
cd vectorize-tutorial要创建索引,您需要使用 wrangler vectorize create 命令并为索引提供名称。良好的索引名称应:
- 小写和/或数字 ASCII 字符的组合,少于 32 个字符,以字母开头,使用短横线(-)代替空格。
- 描述用例和环境。例如,"production-doc-search" 或 "dev-recommendation-engine"。
- 仅用于描述索引,不在代码中直接引用。
此外,您需要定义要存储在索引中的向量的 dimensions,以及创建索引时用于确定相似向量的距离 metric。metric 可以是 euclidean、cosine 或 dot product。此配置以后无法更改,因为向量数据库针对固定的向量配置。
运行以下 wrangler vectorize 命令:
npx wrangler vectorize create tutorial-index --dimensions=32 --metric=euclidean🚧 Creating index: 'tutorial-index'
✅ Successfully created a new Vectorize index: 'tutorial-index'
📋 To start querying from a Worker, add the following binding configuration into 'wrangler.toml':
[[vectorize]]
binding = "VECTORIZE" # available in your Worker on env.VECTORIZE
index_name = "tutorial-index"上述命令将创建新的向量数据库,并输出下一步所需的绑定(binding)配置。
您必须为 Worker 创建绑定(binding)以连接到 Vectorize 索引。绑定(binding) 允许 Workers 从 Cloudflare Workers 访问 Vectorize 或 R2 等资源。通过更新 worker 的 Wrangler 文件创建绑定。
要将索引绑定到 Worker,请在 Wrangler 文件末尾添加以下内容:
{
"vectorize": [
{
"binding": "VECTORIZE", // available in your Worker on env.VECTORIZE
"index_name": "tutorial-index"
}
]
}[[vectorize]]
binding = "VECTORIZE"
index_name = "tutorial-index"具体来说:
- 为
<BINDING_NAME>设置的值(字符串)将用于在 Worker 中引用此数据库。在本教程中,将绑定命名为VECTORIZE。 - 绑定必须是有效的 JavaScript 变量名 ↗。例如,
binding = "MY_INDEX"或binding = "PROD_SEARCH_INDEX"都是有效的绑定名称。 - 绑定在 Worker 中的
env.<BINDING_NAME>处可用,Vectorize 客户端 API 在此绑定上暴露,供 Workers 应用内使用。
Vectorize 允许您向索引中的每个向量添加最多 10KiB 的元数据,并提供在查询向量时过滤该元数据的能力。为此,您需要将元数据字段指定为 Vectorize 索引的"元数据索引"。
要在查询期间启用元数据字段上的向量过滤,请使用如下命令:
npx wrangler vectorize create-metadata-index tutorial-index --property-name=url --type=string📋 Creating metadata index...
✅ Successfully enqueued metadata index creation request. Mutation changeset identifier: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.这里 url 是启用过滤的元数据字段。--type 参数定义元数据字段的数据类型;支持 string、number 和 boolean 类型。
元数据索引创建通常需要几秒钟。您可以通过运行以下命令查看 Vectorize 索引的元数据索引列表:
npx wrangler vectorize list-metadata-index tutorial-index📋 Fetching metadata indexes...
┌──────────────┬────────┐
│ propertyName │ type │
├──────────────┼────────┤
│ url │ String │
└──────────────┴────────┘每个 Vectorize 索引最多可创建 10 个元数据索引。
对于 number 类型的元数据索引,索引数字精度为 float64。
对于 string 类型的元数据索引,每个向量在 UTF-8 字符边界处截断到该限制内最长格式良好的 UTF-8 子字符串,索引字符串数据的前 64B,因此向量可按每个索引属性的前 64B 值进行过滤。
请参阅 Vectorize 限制 了解完整限制列表。
在查询向量数据库之前,您需要插入向量以供查询。这些向量将从数据(如文本或图像)生成,传递给机器学习模型。但是,本教程将定义静态向量以说明向量搜索本身的工作原理。
首先,打开 vectorize-tutorial Worker 的 src/index.ts 文件。index.ts 文件是配置 Worker 与 Vectorize 索引交互的地方。
清除 index.ts 的内容,将以下代码片段粘贴到 index.ts 文件中。在 env 参数上,将 <BINDING_NAME> 替换为 VECTORIZE:
export interface Env {
// This makes your vector index methods available on env.VECTORIZE.*
// For example, env.VECTORIZE.insert() or query()
VECTORIZE: Vectorize;
}
// Sample vectors: 32 dimensions wide.
//
// Vectors from popular machine-learning models are typically ~100 to 1536 dimensions
// wide (or wider still).
const sampleVectors: Array<VectorizeVector> = [
{
id: "1",
values: [
0.12, 0.45, 0.67, 0.89, 0.23, 0.56, 0.34, 0.78, 0.12, 0.9, 0.24, 0.67,
0.89, 0.35, 0.48, 0.7, 0.22, 0.58, 0.74, 0.33, 0.88, 0.66, 0.45, 0.27,
0.81, 0.54, 0.39, 0.76, 0.41, 0.29, 0.83, 0.55,
],
metadata: { url: "/products/sku/13913913" },
},
{
id: "2",
values: [
0.14, 0.23, 0.36, 0.51, 0.62, 0.47, 0.59, 0.74, 0.33, 0.89, 0.41, 0.53,
0.68, 0.29, 0.77, 0.45, 0.24, 0.66, 0.71, 0.34, 0.86, 0.57, 0.62, 0.48,
0.78, 0.52, 0.37, 0.61, 0.69, 0.28, 0.8, 0.53,
],
metadata: { url: "/products/sku/10148191" },
},
{
id: "3",
values: [
0.21, 0.33, 0.55, 0.67, 0.8, 0.22, 0.47, 0.63, 0.31, 0.74, 0.35, 0.53,
0.68, 0.45, 0.55, 0.7, 0.28, 0.64, 0.71, 0.3, 0.77, 0.6, 0.43, 0.39, 0.85,
0.55, 0.31, 0.69, 0.52, 0.29, 0.72, 0.48,
],
metadata: { url: "/products/sku/97913813" },
},
{
id: "4",
values: [
0.17, 0.29, 0.42, 0.57, 0.64, 0.38, 0.51, 0.72, 0.22, 0.85, 0.39, 0.66,
0.74, 0.32, 0.53, 0.48, 0.21, 0.69, 0.77, 0.34, 0.8, 0.55, 0.41, 0.29,
0.7, 0.62, 0.35, 0.68, 0.53, 0.3, 0.79, 0.49,
],
metadata: { url: "/products/sku/418313" },
},
{
id: "5",
values: [
0.11, 0.46, 0.68, 0.82, 0.27, 0.57, 0.39, 0.75, 0.16, 0.92, 0.28, 0.61,
0.85, 0.4, 0.49, 0.67, 0.19, 0.58, 0.76, 0.37, 0.83, 0.64, 0.53, 0.3,
0.77, 0.54, 0.43, 0.71, 0.36, 0.26, 0.8, 0.53,
],
metadata: { url: "/products/sku/55519183" },
},
];
export default {
async fetch(request, env, ctx): Promise<Response> {
let path = new URL(request.url).pathname;
if (path.startsWith("/favicon")) {
return new Response("", { status: 404 });
}
// You only need to insert vectors into your index once
if (path.startsWith("/insert")) {
// Insert some sample vectors into your index
// In a real application, these vectors would be the output of a machine learning (ML) model,
// such as Workers AI, OpenAI, or Cohere.
const inserted = await env.VECTORIZE.insert(sampleVectors);
// Return the mutation identifier for this insert operation
return Response.json(inserted);
}
return Response.json({ text: "nothing to do... yet" }, { status: 404 });
},
} satisfies ExportedHandler<Env>;在上面的代码中,您:
- 定义从 Workers 代码到 Vectorize 索引的绑定。此绑定与
wrangler.jsonc文件中"vectorise"键下设置的binding值匹配。 - 指定一组示例向量,您将在下一步中查询这些向量。
- 将这些向量插入索引并确认成功。
在下一步中,您将扩展 Worker 以查询索引和插入的向量。
在此步骤中,您将获取表示传入查询的向量,并使用它搜索索引。
首先,打开 vectorize-tutorial Worker 的 src/index.ts 文件。index.ts 文件是配置 Worker 与 Vectorize 索引交互的地方。
清除 index.ts 的内容。将以下代码片段粘贴到 index.ts 文件中。在 env 参数上,将 <BINDING_NAME> 替换为 VECTORIZE:
export interface Env {
// This makes your vector index methods available on env.VECTORIZE.*
// For example, env.VECTORIZE.insert() or query()
VECTORIZE: Vectorize;
}
// Sample vectors: 32 dimensions wide.
//
// Vectors from popular machine-learning models are typically ~100 to 1536 dimensions
// wide (or wider still).
const sampleVectors: Array<VectorizeVector> = [
{
id: "1",
values: [
0.12, 0.45, 0.67, 0.89, 0.23, 0.56, 0.34, 0.78, 0.12, 0.9, 0.24, 0.67,
0.89, 0.35, 0.48, 0.7, 0.22, 0.58, 0.74, 0.33, 0.88, 0.66, 0.45, 0.27,
0.81, 0.54, 0.39, 0.76, 0.41, 0.29, 0.83, 0.55,
],
metadata: { url: "/products/sku/13913913" },
},
{
id: "2",
values: [
0.14, 0.23, 0.36, 0.51, 0.62, 0.47, 0.59, 0.74, 0.33, 0.89, 0.41, 0.53,
0.68, 0.29, 0.77, 0.45, 0.24, 0.66, 0.71, 0.34, 0.86, 0.57, 0.62, 0.48,
0.78, 0.52, 0.37, 0.61, 0.69, 0.28, 0.8, 0.53,
],
metadata: { url: "/products/sku/10148191" },
},
{
id: "3",
values: [
0.21, 0.33, 0.55, 0.67, 0.8, 0.22, 0.47, 0.63, 0.31, 0.74, 0.35, 0.53,
0.68, 0.45, 0.55, 0.7, 0.28, 0.64, 0.71, 0.3, 0.77, 0.6, 0.43, 0.39, 0.85,
0.55, 0.31, 0.69, 0.52, 0.29, 0.72, 0.48,
],
metadata: { url: "/products/sku/97913813" },
},
{
id: "4",
values: [
0.17, 0.29, 0.42, 0.57, 0.64, 0.38, 0.51, 0.72, 0.22, 0.85, 0.39, 0.66,
0.74, 0.32, 0.53, 0.48, 0.21, 0.69, 0.77, 0.34, 0.8, 0.55, 0.41, 0.29,
0.7, 0.62, 0.35, 0.68, 0.53, 0.3, 0.79, 0.49,
],
metadata: { url: "/products/sku/418313" },
},
{
id: "5",
values: [
0.11, 0.46, 0.68, 0.82, 0.27, 0.57, 0.39, 0.75, 0.16, 0.92, 0.28, 0.61,
0.85, 0.4, 0.49, 0.67, 0.19, 0.58, 0.76, 0.37, 0.83, 0.64, 0.53, 0.3,
0.77, 0.54, 0.43, 0.71, 0.36, 0.26, 0.8, 0.53,
],
metadata: { url: "/products/sku/55519183" },
},
];
export default {
async fetch(request, env, ctx): Promise<Response> {
let path = new URL(request.url).pathname;
if (path.startsWith("/favicon")) {
return new Response("", { status: 404 });
}
// You only need to insert vectors into your index once
if (path.startsWith("/insert")) {
// Insert some sample vectors into your index
// In a real application, these vectors would be the output of a machine learning (ML) model,
// such as Workers AI, OpenAI, or Cohere.
let inserted = await env.VECTORIZE.insert(sampleVectors);
// Return the mutation identifier for this insert operation
return Response.json(inserted);
}
// return Response.json({text: "nothing to do... yet"}, { status: 404 })
// In a real application, you would take a user query. For example, "what is a
// vector database" - and transform it into a vector embedding first.
//
// In this example, you will construct a vector that should
// match vector id #4
const queryVector: Array<number> = [
0.13, 0.25, 0.44, 0.53, 0.62, 0.41, 0.59, 0.68, 0.29, 0.82, 0.37, 0.5,
0.74, 0.46, 0.57, 0.64, 0.28, 0.61, 0.73, 0.35, 0.78, 0.58, 0.42, 0.32,
0.77, 0.65, 0.49, 0.54, 0.31, 0.29, 0.71, 0.57,
]; // vector of dimensions 32
// Query your index and return the three (topK = 3) most similar vector
// IDs with their similarity score.
//
// By default, vector values are not returned, as in many cases the
// vector id and scores are sufficient to map the vector back to the
// original content it represents.
const matches = await env.VECTORIZE.query(queryVector, {
topK: 3,
returnValues: true,
returnMetadata: "all",
});
return Response.json({
// This will return the closest vectors: the vectors are arranged according
// to their scores. Vectors that are more similar would show up near the top.
// In this example, Vector id #4 would turn out to be the most similar to the queried vector.
// You return the full set of matches so you can check the possible scores.
matches: matches,
});
},
} satisfies ExportedHandler<Env>;您还可以使用 Vectorize 的 queryById() 操作搜索与索引中已有向量相似的向量。
在全局部署 Worker 之前,运行以下命令使用 Cloudflare 账户登录:
npx wrangler login您将被引导到要求登录 Cloudflare 仪表板的网页。登录后,系统会询问 Wrangler 是否可以对 Cloudflare 账户进行更改。向下滚动并选择 Allow(允许) 继续。
从这里,您可以部署 Worker 使项目可在 Internet 上访问。要部署 Worker,请运行:
npx wrangler deploy部署后,在 https://vectorize-tutorial.<YOUR_SUBDOMAIN>.workers.dev 预览 Worker。
要插入向量然后查询它们,请使用已部署 Worker 的 URL,例如 https://vectorize-tutorial.<YOUR_SUBDOMAIN>.workers.dev/。打开浏览器并:
- 首先访问
/insert插入向量。这将返回以下 JSON:
// https://vectorize-tutorial.<YOUR_SUBDOMAIN>.workers.dev/insert
{
"mutationId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}这里的 mutationId 指与此异步 insert 操作对应的唯一标识符。插入的向量通常需要几秒钟才能可供查询。
您可以使用索引 info 操作检查最后处理的 mutation:
npx wrangler vectorize info tutorial-index📋 Fetching index info...
┌────────────┬─────────────┬──────────────────────────────────────┬──────────────────────────┐
│ dimensions │ vectorCount │ processedUpToMutation │ processedUpToDatetime │
├────────────┼─────────────┼──────────────────────────────────────┼──────────────────────────┤
│ 32 │ 5 │ xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx │ YYYY-MM-DDThh:mm:ss.SSSZ │
└────────────┴─────────────┴──────────────────────────────────────┴──────────────────────────┘使用相同向量 id 的后续 insert 将返回 mutation id,但不会改变索引向量计数,因为相同的向量 id 不能 insert 两次。您需要使用 upsert 操作来更新索引中已存在 id 的向量值。
- 查询索引 - 访问根路径
/时,预期查询向量[0.13, 0.25, 0.44, ...]最接近向量 ID4。此查询将返回三个(topK: 3)最接近的匹配,以及它们的向量值和元数据。
您会注意到 id: 4 的 score 为 0.46348256。由于您使用 euclidean 作为距离度量,分数越接近 0.0,向量越接近。
// https://vectorize-tutorial.<YOUR_SUBDOMAIN>.workers.dev/
{
"matches": {
"count": 3,
"matches": [
{
"id": "4",
"score": 0.46348256,
"values": [
0.17, 0.29, 0.42, 0.57, 0.64, 0.38, 0.51, 0.72, 0.22, 0.85, 0.39,
0.66, 0.74, 0.32, 0.53, 0.48, 0.21, 0.69, 0.77, 0.34, 0.8, 0.55, 0.41,
0.29, 0.7, 0.62, 0.35, 0.68, 0.53, 0.3, 0.79, 0.49
],
"metadata": {
"url": "/products/sku/418313"
}
},
{
"id": "3",
"score": 0.52920616,
"values": [
0.21, 0.33, 0.55, 0.67, 0.8, 0.22, 0.47, 0.63, 0.31, 0.74, 0.35, 0.53,
0.68, 0.45, 0.55, 0.7, 0.28, 0.64, 0.71, 0.3, 0.77, 0.6, 0.43, 0.39,
0.85, 0.55, 0.31, 0.69, 0.52, 0.29, 0.72, 0.48
],
"metadata": {
"url": "/products/sku/97913813"
}
},
{
"id": "2",
"score": 0.6337869,
"values": [
0.14, 0.23, 0.36, 0.51, 0.62, 0.47, 0.59, 0.74, 0.33, 0.89, 0.41,
0.53, 0.68, 0.29, 0.77, 0.45, 0.24, 0.66, 0.71, 0.34, 0.86, 0.57,
0.62, 0.48, 0.78, 0.52, 0.37, 0.61, 0.69, 0.28, 0.8, 0.53
],
"metadata": {
"url": "/products/sku/10148191"
}
}
]
}
}从这里,尝试传递不同的 queryVector 并观察结果:匹配和 score 应根据查询向量与索引中向量之间距离的变化而改变。
在实际应用中,queryVector 将是来自用户或系统的查询的向量嵌入表示,sampleVectors 将从真实内容生成。要在此基础上构建,请阅读结合 Workers AI 和 Vectorize 构建端到端应用的向量搜索教程。
完成本教程后,您已成功创建并查询第一个 Vectorize 索引、访问该索引的 Worker,并全局部署了项目。
- 使用 Workers AI 和 Vectorize 构建端到端向量搜索应用。
- 了解更多关于向量数据库如何工作。
- 阅读示例了解如何从 Cloudflare Workers 使用 Vectorize API。
- 欧几里得距离与余弦相似度 ↗。
- 点积 ↗。