← Cloudflare Vectorize / vectorize / best-practices
Вставка векторов
Индексы Vectorize позволяют вставлять векторы в любой момент: Vectorize оптимизирует индекс в фоновом режиме, чтобы поиск по векторам оставался эффективным даже при добавлении новых или обновлении существующих векторов.
Поддерживаемые форматы векторов
Vectorize поддерживает вставку и upsert векторов в трёх форматах:
- Массив чисел с плавающей точкой (преобразованный в JavaScript
number[]массив). - A Float32Array ↗
- A Float64Array ↗
В большинстве случаев number[] массив является наиболее простым вариантом при работе с другими API и представляет собой тип возвращаемого значения большинства API машинного обучения.
Vectorize хранит и возвращает векторные размерности в формате Float32; размерности, переданные в формате Float64, перед сохранением будут преобразованы в Float32.
Метаданные
Метаданные представляют собой необязательный набор пар «ключ и значение», которые можно прикрепить к вектору при вставке или 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 рекомендуется заранее спланировать, как вы будете выполнять запросы к векторам с фильтрацией по этим метаданным.
Внимательно учитывайте кардинальность значений метаданных применительно к вашим запросам. Кардинальность представляет собой уровень уникальности значений данных в наборе. Низкая кардинальность означает, что уникальных значений немного: например, количество планет в Солнечной системе или количество стран в мире. Высокая кардинальность означает, что уникальных значений много: строки UUIv4, метки времени с точностью до миллисекунды.
Высокая кардинальность полезна для избирательности оператора равенства ($eq) фильтр. Например, если вы хотите найти векторы, связанные с идентификатором одного пользователя. Но этот фильтр не поможет, если у всех векторов одинаковое значение. Это пример крайне низкой кардинальности.
Высокая кардинальность может также влиять на диапазонные запросы, которые выполняют поиск по нескольким уникальным значениям метаданных. Например, если индексированное значение метаданных использует временные метки с точностью до миллисекунды, производительность снизится при большом диапазоне, за который были записаны тысячи векторов с уникальными временными метками.
Под капотом Vectorize использует обратный индекс для сопоставления значений с ID векторов. Если количество уникальных значений в определённом диапазоне слишком велико, для этого требуется чтение больших частей индекса (в худшем случае полное сканирование индекса). Это может привести к проблемам с памятью, поэтому Vectorize намеренно снижает производительность и точность запроса, чтобы завершить его выполнение.
Один из способов работы с данными высокой кардинальности: сгруппировать больше векторов под одним и тем же значением с помощью бакетов. Возьмём тот же пример с меткой времени в миллисекундах: допустим, вы обычно фильтруете по диапазонам дат с шагом в 5 минут. В этом случае метку времени можно округлять вниз до ближайшей отметки в 5 минут, разбивая значения метаданных на пятиминутные окна. При этом исходную метку времени в миллисекундах можно по-прежнему хранить отдельно, в неиндексируемом поле.
Пространства имён
Пространства имён позволяют разделять векторы внутри индекса, например по идентификатору клиента, продавца или магазина.
Чтобы связать векторы с пространством имён, можно при необходимости указать namespace: string значение при выполнении операции insert или upsert. При выполнении запроса вы можете передать пространство имён, в котором нужно искать, как необязательный параметр запроса.
Пространство имён может содержать до 64 символов (байт), а на один индекс может приходиться до 1000 пространств имён. См. Лимиты документацию, чтобы узнать больше.
Если в операции запроса указано пространство имён, для поиска используются только векторы из этого пространства имён. Фильтрация по пространству имён применяется до поиска по векторам, что повышает точность найденных результатов.
Чтобы вставить векторы с указанием пространства имён:
// 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",
});Повышение пропускной способности записи
Один из способов сократить время, за которое обновления становятся видимыми в запросах: объединять больше векторов в меньшее количество запросов. Это особенно важно при высокой нагрузке на запись. О том, сколько векторов можно записать за один запрос, см. в Лимиты страницу.
Для обеспечения надёжности Vectorize сразу записывает изменения в журнал упреждающей записи (write ahead log). Чтобы эти записи стали видимыми при чтении, асинхронный процесс считывает текущие файлы индекса из R2, создаёт обновлённый индекс, записывает новые файлы индекса обратно в R2 и фиксирует изменение. Чтобы снизить накладные расходы на запись и повысить её пропускную способность, Vectorize объединяет несколько изменений в один пакет. Максимальный размер пакета составляет 200,000 векторов или 1,000 отдельных обновлений, в зависимости от того, какой предел будет достигнут раньше.
Например, предположим, что нужно добавить в индекс 250,000 векторов. Если добавлять их по одному, вызывая API вставки 250,000 раз, Vectorize будет обрабатывать не более 1000 векторов за одно задание, а значит потребуется выполнить 250 заданий. Это может занять не менее часа.
Лучше разбивать обновления на пакеты. Например, можно разделить наши 250,000 векторов на 100 файлов по 2,500 векторов в каждом и вызвать HTTP API для вставки 100 раз. Vectorize обновит индекс всего за 2 или 3 задания. Все 250,000 векторов станут доступны для запросов в течение нескольких минут.
Примеры
API Workers
Используйте insert() и upsert() методы, доступные для индекса из Cloudflare Worker, чтобы добавлять векторы в текущий индекс.
// 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 для дополнительных примеров.
wrangler CLI
Вы можете напрямую массово загружать векторные эмбеддинги:
- Файл должен быть в формате 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.ndjsonHTTP API
Vectorize также поддерживает вставку векторов через REST API, что позволяет работать с индексом Vectorize из существующих инструментов и языков машинного обучения (включая Python).
Например, чтобы вставить эмбеддинги в Формат NDJSON непосредственно из скрипта Python:
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, также поддерживают формат NDJSON благодаря встроенному read_json метод:
import pandas as pd
data = pd.read_json('embeddings.ndjson', lines=True)