跳转到内容
搜索文档

Vectorize 简介

最后更新 查看 MarkdownAgent 设置

Vectorize 是 Cloudflare 的向量数据库。向量数据库允许您使用机器学习(ML)模型执行语义搜索、推荐、分类和异常检测任务,并为 LLM(Large Language Models)提供上下文。

本指南将指导您:

  • 创建第一个 Vectorize 索引。
  • Cloudflare Worker 连接到索引。
  • 插入向量并通过查询索引执行相似性搜索。

前提条件

要继续,您需要:

  1. 如果尚未注册,请注册 Cloudflare 账户
  2. 安装 npm
  3. 安装 Node.js。使用 Node 版本管理器(如 Voltanvm)以避免权限问题并切换 Node.js 版本。Wrangler 需要 Node 版本 16.17.0 或更高。

1. 创建 Worker

您将创建一个新项目,其中包含一个 Worker,作为 Vectorize 索引的客户端应用。

运行以下命令创建名为 vectorize-tutorial 的新项目:

npm 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.jsoncvectorize-tutorial Worker 访问索引的方式。

2. 创建索引

向量数据库与传统 SQL 或 NoSQL 数据库不同。向量数据库设计用于存储向量嵌入,即数据的表示,而非原始数据本身。

要创建第一个 Vectorize 索引,请进入刚为 Workers 项目创建的目录:

cd vectorize-tutorial

要创建索引,您需要使用 wrangler vectorize create 命令并为索引提供名称。良好的索引名称应:

  • 小写和/或数字 ASCII 字符的组合,少于 32 个字符,以字母开头,使用短横线(-)代替空格。
  • 描述用例和环境。例如,"production-doc-search" 或 "dev-recommendation-engine"。
  • 仅用于描述索引,不在代码中直接引用。

此外,您需要定义要存储在索引中的向量的 dimensions,以及创建索引时用于确定相似向量的距离 metricmetric 可以是 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)配置。

3. 将 Worker 绑定到索引

您必须为 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 应用内使用。

4. [可选] 创建元数据索引

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 参数定义元数据字段的数据类型;支持 stringnumberboolean 类型。

元数据索引创建通常需要几秒钟。您可以通过运行以下命令查看 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 限制 了解完整限制列表。

5. 插入向量

在查询向量数据库之前,您需要插入向量以供查询。这些向量将从数据(如文本或图像)生成,传递给机器学习模型。但是,本教程将定义静态向量以说明向量搜索本身的工作原理。

首先,打开 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>;

在上面的代码中,您:

  1. 定义从 Workers 代码到 Vectorize 索引的绑定。此绑定与 wrangler.jsonc 文件中 "vectorise" 键下设置的 binding 值匹配。
  2. 指定一组示例向量,您将在下一步中查询这些向量。
  3. 将这些向量插入索引并确认成功。

在下一步中,您将扩展 Worker 以查询索引和插入的向量。

6. 查询向量

在此步骤中,您将获取表示传入查询的向量,并使用它搜索索引。

首先,打开 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() 操作搜索与索引中已有向量相似的向量。

7. 部署 Worker

在全局部署 Worker 之前,运行以下命令使用 Cloudflare 账户登录:

npx wrangler login

您将被引导到要求登录 Cloudflare 仪表板的网页。登录后,系统会询问 Wrangler 是否可以对 Cloudflare 账户进行更改。向下滚动并选择 Allow(允许) 继续。

从这里,您可以部署 Worker 使项目可在 Internet 上访问。要部署 Worker,请运行:

npx wrangler deploy

部署后,在 https://vectorize-tutorial.<YOUR_SUBDOMAIN>.workers.dev 预览 Worker。

8. 查询索引

要插入向量然后查询它们,请使用已部署 Worker 的 URL,例如 https://vectorize-tutorial.<YOUR_SUBDOMAIN>.workers.dev/。打开浏览器并:

  1. 首先访问 /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 的向量值。

  1. 查询索引 - 访问根路径 / 时,预期查询向量 [0.13, 0.25, 0.44, ...] 最接近向量 ID 4。此查询将返回三个(topK: 3)最接近的匹配,以及它们的向量值和元数据。

您会注意到 id: 4score0.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,并全局部署了项目。

相关资源

这篇文档对您有帮助吗?