INTEGRITY Документация

Введение в Vectorize

Vectorize представляет собой векторную базу данных Cloudflare. Векторные базы данных позволяют использовать модели машинного обучения (МО) для решения задач семантического поиска, рекомендаций, классификации и обнаружения аномалий, а также для предоставления контекста LLM (большим языковым моделям).

Это руководство проведёт вас через следующие шаги:

Предварительные требования

Чтобы продолжить, вам потребуется:

  1. Зарегистрируйтесь для получения Аккаунт Cloudflare ↗ если вы ещё этого не сделали.
  2. Установка npm ↗.
  3. Установка Node.js ↗. Используйте менеджер версий Node, например Volta ↗ или nvm ↗ чтобы избежать проблем с правами доступа и переключать версии Node.js. Wrangler требует версии Node 16.17.0 или более поздней версии.

1. Создайте Worker

Вы создадите новый проект с Worker, который будет выступать клиентским приложением для вашего индекса Vectorize.

Создайте новый проект с именем vectorize-tutorial выполнив:

npm create cloudflare@latest -- vectorize-tutorial

Для настройки выберите следующие параметры:

Это создаст новый vectorize-tutorial каталог. Ваш новый vectorize-tutorial каталог будет включать:

2. Создайте индекс

Векторная база данных отличается от традиционной SQL или NoSQL базы данных. Она предназначена для хранения векторных эмбеддингов, которые являются представлениями данных, а не самими исходными данными.

Чтобы создать свой первый индекс Vectorize, перейдите в каталог, который вы только что создали для проекта Workers:

cd vectorize-tutorial

Чтобы создать индекс, вам потребуется использовать wrangler vectorize create команду и укажите имя индекса. Хорошее имя индекса:

Кроме того, вам нужно будет определить как dimensions векторов, которые будут храниться в индексе, а также расстояние metric используемая для определения похожих векторов при создании индекса. metric может быть евклидовой, косинусной или основанной на скалярном произведении. Эту конфигурацию нельзя изменить позже, поскольку векторная база данных настраивается с фиксированной конфигурацией векторов.

Выполните следующую 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"

Приведённая выше команда создаст новую базу данных векторов и выведет привязка конфигурация, необходимая на следующем шаге.

3. Привяжите свой Worker к индексу

Чтобы Worker мог подключаться к индексу Vectorize, необходимо создать привязку. Bindings позволяют вашим Workers обращаться к таким ресурсам, как Vectorize или R2, из Cloudflare Workers. Вы создаёте привязки, обновляя файл Wrangler своего воркера.

Чтобы привязать индекс к своему Worker, добавьте следующее в конец файла Wrangler:

{
	"vectorize": [
		{
			"binding": "VECTORIZE", // available in your Worker on env.VECTORIZE
			"index_name": "tutorial-index"
		}
	]
}
[[vectorize]]
binding = "VECTORIZE"
index_name = "tutorial-index"

А именно:

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 определяет тип данных для поля метаданных; string, number и boolean типы поддерживаются.

Создание индекса метаданных обычно занимает несколько секунд. Проверить список индексов метаданных для вашего индекса Vectorize можно с помощью команды:

npx wrangler vectorize list-metadata-index tutorial-index
📋 Fetching metadata indexes...
┌──────────────┬────────┐
│ propertyName │ type   │
├──────────────┼────────┤
│ url          │ String │
└──────────────┴────────┘

Для одного индекса Vectorize можно создать до 10 индексов метаданных.

Для индексов метаданных типа number, точность индексируемых чисел соответствует float64.

Для индексов метаданных типа string, каждый вектор индексирует первые 64 байта строковых данных, усечённых по границам символов UTF-8 до самой длинной корректной подстроки UTF-8 в пределах этого лимита, поэтому векторы можно фильтровать по первым 64 байтам значения для каждого индексируемого свойства.

См. Ограничения 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. Определите привязку к индексу Vectorize из кода Workers. Эта привязка соответствует binding значение, которое вы задали в wrangler.jsonc файл в "vectorise" ключ.
  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, чтобы сделать проект доступным в интернете. Для развёртывания Worker выполните команду:

npx wrangler deploy

После развёртывания просмотрите свой Worker по адресу https://vectorize-tutorial.<YOUR_SUBDOMAIN>.workers.dev.

8. Запросите свой индекс

Чтобы вставить векторы, а затем выполнить по ним запрос, используйте URL-адрес развёрнутого Worker, например 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 представляет собой уникальный идентификатор, соответствующий этой асинхронной операции вставки. Обычно вставленные векторы становятся доступны для запросов через несколько секунд.

Чтобы проверить последнюю обработанную мутацию, можно использовать операцию получения информации об индексе:

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 │
└────────────┴─────────────┴──────────────────────────────────────┴──────────────────────────┘

Последующие вставки с одинаковыми идентификаторами векторов вернут идентификатор мутации, но не изменят количество векторов в индексе, поскольку одинаковые идентификаторы векторов нельзя вставить дважды. Вам потребуется использовать upsert операцию, чтобы обновить значения вектора для идентификатора, который уже существует в индексе.

  1. Выполните запрос к своему индексу: вектор запроса должен содержать [0.13, 0.25, 0.44, ...] как ближайший к вектору с ID 4 посетив корневой путь / . Этот запрос вернёт три (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 для создания комплексного приложения на Workers.

Завершив это руководство, вы успешно создали и выполнили запрос к своему первому индексу Vectorize, создали Worker для доступа к этому индексу и развернули проект по всему миру.