~/tools / Эмбеддинги и поиск (RAG) / pgvector SQL Builder

pgvector SQL Builder — SQL для pgvector: таблица, индекс HNSW/IVFFlat и запрос соседей

Напишите SQL для хранения и поиска эмбеддингов в PostgreSQL с pgvector: таблицу со столбцом vector(n) или halfvec(n), индекс HNSW или IVFFlat с классом операторов, подходящим к вашему расстоянию, и запрос ближайших соседей с удобочитаемой оценкой. Инструмент проверяет ограничения, указанные в документации pgvector, и оценивает, сколько места занимают векторы. Ничто не покидает ваш браузер.

Каждый вектор занимает 1,544 байт, поэтому 10,000 строк занимают около 15.4 MB только под векторы (индексы и другие столбцы не учтены).

1. Расширение и таблица

CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE documents (
  id bigserial PRIMARY KEY,
  content text NOT NULL,
  embedding vector(384) NOT NULL
);

2. Индекс

CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64);

3. Поиск

PREPARE принимает вектор вопроса из /api/embed как $1. Передавайте его как текст, например '[0.01,-0.02,…]'.

PREPARE search_documents(vector(384)) AS
  SELECT id, content, 1 - (embedding <=> $1) AS cosine_similarity
  FROM documents
  ORDER BY embedding <=> $1
  LIMIT 5;

-- EXECUTE search_documents('[0.0123, -0.0456, ...]');

Ограничения и значения по умолчанию из README и исходного кода pgvector 0.8.7, проверено 2026-11-04. pgvector README

Всё происходит в вашем браузере. Инструмент пишет SQL и ни к чему не подключается.

pgvector — расширение с открытым исходным кодом, которое добавляет в PostgreSQL поиск векторов по сходству, так что эмбеддинги, созданные в Ollama, можно хранить в той же базе данных, что и остальные данные. В нескольких деталях легко ошибиться. Столбец должен иметь столько же измерений, сколько и ваша модель эмбеддингов. У каждого расстояния свой оператор: <=> для косинусного расстояния, <-> для расстояния L2, <#> для отрицательного скалярного произведения и <+> для расстояния L1. Приближённый индекс используется только тогда, когда он построен с классом операторов для того же расстояния, например vector_cosine_ops для <=>, и когда запрос сортирует по самому оператору по возрастанию и содержит LIMIT. Этот инструмент пишет три части по одному набору выбранных параметров: CREATE EXTENSION и CREATE TABLE, CREATE INDEX и оператор PREPARE, который возвращает ближайшие строки с удобочитаемой оценкой (косинусное сходство равно 1 минус косинусное расстояние, а скалярное произведение равно <#>, умноженному на -1). Он применяет ограничения из README и исходного кода pgvector версии 0.8.7: до 16,000 измерений в столбце, индексы до 2,000 измерений для vector и 4,000 для halfvec, нет класса операторов L1 для IVFFlat, для HNSW m от 2 до 100 и ef_construction от 4 до 1,000 и не меньше 2 × m. В HNSW поиск возвращает не больше hnsw.ef_search строк (по умолчанию 40), поэтому инструмент предупреждает, когда LIMIT больше. Для IVFFlat он подставляет lists и probes по отправным значениям из README: rows / 1000 для таблиц до 1M строк, sqrt(rows) для больших и sqrt(lists) для probes. Сгенерированный SQL был выполнен на pgvector 0.8.7 с PostgreSQL 16 на настоящих векторах с 384 измерениями из Ollama, и EXPLAIN показал, что индекс используется.

Основная логика этого инструмента открыта под лицензией MIT. github.com/seigo5555/toolkitbox-lib/src/pgvector-sql.ts

Когда пригодится

  • Создать таблицу для фрагментов документов, прежде чем загружать эмбеддинги из Ollama в PostgreSQL
  • Проверить, какой оператор соответствует какому классу операторов для косинусного расстояния, L2, скалярного произведения или L1, чтобы индекс действительно использовался
  • Оценить, сколько места занимают векторы на небольшом VPS, и сравнить vector с halfvec

Как пользоваться

  1. Введите имя таблицы и число измерений вашей модели эмбеддингов. Это длина одного вектора из /api/embed; её показывает Embedding Similarity Calculator на этом сайте.
  2. Выберите тип, расстояние и индекс. Документация Ollama рекомендует косинусное сходство для большинства случаев семантического поиска, а /api/embed возвращает векторы длиной 1.
  3. Скопируйте три блока и выполните их в psql или другом клиенте. Индекс IVFFlat создавайте после загрузки данных; индекс HNSW можно создать на пустой таблице.

Вопросы

Какое расстояние выбрать?

Документация Ollama по эмбеддингам рекомендует косинусное сходство для большинства случаев семантического поиска. В pgvector <=> возвращает косинусное расстояние, а инструмент превращает его в cosine_similarity как 1 минус расстояние. Для векторов длиной 1, как те, что возвращает /api/embed, косинусное расстояние, расстояние L2 и скалярное произведение упорядочивают строки одинаково, потому что для таких векторов квадрат расстояния L2 равен 2 минус 2, умноженное на косинусное сходство.

HNSW или IVFFlat?

README pgvector говорит, что у HNSW запросы работают лучше, чем у IVFFlat (с точки зрения компромисса между скоростью и полнотой), но он строится медленнее и использует больше памяти, и что его можно создать на пустой таблице, так как нет этапа обучения. IVFFlat строится быстрее, использует меньше памяти, и его следует создавать после того, как в таблице появились данные. Без индекса pgvector выполняет точный поиск, дающий идеальную полноту.

Почему мой запрос не использует индекс?

README говорит, что в запросе должны быть ORDER BY и LIMIT, а ORDER BY должен быть самим оператором расстояния по возрастанию, а не выражением вроде 1 - (embedding <=> …) DESC. Оператор должен также соответствовать классу операторов индекса: <=> с vector_cosine_ops, <-> с vector_l2_ops, <#> с vector_ip_ops и <+> с vector_l1_ops. Инструмент пишет и то и другое по одному выбору. README также отмечает, что полное сканирование таблицы может быть быстрее, если таблица небольшая.

Почему я получаю меньше строк, чем задано в LIMIT?

В HNSW результаты ограничены параметром hnsw.ef_search, по умолчанию 40; когда мы попробовали LIMIT 100 на таблице из 200 строк, то получали 40 строк, пока не повысили hnsw.ef_search до 100. README добавляет, что фильтрация через WHERE применяется после сканирования индекса, поэтому условие может оставить ещё меньше строк. Начиная с версии 0.8.0 итеративное сканирование индекса (SET hnsw.iterative_scan = strict_order или relaxed_order) при необходимости просматривает индекс дальше.

Что такое halfvec?

Тип вектора с половинной точностью. Каждый вектор занимает 2 × измерения + 8 байт вместо 4 × измерения + 8, а индексы HNSW и IVFFlat по halfvec поддерживают до 4,000 измерений вместо 2,000. Каждый элемент — число с плавающей запятой половинной точности, поэтому значения хранятся менее точно.

Отправляются ли мои данные куда-либо?

Нет. Инструмент только пишет SQL в вашем браузере и никогда не подключается к базе данных.

Похожие статьи

Похожие