Пошаговое руководство по хранению, индексированию и поиску эмбеддингов в PostgreSQL с помощью расширения pgvector. Примерное время выполнения — 45–90 минут в зависимости от размера данных и железа.
Что вы изучите
Установка и активация расширения pgvector для PostgreSQL 16 (релиз 2023) и pgvector 0.6.2 (релиз 2025).
Создание таблицы с векторным столбцом размерности 1536 (OpenAI/Anthropic/Claude-Codex style) и индекса HNSW для быстрого поиска.
Примеры similarity search (KNN) через SQL и вставка эмбеддингов через psql и Python (psycopg 3).
Тестирование производительности, рекомендации по параметрам индекса и резервное копирование/восстановление базы с расширением vector.
Требования
PostgreSQL 16 (релиз 2023). Рекомендуется 16.5+ для исправлений до 2026.
pgvector 0.6.2 (релиз 2025). Размер исходников ~200 KB, скомпилированный модуль ~500 KB.
ОС: Ubuntu 22.04 LTS или Debian 12. Другие дистрибутивы совместимы при наличии build-essential и postgresql-server-dev-16.
Минимальные ресурсы: 2 vCPU, 8 GB RAM для тестовой среды; рекомендуемые для продакшна: 8 vCPU, 32 GB RAM, NVMe SSD.
Порты: PostgreSQL по умолчанию 5432. HNSW-индекс хранится в файлах внутри каталога данных PostgreSQL.
0
Статья была полезной?
Комментарии (0)
Войдите или зарегистрируйтесь, чтобы оставить комментарий
Загрузка комментариев…
Кому подходит руководство: инженерам и ML-инженерам, которые хотят хранить эмбеддинги рядом с данными, избежать внешних векторных сервисов и упростить RAG (retrieval-augmented generation). В конце вы получите рабочую базу с быстрым поиском по эмбеддингам и инструкциями по тестированию и бэкапу.
Зачем pgvector?
pgvector добавляет в PostgreSQL поддержку векторных столбцов и операторов для similarity search (косинусное сходство, L2). Вариант с pgvector удобен, когда вы хотите держать метаданные и эмбеддинги в едином хранилище, снизить сложность инфраструктуры и воспользоваться транзакциями и бэкапами PostgreSQL 16 (2023) для целостности данных. Для RAG это упрощает систему: одна база данных — одна точка доступа для индекса, метаданных и ACID-транзакций.
Шаг 1: установка extension
Команда для Ubuntu 22.04 / Debian 12. В примере устанавливается PostgreSQL 16 и собирается pgvector 0.6.2 (2025). Время выполнения: 3–10 минут (зависит от сети и CPU).
# Установка PostgreSQL 16
sudo apt update && sudo apt install -y postgresql-16 postgresql-server-dev-16 build-essential git
# Сборка и установка pgvector 0.6.2
git clone https://github.com/pgvector/pgvector.git
cd pgvector
git checkout v0.6.2
make
sudo make install
# Перезапуск сервиса PostgreSQL
sudo systemctl restart postgresql
Пояснение: сборка требует заголовков PostgreSQL (пакет postgresql-server-dev-16). Команда make установит бинарный модуль в каталог расширений PostgreSQL.
Ошибка: fatal error: postgres.h: No such file or directory. Причина — отсутствует пакет postgresql-server-dev-16. Фикс: sudo apt install postgresql-server-dev-16 и повторить make.
Ошибка: permission denied при install. Фикс: выполнить sudo для make install.
Шаг 2: индекс HNSW
Создадим таблицу с векторным столбцом размерности 1536 и индекс HNSW. По умолчанию HNSW в pgvector существенно быстрее для KNN на больших наборах данных; индекс строится дольше, но поиск значительно быстрее. Время создания индекса зависит от объема: для 1M векторов 1536-d на 8-core NVMe — ~20–60 минут.
-- Создание базы и расширения (в psql)
CREATE DATABASE rag_db;
\c rag_db
CREATE EXTENSION IF NOT EXISTS vector WITH VERSION '0.6.2';
-- Создание таблицы
CREATE TABLE documents (
id serial PRIMARY KEY,
content text,
embedding vector(1536) -- размерность 1536
);
-- Создание HNSW индекса
CREATE INDEX CONCURRENTLY ON documents USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 200);
Пояснение: мы используем оператор vector_cosine_ops для косинусного сходства и HNSW с параметрами m=16 и ef_construction=200, которые хорошо работают для embeddings размерности 768–4096 в большинстве задач RAG. Опция CONCURRENTLY позволяет не блокировать запись в таблицу при создании индекса.
Ожидаемый вывод (успешно):
CREATE DATABASE
CREATE EXTENSION
CREATE TABLE
CREATE INDEX
Типичная ошибка и фикс:
Ошибка: ERROR: operator class for access method "hnsw" does not exist for type vector. Причина — неправильный оператор (например, vector_l2_ops вместо vector_cosine_ops) или старая версия pgvector. Фикс: убедиться, что версия pgvector >= 0.6.2 и использовать корректный оператор: vector_cosine_ops для косинусного поиска.
Ошибка: could not create extension "vector": version mismatch. Фикс: заранее выполнить CREATE EXTENSION vector VERSION '0.6.2' и убедиться, что на сервере установлена соответствующая версия.
psql вывод создания HNSW индекса для pgvector
Шаг 3: similarity search
Пример поиска наиболее похожих документов по эмбеддингу. Используем оператор расстояния <=> (distance operator) и ORDER BY для KNN. Время запроса для HNSW: миллисекунды при корректных параметрах и NVMe.
-- Пример запроса: получить 5 ближайших по косинусному сходству
-- подставим эмбеддинг в формате массива float
SELECT id, content, embedding <=> '[0.0123, -0.321, ...]'::vector AS distance
FROM documents
ORDER BY embedding <=> '[0.0123, -0.321, ...]'::vector
LIMIT 5;
Пример вставки эмбеддинга через psql (короткий пример, 1536 значений опущены):
INSERT INTO documents (content, embedding)
VALUES ('Первый документ', '[0.001, 0.002, /* ... 1536 элементов ... */]'::vector);
Ожидаемый вывод (успешно):
id | content | distance
----+----------------+--------------------
12 | Текст релевантный | 0.0421
45 | Другой релевантный | 0.0503
(5 rows)
Типичные ошибки и фиксы:
Ошибка: ERROR: vector dimension mismatch: 1536 != 768. Причина — запросный вектор имеет другую размерность, чем столбец. Фикс: привести эмбеддинг к той же размерности или пересоздать столбец с нужной размерностью.
Ошибка: ERROR: operator does not exist: vector <=> text. Фикс: убедиться, что конвертация выполняется через ::vector или использовать параметризованный запрос в клиенте (psycopg) и передавать как bytea/float32[] преобразованный в vector.
Результат запроса similarity search в psql с расстоянием
Шаг 4: тестирование производительности
Протестируйте латентность и пропускную способность запросов KNN. Здесь показан быстрый сценарий замера одного запроса через EXPLAIN ANALYZE и пример подключаемого Python-скрипта для нагрузки. Время выполнения одного запроса для HNSW обычно 0.5–10 ms при ef_search=128 и NVMe в продакшне; для больших ef_search латентность растет.
-- В psql: план и время
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT id FROM documents
ORDER BY embedding <=> '[0.0123, -0.321, ...]'::vector
LIMIT 10;
Ожидаемый вывод (успешно):
Limit (cost=0.00..123.45 rows=10) (actual time=1.234..1.567 rows=10 loops=1)
Buffers: shared hit=12
-> Index Scan using documents_embedding_hnsw on documents (cost=0.00..4567.89) (actual time=1.200..1.481 rows=10 loops=1)
Planning Time: 0.345 ms
Execution Time: 1.567 ms
Нагрузочное тестирование через Python (psycopg 3) для 1000 последовательных запросов:
import time
import psycopg
conn = psycopg.connect("dbname=rag_db user=postgres")
cur = conn.cursor()
query = "SELECT id FROM documents ORDER BY embedding <=> %s::vector LIMIT 10;"
vec = '[0.0123, -0.321, ...]'
start = time.time()
for i in range(1000):
cur.execute(query, (vec,))
cur.fetchall()
end = time.time()
print('avg latency ms:', (end-start)/1000*1000)
Ожидаемый вывод (успешно):
avg latency ms: 2.8
Типичные ошибки и фикс:
Проблема: высокий p99 (200+ ms). Возможные причины: отсутствие индекса HNSW, ef_search слишком велик, диск HDD. Фиксы: убедиться в наличии HNSW индекса, использовать NVMe SSD, уменьшить ef_search, увеличить память и CPU.
Проблема: индекс занимает много места. Фикс: уменьшить m или использовать более агрессивную нормализацию эмбеддингов (float16) на прикладном уровне, либо sharding.
Шаг 5: backup и миграция
Бэкап и восстановление базы с расширением vector — ключевой момент. При восстановлении на новом сервере необходимо заранее создать расширение vector той же версии, что в дампе, иначе pg_restore выдаст ошибку.
# Снятие бэкапа в формате custom
pg_dump -Fc -f rag_db.dump rag_db
# На новом сервере: создать базу и установить расширение
createdb rag_db
psql -d rag_db -c "CREATE EXTENSION IF NOT EXISTS vector WITH VERSION '0.6.2';"
# Восстановление
pg_restore -d rag_db rag_db.dump
Ожидаемый вывод (успешно):
pg_dump: dumping database structure
pg_restore: connecting to database for restore
pg_restore: finished
Типичная ошибка и фикс:
Ошибка: ERROR: extension "vector" is not installed
DETAIL: Package "pgvector" is required to be present on the server. Фикс: установить бинарный модуль pgvector (см. Шаг 1) и создать расширение перед восстановлением.
Ошибка: ERROR: version mismatch for extension "vector". Фикс: установить нужную версию pgvector или открепить/удалить extension и пересоздать его в корректной версии.
Что быстрее: Pinecone или pgvector?
Краткая оценка производительности и затрат. Pinecone (управляемый векторный сервис) часто обеспечивает очень низкие латентности на больших кластерах за счёт горизонтального масштабирования и оптимизированных C++ реализаций индексов (HNSW/IVF). Однако pgvector в PostgreSQL выигрывает в интеграции, снижении сложности архитектуры и стоимости при умеренных объемах (до нескольких миллионов векторов).
Конкретика (оценочные числа на 2025–2026):
Pinecone: даёт p99 < 5 ms на глобальных endpoint при 1M+ векторов в managed-кластере; стоимость зависит от конфигурации — от десятков до сотен долларов в месяц для среднего датасета.
pgvector на PostgreSQL 16 с HNSW на NVMe и 8 vCPU: p99 обычно 5–50 ms для 1M–5M векторов при ef_search=128; стоимость — стоимость выделенных серверов/VM и администрирования, но может быть значительно ниже managed-сервисов при самостоятельном управлении.
Выбор зависит от требований: если нужна простота и интеграция с SQL и транзакциями — pgvector; если требуется глобальное масштабирование и SLA без операционной нагрузки — Pinecone или другой managed-провайдер.
Для RAG с tight integration и требованиями к транзакциям выбирайте pgvector + PostgreSQL.
Для высоконагруженного векторного поиска с минимальной операционной нагрузкой выбирайте managed-сервис.
Больше примеров и кейсов можно найти в разделах Проекты и Разбор на сайте.
Какие best practices?
Набор практик для надёжного продакшн-использования pgvector и RAG-пайплайна.
Нормализация эмбеддингов: используйте L2-нормализацию для косинусных запросов, храните float32; если экономия места критична — рассмотреть float16 на прикладном уровне и декодирование при поиске.
Размер индекса и параметры: m=8–32 и ef_construction=100–300 — разумные стартовые значения; для низкой латентности увеличьте m, для экономии места уменьшите m. Тестируйте p95/p99 на тестовом наборе данных.
CREATE INDEX CONCURRENTLY: всегда используйте CONCURRENTLY для индексов в production, чтобы избегать длительных блокировок. Для больших данных учитывайте, что concurrent индекс может занять больше времени и временно увеличить IO.
Мониторинг и метрики: собирайте p99, p95 латентности, используя pg_stat_statements и внешние метрики. Контролируйте использование памяти и IO на NVMe.
Резервирование и миграции: включать pgvector в процесс миграции; перед восстановлением всегда устанавливать ту же версию расширения.
Шардинг: для десятков миллионов векторов рассмотрите шардирование по логическому ключу (user_id) или вертикальное разделение на несколько баз с реплицами и распределителем запросов.
Кэширование: кэшируйте частые запросы на уровне приложения или используйте Redis для быстрого доступа к горячим результатам.
Частые вопросы
как хранить эмбеддинги большого размера (например, 4096) в pgvector?
Хранение эмбеддингов размерности 4096 в pgvector возможно, но требует учёта объёма диска и RAM. Один вектор float32 4096 занимает ~16 KB. Для миллиона таких векторов потребуется ~16 GB только под сырые данные, плюс размер индекса HNSW (обычно 1.5–3x от данных). Рекомендуется использовать NVMe, как минимум 64 GB RAM для удобного кэширования и тестировать параметры HNSW (m, ef_construction). При необходимости рассмотрите уменьшение размерности с помощью PCA/UMAP или float16 на этапе сохранения.
почему запросы возвращают ошибку dimension mismatch?
Ошибка dimension mismatch означает, что размерность передаваемого вектора не совпадает с объявленной размерностью столбца vector(N). Исправление: привести эмбеддинг к нужной длине или пересоздать столбец с новой размерностью. В psql для проверки размерности можно выполнить SELECT pg_typeof(embedding), octet_length(embedding::bytea) FROM documents LIMIT 1; и сверить с ожидаемой. В приложении убедитесь, что эмбеддинги генерируются одной моделью и что не происходит усечения или дописывания значений.
где хранить метаданные документов: в PostgreSQL или отдельно?
Хранение метаданных непосредственно в PostgreSQL вместе с эмбеддингами даёт преимущества транзакций, ACID и упрощённые запросы JOIN по id. Если метаданные большие (например, бинарные файлы или миллионы полей), имеет смысл хранить большие артефакты в объектном хранилище (S3) и ссылаться на них через URL в колонке metadata. Для большинства RAG-сценариев хранение текста/ключевых полей рядом с вектором оптимально.
как обеспечить отказоустойчивость pgvector решения?
Отказоустойчивость достигается стандартными средствами PostgreSQL: репликация (streaming replication), PITR (Point-in-Time Recovery) и регулярные pg_dump/pg_basebackup. Для индексов HNSW репликация будет работать на уровне файлов; при восстановлении убедитесь, что версия расширения совпадает. Для горячего восстановления рекавери тестируйте сценарии failover, чтобы понять время восстановления и возможные откаты индекса.
сколько стоит содержание pgvector в сравнении с managed решениями?
Стоимость зависит от нагрузки и объёма данных. Для небольших и средних наборов (до нескольких миллионов векторов) самостоятельный PostgreSQL на облачной VM с NVMe и 8–16 vCPU часто дешевле managed-сервисов, но требует операционной поддержки. Managed провайдеры (Pinecone, Weaviate Cloud) берут плату за удобство и масштабирование, что может быть оправдано при высоких SLA и глобальном покрытии. Оцените TCO, включая администрирование, резервное копирование и мониторинг.
pgvector для RAG: embeddings в PostgreSQL | KtoHto
Комментарии (0)
Войдите или зарегистрируйтесь, чтобы оставить комментарий
Загрузка комментариев…