Резервное копирование и восстановление коллекций Vector DB с использованием снимков#
Коллекция является базовой единицей хранения данных в Platform V Vector DB (далее - Vector DB). Она содержит векторы, их идентификаторы и полезную нагрузку. Однако для обеспечения эффективного поиска требуется создание дополнительных структур данных поверх самих данных. Построение этих структур может занять некоторое время, особенно для больших коллекций. Именно поэтому использование снимков является лучшим способом экспорта и импорта коллекций Vector DB, так как они содержат все необходимые элементы для быстрого восстановления всей коллекции.
В этом руководстве представлено, как создать снимок коллекции и восстановить его. Поскольку работа со снимками в распределенной среде может показаться немного более сложной, будет использоваться кластер Vector DB из трех узлов. Тем не менее тот же подход применим и к одноузловой конфигурации.
Снимки нельзя создавать в локальном режиме Python SDK. Необходимо запустить контейнер Docker Vector DB или воспользоваться облачной платформой Vector DB.
Можно использовать методы, описанные на этой странице, чтобы перенести кластер. Следуйте инструкциям данного руководства по созданию и скачиванию снимков. При восстановлении данных из снимка восстановите данные на новый кластер.
Предварительные условия#
Предположим, уже есть запущенный экземпляр или кластер Vector DB. Если это не так, необходимо следовать руководству по установке, чтобы создать кластер несколькими щелчками мыши.
Когда кластер запущен, установите требуемые зависимости:
pip install qdrant-client datasets
Установить соединение с Vector DB#
Для взаимодействия с Vector DB будут использоваться Python SDK и необработанные вызовы HTTP . Так будет использоваться кластер из трех узлов, нужно знать URL-адреса всех узлов. Для простоты сохраните их все в константах, наряду с ключом API, чтобы можно было ссылаться на них позже:
QDRANT_MAIN_URL = "https://my-cluster.com:6333"
QDRANT_NODES = (
"https://node-0.my-cluster.com:6333",
"https://node-1.my-cluster.com:6333",
"https://node-2.my-cluster.com:6333",
)
QDRANT_API_KEY = "my-api-key"
Теперь можно создать экземпляр клиента:
from qdrant_client import QdrantClient
client = QdrantClient(QDRANT_MAIN_URL, api_key=QDRANT_API_KEY)
Прежде всего следует создать коллекцию из предварительно вычисленного набора данных. Если уже есть коллекция, можно пропустить этот шаг и сразу перейти к созданию снимка.
Создание коллекции и импорт данных#
Загрузить набор данных#
В данном примере будет использован набор данных с предварительно рассчитанными вложениями (embedding), доступный на платформе Hugging Face Hub. Набор данных называется Qdrant/arxiv-titles-instructorxl-embeddings и был создан с помощью модели InstructorXL. Он содержит 2,25 млн вложений для названий статей из набора данных arXiv.
Загрузка набора данных настолько проста, насколько это возможно:
from datasets import load_dataset
dataset = load_dataset(
"Qdrant/arxiv-titles-instructorxl-embeddings", split="train", streaming=True
)
Был использован потоковый режим, поэтому набор данных не загружается в память. Вместо этого можно пройти по нему и извлечь идентификатор и вектор вложения:
for payload in dataset:
id_ = payload.pop("id")
vector = payload.pop("vector")
print(id_, vector, payload)
Отдельная полезная нагрузка выглядит следующим образом:
{
'title': 'Dynamics of partially localized brane systems',
'DOI': '1109.1415'
}
Создание коллекции#
Для начала следует создать коллекцию. Т.к. конфигурация входит в состав снимка коллекции, ее следует изменить:
from qdrant_client import models
if not client.collection_exists("test_collection"):
client.create_collection(
collection_name="test_collection",
vectors_config=models.VectorParams(
size=768, # Size of the embedding vector generated by the InstructorXL model
distance=models.Distance.COSINE
),
)
Импорт набор данных#
Расчет вложений обычно является узким местом конвейеров векторного поиска, но они уже находятся на месте. Так как целью данного руководства является демонстрация создания снимка, будет выполнена загрузка только небольшой части набора данных:
ids, vectors, payloads = [], [], []
for payload in dataset:
id_ = payload.pop("id")
vector = payload.pop("vector")
ids.append(id_)
vectors.append(vector)
payloads.append(payload)
# We are going to upload only 1000 vectors
if len(ids) == 1000:
break
client.upsert(
collection_name="test_collection",
points=models.Batch(
ids=ids,
vectors=vectors,
payloads=payloads,
),
)
Коллекция теперь готова к использованию для поиска. Необходимо создать ее снимок.
Создание и скачивание снимков#
Vector DB предоставляет конечную точку HTTP для запроса создания снимка, однако также можно вызвать ее с помощью Python SDK. Текущая установка состоит из трех узлов, поэтому нужно вызывать эту конечную точку на каждом из них и создавать снимок на каждом узле. При использовании Python SDK это означает создание отдельного экземпляра клиента для каждого узла.
Возможно получение ошибки тайм-аута, если размер коллекции большой. Можно инициировать процесс создания снимка в фоновом режиме, не дожидаясь результата, используя параметр wait=false. В любое время можно получить список всех снимков через API.
snapshot_urls = []
for node_url in QDRANT_NODES:
node_client = QdrantClient(node_url, api_key=QDRANT_API_KEY)
snapshot_info = node_client.create_snapshot(collection_name="test_collection")
snapshot_url = f"{node_url}/collections/test_collection/snapshots/{snapshot_info.name}"
snapshot_urls.append(snapshot_url)
// for `https://node-0.my-cluster.com:6333`
POST /collections/test_collection/snapshots
// for `https://node-1.my-cluster.com:6333`
POST /collections/test_collection/snapshots
// for `https://node-2.my-cluster.com:6333`
POST /collections/test_collection/snapshots
Ответ:
{
"result": {
"name": "test_collection-559032209313046-2024-01-03-13-20-11.snapshot",
"creation_time": "2024-01-03T13:20:11",
"size": 18956800
},
"status": "ok",
"time": 0.307644965
}
Как только будут URL-ссылки на снимки, их можно скачать. Обратите внимание, что запрос должен включать ключ API в заголовках. Скачивание снимка можно выполнить только через HTTP API, поэтому необходимо воспользоваться библиотекой requests.
import requests
import os
# Create a directory to store snapshots
os.makedirs("snapshots", exist_ok=True)
local_snapshot_paths = []
for snapshot_url in snapshot_urls:
snapshot_name = os.path.basename(snapshot_url)
local_snapshot_path = os.path.join("snapshots", snapshot_name)
response = requests.get(
snapshot_url, headers={"api-key": QDRANT_API_KEY}
)
with open(local_snapshot_path, "wb") as f:
response.raise_for_status()
f.write(response.content)
local_snapshot_paths.append(local_snapshot_path)
Альтернативно, можно использовать команду wget:
wget https://node-0.my-cluster.com:6333/collections/test_collection/snapshots/test_collection-559032209313046-2024-01-03-13-20-11.snapshot \
--header="api-key: ${QDRANT_API_KEY}" \
-O node-0-shapshot.snapshot
wget https://node-1.my-cluster.com:6333/collections/test_collection/snapshots/test_collection-559032209313047-2024-01-03-13-20-12.snapshot \
--header="api-key: ${QDRANT_API_KEY}" \
-O node-1-shapshot.snapshot
wget https://node-2.my-cluster.com:6333/collections/test_collection/snapshots/test_collection-559032209313048-2024-01-03-13-20-13.snapshot \
--header="api-key: ${QDRANT_API_KEY}" \
-O node-2-shapshot.snapshot
Снимки теперь хранятся локально. Можно использовать их для восстановления коллекции на другом экземпляре Vector DB или рассматривать их как резервные копии. Следует создать другую коллекцию, используя те же данные на том же кластере.
Восстановление из снимка#
Ранее созданный снимок готов к использованию для восстановления. Обычно он используется для перемещения коллекции на другой экземпляр Vector DB, но доступно использование для создания новой коллекции на том же кластере. Просто она будет иметь другое имя, test_collection_import. Нет необходимости сначала создавать коллекцию, поскольку она будет создана автоматически.
Процесс восстановления коллекции также выполняется отдельно на каждом узле, но Python SDK пока не поддерживает его. Вместо этого будет использован HTTP API, а для отправки запросов каждому узлу используется библиотека requests.
for node_url, snapshot_path in zip(QDRANT_NODES, local_snapshot_paths):
snapshot_name = os.path.basename(snapshot_path)
requests.post(
f"{node_url}/collections/test_collection_import/snapshots/upload?priority=snapshot",
headers={
"api-key": QDRANT_API_KEY,
},
files={"snapshot": (snapshot_name, open(snapshot_path, "rb"))},
)
Альтернативно, можно использовать команду curl:
curl -X POST 'https://node-0.my-cluster.com:6333/collections/test_collection_import/snapshots/upload?priority=snapshot' \
-H 'api-key: ${QDRANT_API_KEY}' \
-H 'Content-Type:multipart/form-data' \
-F 'snapshot=@node-0-shapshot.snapshot'
curl -X POST 'https://node-1.my-cluster.com:6333/collections/test_collection_import/snapshots/upload?priority=snapshot' \
-H 'api-key: ${QDRANT_API_KEY}' \
-H 'Content-Type:multipart/form-data' \
-F 'snapshot=@node-1-shapshot.snapshot'
curl -X POST 'https://node-2.my-cluster.com:6333/collections/test_collection_import/snapshots/upload?priority=snapshot' \
-H 'api-key: ${QDRANT_API_KEY}' \
-H 'Content-Type:multipart/form-data' \
-F 'snapshot=@node-2-shapshot.snapshot'
Важно
Priority=snapshot выбран, чтобы убедиться, что предпочтение отдается снимку перед данными, хранящимися на узле. Подробнее о приоритете описано в соответствующем разделе документации.