F.75. вектор (pgvector)#
F.75. вектор (pgvector) #
- F.75.1. О векторе
- F.75.2. Начало работы
- F.75.3. Хранение
- F.75.4. Запросы
- F.75.5. Индексирование
- F.75.6. HNSW
- F.75.7. IVFFlat
- F.75.8. Фильтрация
- F.75.9. Итеративные сканирования индекса
- F.75.10. Векторы половинной точности
- F.75.11. Индексирование с половинной точностью
- F.75.12. Бинарные векторы
- F.75.13. Бинарная квантизация
- F.75.14. Разреженные векторы
- F.75.15. Гибридный Поиск
- F.75.16. Индексация подвекторов
- F.75.17. Производительность
- F.75.18. Мониторинг
- F.75.19. Масштабирование
- F.75.20. Языки
- F.75.21. Часто задаваемые вопросы
- F.75.22. Устранение неполадок
- F.75.23. Справка
- F.75.24. Хостинг Postgres
- F.75.25. Обновление
- F.75.26. Спасибо
- F.75.27. История
- F.75.28. Для разработчика
Открытый поиск векторного сходства для Postgres.
Храните ваши векторы вместе с остальными данными. Поддерживает:
точный и приближённый поиск ближайших соседей
одинарной точности, половинной точности, двоичные и разреженные векторы
L2 расстояние, скалярное произведение, косинусное расстояние, L1 расстояние, Хэммингово расстояние и расстояние Жаккара
любой язык с клиентом Postgres
Плюс соответствие ACID, восстановление на определенный момент времени, JOINs и все другие отличные возможности Postgres
F.75.2. Начало работы #
Включите расширение (сделайте это один раз в каждой базе данных, где вы хотите его использовать)
CREATE EXTENSION vector;
Создайте векторный столбец с 3 измерениями
CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3));
Вставить векторы
INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]');
Получить ближайших соседей по L2 расстоянию
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
Также поддерживает скалярное произведение (<#>
), косинусное
расстояние (<=>
) и L1 расстояние
(<+>
)
Note: <#>
возвращает отрицательное внутреннее
произведение, так как Postgres поддерживает только ASC
порядок
индексных сканирований для операторов
F.75.3. Хранение #
Создать новую таблицу с векторной колонкой
CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3));
Или добавьте векторный столбец в существующую таблицу
ALTER TABLE items ADD COLUMN embedding vector(3);
Также поддерживает половинной точности, бинарные и разреженные векторы
Вставить векторы
INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]');
Или загрузите векторы оптом, используя COPY
(пример)
COPY items (embedding) FROM STDIN WITH (FORMAT BINARY);
Обновление или вставка векторов
INSERT INTO items (id, embedding) VALUES (1, '[1,2,3]'), (2, '[4,5,6]') ON CONFLICT (id) DO UPDATE SET embedding = EXCLUDED.embedding;
Обновить векторы
UPDATE items SET embedding = '[1,2,3]' WHERE id = 1;
Удалить векторы
DELETE FROM items WHERE id = 1;
F.75.4. Запросы #
Получить ближайших соседей к вектору
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
Поддерживаемые функции расстояния:
<->
- расстояние L2<#>
- (отрицательное) скалярное произведение<=>
- косинусное расстояние<+>
- L1 расстояние<~>
- Хэммингово расстояние (бинарные векторы)<%>
- расстояние Джаккарда (бинарные векторы)
Получить ближайших соседей для строки
SELECT * FROM items WHERE id != 1 ORDER BY embedding <-> (SELECT embedding FROM items WHERE id = 1) LIMIT 5;
Получить строки в пределах определенного расстояния
SELECT * FROM items WHERE embedding <-> '[3,1,2]' < 5;
Note: Используйте вместе с ORDER BY
и
LIMIT
, чтобы использовать индекс
F.75.4.1. Расстояния #
Получить расстояние
SELECT embedding <-> '[3,1,2]' AS distance FROM items;
Для скалярного произведения умножьте на -1 (так как
<#>
возвращает отрицательное скалярное произведение)
SELECT (embedding <#> '[3,1,2]') * -1 AS inner_product FROM items;
Для косинусного сходства используйте 1 - косинусное расстояние
SELECT 1 - (embedding <=> '[3,1,2]') AS cosine_similarity FROM items;
F.75.4.2. Агрегатные функции #
Средние векторы
SELECT AVG(embedding) FROM items;
Средние группы векторов
SELECT category_id, AVG(embedding) FROM items GROUP BY category_id;
F.75.5. Индексирование #
По умолчанию pgvector выполняет точный поиск ближайших соседей, который обеспечивает идеальную полноту.
Вы можете добавить индекс для использования приблизительного поиска ближайших соседей, который обменивает некоторую точность на скорость. В отличие от типичных индексов, вы увидите разные результаты для запросов после добавления приблизительного индекса.
Поддерживаемые типы индексов:
F.75.6. HNSW #
Индекс HNSW создает многослойный граф. Он обеспечивает лучшую производительность запросов, чем IVFFlat (в терминах компромисса между скоростью и точностью), но имеет более медленное время построения и использует больше памяти. Также индекс может быть создан без каких-либо данных в таблице, так как отсутствует этап обучения, как в IVFFlat.
Добавьте индекс для каждой функции расстояния, которую вы хотите использовать.
Расстояние L2
CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);
Note: Используйте halfvec_l2_ops
для
halfvec
и sparsevec_l2_ops
для sparsevec
(и аналогично с другими
функциями расстояния)
Внутреннее произведение
CREATE INDEX ON items USING hnsw (embedding vector_ip_ops);
Косинусное расстояние
CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);
Расстояние L1
CREATE INDEX ON items USING hnsw (embedding vector_l1_ops);
Хэммингово расстояние
CREATE INDEX ON items USING hnsw (embedding bit_hamming_ops);
Расстояние Жаккара
CREATE INDEX ON items USING hnsw (embedding bit_jaccard_ops);
Поддерживаемые типы:
vector
- до 2,000 измеренийhalfvec
- до 4,000 измеренийbit
- до 64,000 измеренийsparsevec
- до 1,000 ненулевых элементов
F.75.6.1. Параметры индекса #
Укажите параметры HNSW
m
- максимальное количество подключений на слой (по умолчанию 16)ef_construction
- размер динамического списка кандидатов для построения графа (по умолчанию 64)
CREATE INDEX ON items USING hnsw (embedding vector_l2_ops) WITH (m = 16, ef_construction = 64);
Большее значение ef_construction
обеспечивает
лучшую полноту при стоимости времени построения индекса / скорости вставки.
F.75.6.2. Параметры запроса #
Укажите размер динамического списка кандидатов для поиска (по умолчанию 40)
SET hnsw.ef_search = 100;
Большее значение обеспечивает лучшую полноту за счет скорости.
Используйте SET LOCAL
внутри транзакции, чтобы установить его
для одного запроса
BEGIN; SET LOCAL hnsw.ef_search = 100; SELECT ... COMMIT;
F.75.6.3. Время построения индекса #
Индексы строятся значительно быстрее, когда граф помещается в
maintenance_work_mem
SET maintenance_work_mem = '8GB';
Показывается уведомление, когда график больше не помещается
NOTICE: hnsw graph no longer fits into maintenance_work_mem after 100000 tuples DETAIL: Building will take significantly more time. HINT: Increase maintenance_work_mem to speed up builds.
Note: Не устанавливайте maintenance_work_mem
настолько высоким,
чтобы это исчерпало память на сервере
Как и другие типы индексов, быстрее создать индекс после загрузки ваших начальных данных
Вы также можете ускорить создание индекса, увеличив количество параллельных рабочих процессов (по умолчанию 2)
SET max_parallel_maintenance_workers = 7; -- plus leader
Для большого количества рабочих процессов, возможно, вам также потребуется увеличить
max_parallel_workers
(по умолчанию 8)
F.75.6.4. Прогресс Индексации #
Проверьте прогресс индексации
SELECT phase, round(100.0 * blocks_done / nullif(blocks_total, 0), 1) AS "%" FROM pg_stat_progress_create_index;
Фазы для HNSW следующие:
initializing
загрузка кортежей
F.75.7. IVFFlat #
Индекс IVFFlat делит векторы на списки, а затем ищет подмножество этих списков, которые находятся ближе всего к вектору запроса. Он имеет более быстрое время построения и использует меньше памяти, чем HNSW, но имеет более низкую производительность запросов (в терминах компромисса между скоростью и полнотой).
Три ключа к достижению хорошего запоминания:
Создайте индекс после того, как в таблице появятся данные
Выберите подходящее количество списков - хорошей отправной точкой является
строки / 1000
для до 1M строк иsqrt(строк)
для более 1M строкПри выполнении запроса укажите соответствующее количество проб (большее количество лучше для полноты, меньшее - для скорости) - хорошей отправной точкой является
sqrt(lists)
Добавьте индекс для каждой функции расстояния, которую вы хотите использовать.
Расстояние L2
CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 100);
Note: Используйте halfvec_l2_ops
для
halfvec
(и аналогично с другими функциями
расстояния)
Внутреннее произведение
CREATE INDEX ON items USING ivfflat (embedding vector_ip_ops) WITH (lists = 100);
Косинусное расстояние
CREATE INDEX ON items USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
Хэммингово расстояние
CREATE INDEX ON items USING ivfflat (embedding bit_hamming_ops) WITH (lists = 100);
Поддерживаемые типы:
vector
- до 2,000 измеренийhalfvec
- до 4,000 измеренийbit
- до 64,000 измерений
F.75.7.1. Параметры запроса #
Укажите количество проб (по умолчанию 1)
SET ivfflat.probes = 10;
Большее значение обеспечивает лучшую полноту за счет скорости, и его можно установить на количество списков для точного поиска ближайших соседей (в этом случае планировщик не будет использовать индекс)
Используйте SET LOCAL
внутри транзакции, чтобы установить его
для одного запроса
BEGIN; SET LOCAL ivfflat.probes = 10; SELECT ... COMMIT;
F.75.7.2. Время построения индекса #
Ускорьте создание индексов на больших таблицах, увеличив количество параллельных рабочих процессов (по умолчанию 2)
SET max_parallel_maintenance_workers = 7; -- plus leader
Для большого количества рабочих процессов, возможно, вам также потребуется увеличить
max_parallel_workers
(по умолчанию 8)
F.75.7.3. Прогресс Индексации #
Проверьте прогресс индексации
SELECT phase, round(100.0 * tuples_done / nullif(tuples_total, 0), 1) AS "%" FROM pg_stat_progress_create_index;
Фазы для IVFFlat:
initializing
выполнение k-means
присвоение кортежей
загрузка кортежей
Примечание: %
заполняется только во время
фазы загрузки кортежей
F.75.8. Фильтрация #
Существует несколько способов индексировать запросы ближайших соседей с
WHERE
условием.
SELECT * FROM items WHERE category_id = 123 ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
Хорошее место для начала - создание индекса на фильтрующем столбце. Это может обеспечить быстрый, точный поиск ближайших соседей во многих случаях. Postgres имеет ряд типов индексов для этого: B-tree (по умолчанию), hash, GiST, SP-GiST, GIN, и BRIN.
CREATE INDEX ON items (category_id);
Для нескольких столбцов рассмотрите многоколоночный индекс.
CREATE INDEX ON items (location_id, category_id);
Точные индексы хорошо работают для условий, которые соответствуют низкому проценту строк. В противном случае, приблизительные индексы могут работать лучше.
CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);
С приблизительными индексами фильтрация применяется
после сканирования индекса. Если условие
соответствует 10% строк, с HNSW и значением по умолчанию
hnsw.ef_search
равным 40, в среднем будет соответствовать только 4 строки. Для большего количества строк увеличьте
hnsw.ef_search
.
SET hnsw.ef_search = 200;
Начиная с версии 0.8.0, вы можете включить итеративные индексные сканирования, которые автоматически будут сканировать больше индекса, когда это необходимо.
SET hnsw.iterative_scan = strict_order;
Если фильтрация осуществляется только по нескольким различным значениям, рассмотрите частичное индексирование.
CREATE INDEX ON items USING hnsw (embedding vector_l2_ops) WHERE (category_id = 123);
Если фильтрация осуществляется по многим различным значениям, рассмотрите возможность разбиения на разделы.
CREATE TABLE items (embedding vector(3), category_id int) PARTITION BY LIST(category_id);
F.75.9. Итеративные сканирования индекса #
Добавлено в 0.8.0
С приблизительными индексами запросы с фильтрацией могут возвращать меньше
результатов, так как фильтрация применяется после сканирования
индекса. Начиная с версии 0.8.0, вы можете включить итеративные
сканирования индекса, которые автоматически будут сканировать больше индекса, пока
не будет найдено достаточно результатов (или пока не достигнет
hnsw.max_scan_tuples
или
ivfflat.max_probes
).
Итеративные сканирования могут использовать строгое или свободное упорядочение.
Strict гарантирует, что результаты будут в точном порядке по расстоянию
SET hnsw.iterative_scan = strict_order;
Relaxed позволяет результатам быть немного не в порядке по расстоянию, но обеспечивает лучшую полноту
SET hnsw.iterative_scan = relaxed_order; # or SET ivfflat.iterative_scan = relaxed_order;
С ослабленным упорядочиванием вы можете использовать материализованное CTE, чтобы получить строгое упорядочивание
WITH relaxed_results AS MATERIALIZED ( SELECT id, embedding <-> '[1,2,3]' AS distance FROM items WHERE category_id = 123 ORDER BY distance LIMIT 5 ) SELECT * FROM relaxed_results ORDER BY distance;
Для запросов, которые фильтруют по расстоянию, используйте материализованное CTE и размещайте фильтр расстояния за его пределами для достижения наилучшей производительности (из-за текущего поведения исполнителя Postgres)
WITH nearest_results AS MATERIALIZED ( SELECT id, embedding <-> '[1,2,3]' AS distance FROM items ORDER BY distance LIMIT 5 ) SELECT * FROM nearest_results WHERE distance < 5 ORDER BY distance;
Примечание: Разместите любые другие фильтры внутри CTE
F.75.9.1. Итеративные параметры сканирования #
Поскольку сканирование значительной части приблизительного индекса является дорогостоящим, существуют опции для управления завершением сканирования.
F.75.9.1.1. HNSW #
Укажите максимальное количество кортежей для посещения (по умолчанию 20,000)
SET hnsw.max_scan_tuples = 20000;
Примечание: Это приблизительно и не влияет на начальное сканирование
Укажите максимальный объем памяти для использования, как кратное
work_mem
(по умолчанию 1)
SET hnsw.scan_mem_multiplier = 2;
Note: Попробуйте увеличить это значение, если увеличение
hnsw.max_scan_tuples
не улучшает
полноту
F.75.9.1.2. IVFFlat #
Укажите максимальное количество проб
SET ivfflat.max_probes = 100;
Note: Если это значение меньше, чем ivfflat.probes
,
будет использовано значение ivfflat.probes
F.75.10. Векторы половинной точности #
Используйте тип halfvec
для хранения векторов с половинной точностью
CREATE TABLE items (id bigserial PRIMARY KEY, embedding halfvec(3));
F.75.11. Индексирование с половинной точностью #
Индексы векторов с половинной точностью для меньших индексов
CREATE INDEX ON items USING hnsw ((embedding::halfvec(3)) halfvec_l2_ops);
Получить ближайших соседей
SELECT * FROM items ORDER BY embedding::halfvec(3) <-> '[1,2,3]' LIMIT 5;
F.75.12. Бинарные векторы #
Используйте тип bit
для хранения бинарных векторов
(пример)
CREATE TABLE items (id bigserial PRIMARY KEY, embedding bit(3)); INSERT INTO items (embedding) VALUES ('000'), ('111');
Получить ближайших соседей по расстоянию Хэмминга
SELECT * FROM items ORDER BY embedding <~> '101' LIMIT 5;
Также поддерживает расстояние Джаккара (<%>
)
F.75.13. Бинарная квантизация #
Используйте индексирование выражений для бинарной квантования
CREATE INDEX ON items USING hnsw ((binary_quantize(embedding)::bit(3)) bit_hamming_ops);
Получить ближайших соседей по расстоянию Хэмминга
SELECT * FROM items ORDER BY binary_quantize(embedding)::bit(3) <~> binary_quantize('[1,-2,3]') LIMIT 5;
Пересортировать по оригинальным векторам для лучшего восстановления
SELECT * FROM ( SELECT * FROM items ORDER BY binary_quantize(embedding)::bit(3) <~> binary_quantize('[1,-2,3]') LIMIT 20 ) ORDER BY embedding <=> '[1,-2,3]' LIMIT 5;
F.75.14. Разреженные векторы #
Используйте тип sparsevec
для хранения разреженных векторов
CREATE TABLE items (id bigserial PRIMARY KEY, embedding sparsevec(5));
Вставить векторы
INSERT INTO items (embedding) VALUES ('{1:1,3:2,5:3}/5'), ('{1:4,3:5,5:6}/5');
Формат
{индекс1:значение1,индекс2:значение2}/размерности
и
индексы начинаются с 1, как в SQL массивах
Получить ближайших соседей по L2 расстоянию
SELECT * FROM items ORDER BY embedding <-> '{1:3,3:1,5:2}/5' LIMIT 5;
F.75.15. Гибридный Поиск #
Используйте вместе с Postgres полнотекстовым поиском для гибридного поиска.
SELECT id, content FROM items, plainto_tsquery('hello search') query WHERE textsearch @@ query ORDER BY ts_rank_cd(textsearch, query) DESC LIMIT 5;
Вы можете использовать Reciprocal Rank Fusion или кросс-энкодер, чтобы объединить результаты.
F.75.16. Индексация подвекторов #
Используйте индексирование выражений для индексирования подвекторов
CREATE INDEX ON items USING hnsw ((subvector(embedding, 1, 3)::vector(3)) vector_cosine_ops);
Получить ближайших соседей по косинусному расстоянию
SELECT * FROM items ORDER BY subvector(embedding, 1, 3)::vector(3) <=> subvector('[1,2,3,4,5]'::vector, 1, 3) LIMIT 5;
Повторно ранжировать по полным векторам для лучшего восстановления
SELECT * FROM ( SELECT * FROM items ORDER BY subvector(embedding, 1, 3)::vector(3) <=> subvector('[1,2,3,4,5]'::vector, 1, 3) LIMIT 20 ) ORDER BY embedding <=> '[1,2,3,4,5]' LIMIT 5;
F.75.17. Производительность #
F.75.17.1. Настройка #
Используйте инструмент, такой как
PgTune
для установки начальных значений параметров сервера Postgres. Например,
shared_buffers
обычно должен составлять
25% от памяти сервера. Вы можете найти файл конфигурации с помощью:
SHOW config_file;
И проверьте отдельные настройки с помощью:
SHOW shared_buffers;
Обязательно перезапустите Postgres, чтобы изменения вступили в силу.
F.75.17.2. Загрузка #
Используйте COPY
для массовой загрузки данных
(пример).
COPY items (embedding) FROM STDIN WITH (FORMAT BINARY);
Добавьте любые индексы после загрузки начальных данных для достижения наилучшей производительности.
F.75.17.3. Индексирование #
См. время построения индекса для HNSW и IVFFlat.
В производственных средах создавайте индексы параллельно, чтобы избежать блокировки записей.
CREATE INDEX CONCURRENTLY ...
F.75.17.4. Запросы #
Используйте EXPLAIN ANALYZE
для отладки производительности.
EXPLAIN ANALYZE SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
F.75.17.4.1. Точный поиск #
Чтобы ускорить запросы без индекса, увеличьте
max_parallel_workers_per_gather
.
SET max_parallel_workers_per_gather = 4;
Если векторы нормализованы до длины 1 (как встраивания OpenAI), используйте скалярное произведение для лучшей производительности.
SELECT * FROM items ORDER BY embedding <#> '[3,1,2]' LIMIT 5;
F.75.17.4.2. Приблизительный Поиск #
Чтобы ускорить запросы с индексом IVFFlat, увеличьте количество инвертированных списков (за счет точности).
CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 1000);
F.75.17.5. Вакуумирование #
Очистка может занять некоторое время для индексов HNSW. Ускорьте процесс, сначала переиндексировав.
REINDEX INDEX CONCURRENTLY index_name; VACUUM table_name;
F.75.18. Мониторинг #
Отслеживайте производительность с помощью
pg_stat_statements
(не забудьте добавить его в
shared_preload_libraries
).
CREATE EXTENSION pg_stat_statements;
Получите наиболее времязатратные запросы с помощью:
SELECT query, calls, ROUND((total_plan_time + total_exec_time) / calls) AS avg_time_ms, ROUND((total_plan_time + total_exec_time) / 60000) AS total_time_min FROM pg_stat_statements ORDER BY total_plan_time + total_exec_time DESC LIMIT 20;
Note: Замените total_plan_time + total_exec_time
на total_time
для Postgres < 13
Контролируйте отзыв, сравнивая результаты приблизительного поиска с точным поиском.
BEGIN; SET LOCAL enable_indexscan = off; -- use exact search SELECT ... COMMIT;
F.75.19. Масштабирование #
Масштабируйте pgvector так же, как вы масштабируете Postgres.
Масштабируйте вертикально, увеличивая память, ЦП и хранилище на одном экземпляре. Используйте существующие инструменты для настройки параметров и мониторинга производительности.
Масштабируйте горизонтально с репликами, или используйте Citus или другой подход для шардирования (пример).
F.75.20. Языки #
Используйте pgvector из любого языка с клиентом Postgres. Вы можете даже генерировать и сохранять векторы на одном языке и выполнять запросы на другом.
Язык | Библиотеки / Примеры |
---|---|
C | pgvector-c |
C++ | pgvector-cpp |
C#, F#, Visual Basic | pgvector-dotnet |
Кристалл | pgvector-crystal |
Д | pgvector-d |
Дарт | pgvector-dart |
Elixir | pgvector-elixir |
Эрланг | pgvector-erlang |
Фортран | pgvector-fortran |
Gleam | pgvector-gleam |
Перейти | pgvector-go |
Хаскель | pgvector-haskell |
Java, Kotlin, Groovy, Scala | pgvector-java |
JavaScript, TypeScript | pgvector-node |
Джулия | pgvector-julia |
Лисп | pgvector-lisp |
Lua | pgvector-lua |
Ним | pgvector-nim |
OCaml | pgvector-ocaml |
Perl | pgvector-perl |
PHP | pgvector-php |
Питон | pgvector-python |
Р | pgvector-r |
Raku | pgvector-raku |
Ruby | pgvector-ruby, Neighbor |
Rust | pgvector-rust |
Swift | pgvector-swift |
Zig | pgvector-zig |
F.75.21. Часто задаваемые вопросы #
F.75.21.1. Сколько векторов можно хранить в одной таблице? #
Неразделенная таблица имеет ограничение в 32 ТБ по умолчанию в Postgres. Разделенная таблица может иметь тысячи разделов такого размера.
F.75.21.2. Поддерживается ли репликация? #
Да, pgvector использует журнал предзаписи (WAL), который позволяет репликацию и восстановление до определенного момента времени.
F.75.21.3. Что, если я хочу индексировать векторы с более чем 2000 измерениями? #
Вы можете использовать индексирование с половинной точностью для индексирования до 4,000 измерений или бинарную квантизацию для индексирования до 64,000 измерений. Другой вариант — снижение размерности.
F.75.21.4. Могу ли я хранить векторы с разными размерами в одном столбце? #
Вы можете использовать vector
как тип (вместо
vector(3)
).
CREATE TABLE embeddings (model_id bigint, item_id bigint, embedding vector, PRIMARY KEY (model_id, item_id));
Однако вы можете создавать индексы только на строках с одинаковым количеством измерений (используя выражение и частичное индексирование):
CREATE INDEX ON embeddings USING hnsw ((embedding::vector(3)) vector_l2_ops) WHERE (model_id = 123);
и выполнить запрос с:
SELECT * FROM embeddings WHERE model_id = 123 ORDER BY embedding::vector(3) <-> '[3,1,2]' LIMIT 5;
F.75.21.5. Могу ли я хранить векторы с большей точностью? #
Вы можете использовать тип double precision[]
или
numeric[]
для хранения векторов с большей
точностью.
CREATE TABLE items (id bigserial PRIMARY KEY, embedding double precision[]); -- use {} instead of [] for Postgres arrays INSERT INTO items (embedding) VALUES ('{1,2,3}'), ('{4,5,6}');
При необходимости добавьте
проверочное
ограничение, чтобы гарантировать возможность преобразования данных в
тип vector
и наличие ожидаемых размеров.
ALTER TABLE items ADD CHECK (vector_dims(embedding::vector) = 3);
Используйте индексацию выражений для индексации (с меньшей точностью):
CREATE INDEX ON items USING hnsw ((embedding::vector(3)) vector_l2_ops);
и выполнить запрос с:
SELECT * FROM items ORDER BY embedding::vector(3) <-> '[3,1,2]' LIMIT 5;
F.75.21.6. Нужно ли индексам помещаться в память? #
Нет, но, как и в случае с другими типами индексов, вы, вероятно, увидите лучшую производительность, если они это сделают. Вы можете узнать размер индекса с помощью:
SELECT pg_size_pretty(pg_relation_size('index_name'));
F.75.22. Устранение неполадок #
F.75.22.1. Почему запрос не использует индекс? #
Запрос должен иметь ORDER BY
и
LIMIT
, и ORDER BY
должен быть результатом оператора расстояния (не выражения) в
порядке возрастания.
-- index ORDER BY embedding <=> '[3,1,2]' LIMIT 5; -- no index ORDER BY 1 - (embedding <=> '[3,1,2]') DESC LIMIT 5;
Вы можете побудить планировщик использовать индекс для запроса с помощью:
BEGIN; SET LOCAL enable_seqscan = off; SELECT ... COMMIT;
Также, если таблица небольшая, сканирование таблицы может быть быстрее.
F.75.22.2. Почему запрос не использует параллельное сканирование таблицы? #
Планировщик не учитывает внешнее хранение в оценках стоимости, что может сделать последовательное сканирование выглядящим дешевле. Вы можете уменьшить стоимость параллельного сканирования для запроса с:
BEGIN; SET LOCAL min_parallel_table_scan_size = 1; SET LOCAL parallel_setup_cost = 1; SELECT ... COMMIT;
или выберите хранение векторов встроенно:
ALTER TABLE items ALTER COLUMN embedding SET STORAGE PLAIN;
F.75.22.3. Почему после добавления индекса HNSW для запроса становится меньше результатов? #
Результаты ограничены размером динамического списка кандидатов
(hnsw.ef_search
), который по умолчанию равен 40.
Результатов может быть даже меньше из-за "мертвых" кортежей или условий
фильтрации в запросе. Включение
итеративных сканирований
индекса может помочь в решении этой проблемы.
Также обратите внимание, что векторы с NULL
не индексируются
(так же как и нулевые векторы для косинусного расстояния).
F.75.22.4. Почему после добавления индекса IVFFlat для запроса становится меньше результатов? #
Индекс, вероятно, был создан с слишком малым количеством данных для количества списков. Удалите индекс, пока в таблице не будет больше данных.
DROP INDEX index_name;
Результаты также могут быть ограничены количеством проб
(ivfflat.probes
). Включение
итеративных сканирований
индекса может решить эту проблему.
Также обратите внимание, что векторы с NULL
не индексируются
(так же как и нулевые векторы для косинусного расстояния).
F.75.23. Справка #
F.75.23.1. Тип вектора #
Каждый вектор занимает 4 * размерности + 8
байт
памяти. Каждый элемент является числом с плавающей запятой одинарной точности
(как тип real
в Postgres), и все элементы должны быть конечными (без NaN
,
Infinity
или -Infinity
).
Векторы могут иметь до 16,000 размерностей.
F.75.23.2. Операторы векторов #
Оператор | Описание | Добавлено |
---|---|---|
+ | поэлементное сложение | |
- | поэлементное вычитание | |
* | поэлементное умножение | 0.5.0 |
|| | конкатенация | 0.7.0 |
<-> | Евклидово расстояние | |
<#> | отрицательное скалярное произведение | |
<=> | косинусное расстояние | |
<+> | таксистское расстояние | 0.7.0 |
F.75.23.3. Функции векторные #
Функция | Описание | Добавлено |
---|---|---|
binary_quantize(vector) → bit | бинарное квантование | 0.7.0 |
cosine_distance(vector, vector) → double precision | косинусное расстояние | |
скалярное произведение(vector, vector) → double precision | скалярное произведение | |
l1_distance(vector, vector) → double precision | манхэттенское расстояние | 0.5.0 |
l2_distance(vector, vector) → double precision | Евклидово расстояние | |
l2_normalize(vector) → vector | Нормализация с евклидовой нормой | 0.7.0 |
subvector(vector, integer, integer) → вектор | subvector | 0.7.0 |
vector_dims(vector) → integer | количество измерений | |
vector_norm(vector) → double precision | Евклидова норма |
F.75.23.4. Функции агрегирования векторов #
Функция | Описание | Добавлено |
---|---|---|
avg(vector) → vector | среднее | |
sum(vector) → вектор | сумма | 0.5.0 |
F.75.23.5. Тип Halfvec #
Каждый полувектор занимает 2 * dimensions + 8
байт памяти. Каждый элемент является числом с плавающей запятой
половинной точности, и все элементы должны быть конечными (без
NaN
, Infinity
или
-Infinity
). Полувекторы могут иметь до
16,000 измерений.
F.75.23.6. Операторы Halfvec #
Оператор | Описание | Добавлено |
---|---|---|
+ | поэлементное сложение | 0.7.0 |
- | поэлементное вычитание | 0.7.0 |
* | поэлементное умножение | 0.7.0 |
|| | конкатенация | 0.7.0 |
<-> | Евклидово расстояние | 0.7.0 |
<#> | отрицательное скалярное произведение | 0.7.0 |
<=> | косинусное расстояние | 0.7.0 |
<+> | таксистское расстояние | 0.7.0 |
F.75.23.7. Функции Halfvec #
Функция | Описание | Добавлено |
---|---|---|
binary_quantize(halfvec) → бит | бинарное квантование | 0.7.0 |
cosine_distance(halfvec, halfvec) → double precision | косинусное расстояние | 0.7.0 |
inner_product(halfvec, halfvec) → double precision | скалярное произведение | 0.7.0 |
l1_distance(halfvec, halfvec) → double precision | таксистское расстояние | 0.7.0 |
l2_distance(halfvec, halfvec) → double precision | Евклидово расстояние | 0.7.0 |
l2_norm(halfvec) → double precision | Евклидова норма | 0.7.0 |
l2_normalize(halfvec) → halfvec | Нормализация с использованием евклидовой нормы | 0.7.0 |
subvector(halfvec, integer, integer) → halfvec | подвектор | 0.7.0 |
vector_dims(halfvec) → integer | количество измерений | 0.7.0 |
F.75.23.8. Функции агрегирования Halfvec #
Функция | Описание | Добавлено |
---|---|---|
avg(halfvec) → halfvec | среднее | 0.7.0 |
sum(halfvec) → halfvec | сумма | 0.7.0 |
F.75.23.9. Тип Bit #
Каждый битовый вектор занимает размерности / 8 + 8
байт памяти. См.
документацию
Postgres для получения дополнительной информации.
F.75.23.10. Битовые операторы #
Оператор | Описание | Добавлено |
---|---|---|
<~> | Расстояние Хэмминга | 0.7.0 |
<%> | Расстояние Джаккарда | 0.7.0 |
F.75.23.11. Битовые функции #
Функция | Описание | Добавлено |
---|---|---|
hamming_distance(bit, bit) → double precision | Расстояние Хэмминга | 0.7.0 |
jaccard_distance(bit, bit) → double precision | Расстояние Джаккарда | 0.7.0 |
F.75.23.12. Тип Sparsevec #
Каждый разреженный вектор занимает
8 * ненулевых элементов + 16
байт памяти.
Каждый элемент является числом с плавающей запятой одинарной точности, и
все элементы должны быть конечными (без NaN
,
Infinity
или -Infinity
).
Разреженные векторы могут иметь до 16,000 ненулевых элементов.
F.75.23.13. Операторы Sparsevec #
Оператор | Описание | Добавлено |
---|---|---|
<-> | Евклидово расстояние | 0.7.0 |
<#> | отрицательное скалярное произведение | 0.7.0 |
<=> | косинусное расстояние | 0.7.0 |
<+> | таксистское расстояние | 0.7.0 |
F.75.23.14. Функции Sparsevec #
Функция | Описание | Добавлено |
---|---|---|
cosine_distance(sparsevec, sparsevec) → double precision | косинусное расстояние | 0.7.0 |
inner_product(sparsevec, sparsevec) → double precision | скалярное произведение | 0.7.0 |
l1_distance(sparsevec, sparsevec) → double precision | манхэттенское расстояние | 0.7.0 |
l2_distance(sparsevec, sparsevec) → double precision | Евклидово расстояние | 0.7.0 |
l2_norm(sparsevec) → double precision | Евклидова норма | 0.7.0 |
l2_normalize(sparsevec) → sparsevec | Нормализация с евклидовой нормой | 0.7.0 |
F.75.24. Хостинг Postgres #
pgvector доступен на этих провайдерах.
F.75.25. Обновление #
Установите последнюю версию (используйте тот же метод, что и для первоначальной установки). Затем в каждой базе данных, которую вы хотите обновить, выполните:
ALTER EXTENSION vector UPDATE;
Вы можете проверить версию в текущей базе данных с помощью:
SELECT extversion FROM pg_extension WHERE extname = 'vector';
F.75.26. Спасибо #
Благодарности:
PASE: расширение PostgreSQL для поиска ближайших соседей в ультравысоких размерностях
Faiss: Библиотека для эффективного поиска сходства и кластеризации плотных векторов
Использование неравенства треугольника для ускорения k-средних
Концептуальные разложения для больших разреженных текстовых данных с использованием кластеризации
F.75.27. История #
Просмотрите журнал изменений
F.75.28. Для разработчика #
Каждый может помочь улучшить этот проект. Вот несколько способов, как вы можете помочь:
Исправляйте ошибки и отправляйте запросы на внесение изменений
Написать, уточнить или исправить документацию
Предложить или добавить новые функции
Чтобы начать разработку:
git clone https://github.com/pgvector/pgvector.git cd pgvector make make install
Чтобы запустить все тесты:
make installcheck # regression tests make prove_installcheck # TAP tests
Чтобы запустить отдельные тесты:
make installcheck REGRESS=functions # regression test make prove_installcheck PROVE_TESTS=test/t/001_ivfflat_wal.pl # TAP test
Чтобы включить утверждения:
make clean && PG_CFLAGS="-DUSE_ASSERT_CHECKING" make && make install
Чтобы включить тестирование производительности:
make clean && PG_CFLAGS="-DIVFFLAT_BENCH" make && make install
Чтобы показать использование памяти:
make clean && PG_CFLAGS="-DHNSW_MEMORY -DIVFFLAT_MEMORY" make && make install
Чтобы получить метрики k-средних:
make clean && PG_CFLAGS="-DIVFFLAT_KMEANS_DEBUG" make && make install
Ресурсы для участников