F.75. вектор (pgvector)#

F.75. вектор (pgvector)

F.75. вектор (pgvector) #

Открытый поиск векторного сходства для Postgres.

Храните ваши векторы вместе с остальными данными. Поддерживает:

  • точный и приближённый поиск ближайших соседей

  • одинарной точности, половинной точности, двоичные и разреженные векторы

  • L2 расстояние, скалярное произведение, косинусное расстояние, L1 расстояние, Хэммингово расстояние и расстояние Жаккара

  • любой язык с клиентом Postgres

Плюс соответствие ACID, восстановление на определенный момент времени, JOINs и все другие отличные возможности Postgres

F.75.1. О векторе #

Version: 0.8.0

GitHub

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 следующие:

  1. initializing

  2. загрузка кортежей

F.75.7. IVFFlat #

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

Три ключа к достижению хорошего запоминания:

  1. Создайте индекс после того, как в таблице появятся данные

  2. Выберите подходящее количество списков - хорошей отправной точкой является строки / 1000 для до 1M строк и sqrt(строк) для более 1M строк

  3. При выполнении запроса укажите соответствующее количество проб (большее количество лучше для полноты, меньшее - для скорости) - хорошей отправной точкой является 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:

  1. initializing

  2. выполнение k-means

  3. присвоение кортежей

  4. загрузка кортежей

Примечание: % заполняется только во время фазы загрузки кортежей

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.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.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.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

Ресурсы для участников