pgvector/pgvector

GitHub: pgvector/pgvector

PostgreSQL 的开源扩展,为关系型数据库添加向量存储与相似度搜索能力。

Stars: 20036 | Forks: 1082

# pgvector Postgres 的开源向量相似度搜索 将您的向量与其余数据一起存储。支持: - 精确和近似最近邻搜索 - 单精度、半精度、二进制和稀疏向量 - L2 距离、内积、余弦距离、L1 距离、汉明距离和 Jaccard 距离 - 任何拥有 Postgres 客户端的[语言](#languages) 此外还具备 [ACID](https://en.wikipedia.org/wiki/ACID) 合规性、时间点恢复、JOINs 以及 Postgres 的所有其他[强大功能](https://www.postgresql.org/about/) [![构建状态](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/5ce37d7d8d181529.svg)](https://github.com/pgvector/pgvector/actions) ## 安装 ### Linux 和 Mac 编译并安装扩展(支持 Postgres 13+) ``` cd /tmp git clone --branch v0.8.2 https://github.com/pgvector/pgvector.git cd pgvector make make install # may need sudo ``` 如果遇到问题,请参阅[安装说明](#installation-notes---linux-and-mac) 您也可以使用 [Docker](#docker)、[Homebrew](#homebrew)、[PGXN](#pgxn)、[APT](#apt)、[Yum](#yum)、[pkg](#pkg)、[APK](#apk) 或 [conda-forge](#conda-forge) 进行安装,并且它已预装在 [Postgres.app](#postgresapp) 和许多[托管提供商](#hosted-postgres)中。此外还有针对 [GitHub Actions](https://github.com/pgvector/setup-pgvector) 的说明。 ### Windows 确保已安装 [Visual Studio 中的 C++ 支持](https://learn.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-170#download-and-install-the-tools),并以管理员身份运行 `x64 Native Tools Command Prompt for VS [version]`。然后使用 `nmake` 进行构建: ``` set "PGROOT=C:\Program Files\PostgreSQL\18" cd %TEMP% git clone --branch v0.8.2 https://github.com/pgvector/pgvector.git cd pgvector nmake /F Makefile.win nmake /F Makefile.win install ``` 如果遇到问题,请参阅[安装说明](#installation-notes---windows) 您也可以使用 [Docker](#docker) 或 [conda-forge](#conda-forge) 进行安装。 ## 入门 启用扩展(在需要使用它的每个数据库中执行一次此操作) ``` 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 距离 (`<+>`) 注意:`<#>` 返回负内积,因为 Postgres 仅支持对操作符进行 `ASC` 顺序索引扫描 ## 存储 创建一个带有向量列的新表 ``` CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3)); ``` 或者将向量列添加到现有表中 ``` ALTER TABLE items ADD COLUMN embedding vector(3); ``` 还支持[半精度](#half-precision-vectors)、[二进制](#binary-vectors)和[稀疏](#sparse-vectors)向量 插入向量 ``` INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]'); ``` 或者使用 `COPY` 批量加载向量([示例](https://github.com/pgvector/pgvector-python/blob/master/examples/loading/example.py)) ``` COPY items (embedding) FROM STDIN WITH (FORMAT BINARY); ``` Upsert 向量 ``` 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; ``` ## 查询 获取向量的最近邻 ``` SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5; ``` 支持的距离函数有: - `<->` - L2 距离 - `<#>` - (负)内积 - `<=>` - 余弦距离 - `<+>` - L1 距离 - `<~>` - 汉明距离(二进制向量) - `<%>` - Jaccard 距离(二进制向量) 获取一行的最近邻 ``` 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; ``` 注意:与 `ORDER BY` 和 `LIMIT` 结合使用以利用索引 #### 距离 获取距离 ``` 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; ``` #### 聚合 平均向量 ``` SELECT AVG(embedding) FROM items; ``` 平均向量组 ``` SELECT category_id, AVG(embedding) FROM items GROUP BY category_id; ``` ## 索引 默认情况下,pgvector 执行精确最近邻搜索,可提供完美的召回率。 您可以添加索引以使用近似最近邻搜索,这会牺牲一些召回率来换取速度。与典型索引不同,添加近似索引后,查询结果会有所不同。 支持的索引类型有: - [HNSW](#hnsw) - [IVFFlat](#ivfflat) ## HNSW HNSW 索引创建一个多层图。与 IVFFlat 相比,它具有更好的查询性能(在速度-召回率权衡方面),但构建时间较慢且使用更多内存。此外,由于没有像 IVFFlat 那样的训练步骤,因此可以在表中没有任何数据的情况下创建索引。 为您想要使用的每个距离函数添加一个索引。 L2 距离 ``` CREATE INDEX ON items USING hnsw (embedding vector_l2_ops); ``` 注意:对 `halfvec` 使用 `halfvec_l2_ops`,对 `sparsevec` 使用 `sparsevec_l2_ops`(其他距离函数类似) 内积 ``` 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); ``` Jaccard 距离 ``` CREATE INDEX ON items USING hnsw (embedding bit_jaccard_ops); ``` 支持的类型有: - `vector` - 最多 2,000 维 - `halfvec` - 最多 4,000 维 - `bit` - 最多 64,000 维 - `sparsevec` - 最多 1,000 个非零元素 ### 索引选项 指定 HNSW 参数 - `m` - 每层的最大连接数(默认为 16) - `ef_construction` - 用于构建图的动态候选列表的大小(默认为 64) ``` CREATE INDEX ON items USING hnsw (embedding vector_l2_ops) WITH (m = 16, ef_construction = 64); ``` 较高的 `ef_construction` 值以索引构建时间/插入速度为代价提供更好的召回率。 ### 查询选项 指定搜索的动态候选列表的大小(默认为 40) ``` SET hnsw.ef_search = 100; ``` 较高的值以速度为代价提供更好的召回率。 在事务中使用 `SET LOCAL` 为单个查询设置它 ``` BEGIN; SET LOCAL hnsw.ef_search = 100; SELECT ... COMMIT; ``` ### 索引构建时间 当图能放入 `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. ``` 注意:不要将 `maintenance_work_mem` 设置得过高,以免耗尽服务器上的内存 与其他索引类型一样,在加载初始数据后创建索引更快 您还可以通过增加并行工作进程的数量(默认为 2)来加快索引创建速度 ``` SET max_parallel_maintenance_workers = 7; -- plus leader ``` 对于大量工作进程,您可能需要增加 `max_parallel_workers`(默认为 8) [索引选项](#index-options)对构建时间也有显著影响(除非看到召回率低,否则使用默认值) ### 索引进度 检查[索引进度](https://www.postgresql.org/docs/current/progress-reporting.html#CREATE-INDEX-PROGRESS-REPORTING) ``` SELECT phase, round(100.0 * blocks_done / nullif(blocks_total, 0), 1) AS "%" FROM pg_stat_progress_create_index; ``` HNSW 的阶段有: 1. `initializing` 2. `loading tuples` ## IVFFlat IVFFlat 索引将向量划分为列表,然后搜索其中最接近查询向量的那些列表的子集。与 HNSW 相比,它的构建时间更快,使用的内存更少,但查询性能较低(在速度-召回率权衡方面)。 实现良好召回率的三个关键是: 1. 在表中有一些数据**之后**创建索引 2. 选择适当数量的列表 - 对于多达 1M 行,一个好的起点是 `rows / 1000`,对于超过 1M 行,是 `sqrt(rows)` 3. 查询时,指定适当数量的 [probes](#query-options)(越高对召回率越好,越低对速度越好) - 一个好的起点是 `sqrt(lists)` 为您想要使用的每个距离函数添加一个索引。 L2 距离 ``` CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 100); ``` 注意:对 `halfvec` 使用 `halfvec_l2_ops`(其他距离函数类似) 内积 ``` 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 维 ### 查询选项 指定 probes 的数量(默认为 1) ``` SET ivfflat.probes = 10; ``` 较高的值以速度为代价提供更好的召回率,并且可以将其设置为列表的数量以进行精确最近邻搜索(此时规划器将不使用索引) 在事务中使用 `SET LOCAL` 为单个查询设置它 ``` BEGIN; SET LOCAL ivfflat.probes = 10; SELECT ... COMMIT; ``` ### 索引构建时间 通过增加并行工作进程的数量(默认为 2)加快大表上的索引创建速度 ``` SET max_parallel_maintenance_workers = 7; -- plus leader ``` 对于大量工作进程,您可能还需要增加 `max_parallel_workers`(默认为 8) ### 索引进度 检查[索引进度](https://www.postgresql.org/docs/current/progress-reporting.html#CREATE-INDEX-PROGRESS-REPORTING) ``` SELECT phase, round(100.0 * tuples_done / nullif(tuples_total, 0), 1) AS "%" FROM pg_stat_progress_create_index; ``` IVFFlat 的阶段有: 1. `initializing` 2. `performing k-means` 3. `assigning tuples` 4. `loading tuples` 注意:`%` 仅在 `loading tuples` 阶段填充 ## 过滤 有几种方法可以为带有 `WHERE` 子句的最近邻查询建立索引。 ``` SELECT * FROM items WHERE category_id = 123 ORDER BY embedding <-> '[3,1,2]' LIMIT 5; ``` 一个好的起点是在过滤列上创建索引。在许多情况下,这可以提供快速、精确的最近邻搜索。Postgres 为此提供了许多[索引类型](https://www.postgresql.org/docs/current/indexes-types.html):B-tree(默认)、hash、GiST、SP-GiST、GIN 和 BRIN。 ``` CREATE INDEX ON items (category_id); ``` 对于多列,请考虑[多列索引](https://www.postgresql.org/docs/current/indexes-multicolumn.html)。 ``` CREATE INDEX ON items (location_id, category_id); ``` 精确索引适用于匹配行比例较低的条件。否则,[近似索引](#indexing)可能效果更好。 ``` 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 开始,您可以启用[迭代索引扫描](#iterative-index-scans),它将在需要时自动扫描更多索引。 ``` SET hnsw.iterative_scan = strict_order; ``` 如果仅按少数不同的值进行过滤,请考虑[部分索引](https://www.postgresql.org/docs/current/indexes-partial.html)。 ``` CREATE INDEX ON items USING hnsw (embedding vector_l2_ops) WHERE (category_id = 123); ``` 如果按许多不同的值进行过滤,请考虑[分区](https://www.postgresql.org/docs/current/ddl-partitioning.html)。 ``` CREATE TABLE items (embedding vector(3), category_id int) PARTITION BY LIST(category_id); ``` ## 迭代索引扫描 对于近似索引,由于过滤是在扫描索引**之后**应用的,因此带有过滤的查询可能返回较少的结果。从 0.8.0 开始,您可以启用迭代索引扫描,这将自动扫描更多索引,直到找到足够的结果(或达到 `hnsw.max_scan_tuples` 或 `ivfflat.max_probes`)。 迭代扫描可以使用严格或宽松的排序。 严格确保结果完全按距离排序 ``` SET hnsw.iterative_scan = strict_order; ``` 宽松允许结果在距离上略有乱序,但提供更好的召回率 ``` SET hnsw.iterative_scan = relaxed_order; # 或 SET ivfflat.iterative_scan = relaxed_order; ``` 对于宽松排序,您可以使用[物化 CTE](https://www.postgresql.org/docs/current/queries-with.html#QUERIES-WITH-CTE-MATERIALIZATION)来获得严格排序 ``` 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 + 0; ``` 注意:Postgres 17+ 需要 `+ 0` 对于按距离过滤的查询,请使用物化 CTE 并将距离过滤器放在其外部以获得最佳性能(由于 Postgres 执行器的[当前行为](https://www.postgresql.org/message-id/flat/CAOdR5yGUoMQ6j7M5hNUXrySzaqZVGf_Ne%2B8fwZMRKTFxU1nbJg%40mail.gmail.com)) ``` 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 内部 ### 迭代扫描选项 由于扫描近似索引的大部分内容成本很高,因此有一些选项可以控制扫描何时结束。 #### HNSW 指定要访问的最大元组数(默认为 20,000) ``` SET hnsw.max_scan_tuples = 20000; ``` 注意:这是近似值,不会影响初始扫描 指定要使用的最大内存量,作为 `work_mem` 的倍数(默认为 1) ``` SET hnsw.scan_mem_multiplier = 2; ``` 注意:如果增加 `hnsw.max_scan_tuples` 不能提高召回率,请尝试增加此值 #### IVFFlat 指定 probes 的最大数量 ``` SET ivfflat.max_probes = 100; ``` 注意:如果此值低于 `ivfflat.probes`,将使用 `ivfflat.probes` ## 半精度向量 使用 `halfvec` 类型存储半精度向量 ``` CREATE TABLE items (id bigserial PRIMARY KEY, embedding halfvec(3)); ``` ## 半精度索引 以半精度索引向量以获得更小的索引 ``` 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; ``` ## 二进制向量 使用 `bit` 类型存储二进制向量([示例](https://github.com/pgvector/pgvector-python/blob/master/examples/imagehash/example.py)) ``` 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; ``` 还支持 Jaccard 距离 (`<%>`) ## 二进制量化 使用表达式索引进行二进制量化 ``` 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; ``` ## 稀疏向量 使用 `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'); ``` 格式为 `{index1:value1,index2:value2}/dimensions`,索引从 1 开始,类似于 SQL 数组 通过 L2 距离获取最近邻 ``` SELECT * FROM items ORDER BY embedding <-> '{1:3,3:1,5:2}/5' LIMIT 5; ``` ## 混合搜索 与 Postgres [全文搜索]( 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; ``` ## 性能 ### 调优 使用 [PgTune](https://pgtune.leopard.in.ua/) 等工具设置 Postgres 服务器参数的初始值。例如,`shared_buffers` 通常应为服务器内存的 25%。您可以使用以下命令找到配置文件: ``` SHOW config_file; ``` 并使用以下命令检查各个设置: ``` SHOW shared_buffers; ``` 请务必重启 Postgres 以使更改生效。 ### 加载 使用 `COPY` 批量加载数据([示例](https://github.com/pgvector/pgvector-python/blob/master/examples/loading/example.py))。 ``` COPY items (embedding) FROM STDIN WITH (FORMAT BINARY); ``` 在加载初始数据**之后**添加任何索引以获得最佳性能。 ### 索引 请参阅 [HNSW](#index-build-time) 和 [IVFFlat](#index-build-time-1) 的索引构建时间。 在生产环境中,并发创建索引以避免阻塞写入。 ``` CREATE INDEX CONCURRENTLY ... ``` ### 查询 使用 `EXPLAIN (ANALYZE, BUFFERS)` 调试性能。 ``` EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5; ``` #### 精确搜索 要在没有索引的情况下加速查询,请增加 `max_parallel_workers_per_gather`。 ``` SET max_parallel_workers_per_gather = 4; ``` 如果向量被归一化为长度 1(如 [OpenAI embeddings](https://platform.openai.com/docs/guides/embeddings/which-distance-function-should-i-use)),请使用内积以获得最佳性能。 ``` SELECT * FROM items ORDER BY embedding <#> '[3,1,2]' LIMIT 5; ``` #### 近似搜索 要使用 IVFFlat 索引加速查询,请增加倒排列表的数量(以牺牲召回率为代价)。 ``` CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 1000); ``` ### 清理 (Vacuuming) HNSW 索引的清理可能需要一段时间。首先通过重新索引来加快速度。 ``` REINDEX INDEX CONCURRENTLY index_name; VACUUM table_name; ``` ## 监控 使用 [pg_stat_statements](https://www.postgresql.org/docs/current/pgstatstatements.html) 监控性能(务必将其添加到 `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; ``` 通过比较近似搜索与精确搜索的结果来监控召回率。 ``` BEGIN; SET LOCAL enable_indexscan = off; -- use exact search SELECT ... COMMIT; ``` ## 扩展 以与扩展 Postgres 相同的方式扩展 pgvector。 通过增加单个实例上的内存、CPU 和存储进行垂直扩展。使用现有工具来[调整参数](#tuning)和[监控性能](#monitoring)。 通过[副本](https://www.postgresql.org/docs/current/hot-standby.html)进行水平扩展,或使用 [Citus](https://github.com/citusdata/citus) 或其他方法进行分片([示例](https://github.com/pgvector/pgvector-python/blob/master/examples/citus/example.py))。 ## 语言 从任何拥有 Postgres 客户端的语言使用 pgvector。您甚至可以用一种语言生成和存储向量,然后用另一种语言查询它们。 语言 | 库 / 示例 --- | --- Ada | [pgvector-ada](https://github.com/pgvector/pgvector-ada) Algol | [pgvector-algol](https://github.com/pgvector/pgvector-algol) C | [pgvector-c](https://github.com/pgvector/pgvector-c) C++ | [pgvector-cpp](https://github.com/pgvector/pgvector-cpp) C#, F#, Visual Basic | [pgvector-dotnet](https://github.com/pgvector/pgvector-dotnet) COBOL | [pgvector-cobol](https://github.com/pgvector/pgvector-cobol) Crystal | [pgvector-crystal](https://github.com/pgvector/pgvector-crystal) D | [pgvector-d](https://github.com/pgvector/pgvector-d) Dart | [pgvector-dart](https://github.com/pgvector/pgvector-dart) Elixir | [pgvector-elixir](https://github.com/pgvector/pgvector-elixir) Erlang | [pgvector-erlang](https://github.com/pgvector/pgvector-erlang) Fortran | [pgvector-fortran](https://github.com/pgvector/pgvector-fortran) Gleam | [pgvector-gleam](https://github.com/pgvector/pgvector-gleam) Go | [pgvector-go](https://github.com/pgvector/pgvector-go) Haskell | [pgvector-haskell](https://github.com/pgvector/pgvector-haskell) Java, Kotlin, Groovy, Scala | [pgvector-java](https://github.com/pgvector/pgvector-java) JavaScript, TypeScript | [pgvector-node](https://github.com/pgvector/pgvector-node) Julia | [Pgvector.jl](https://github.com/pgvector/Pgvector.jl) Lisp | [pgvector-lisp](https://github.com/pgvector/pgvector-lisp) Lua | [pgvector-lua](https://github.com/pgvector/pgvector-lua) Nim | [pgvector-nim](https://github.com/pgvector/pgvector-nim) OCaml | [pgvector-ocaml](https://github.com/pgvector/pgvector-ocaml) Pascal | [pgvector-pascal](https://github.com/pgvector/pgvector-pascal) Perl | [pgvector-perl](https://github.com/pgvector/pgvector-perl) PHP | [pgvector-php](https://github.com/pgvector/pgvector-php) Prolog | [pgvector-prolog](https://github.com/pgvector/pgvector-prolog) Python | [pgvector-python](https://github.com/pgvector/pgvector-python) R | [pgvector-r](https://github.com/pgvector/pgvector-r) Racket | [pgvector-racket](https://github.com/pgvector/pgvector-racket) Raku | [pgvector-raku](https://github.com/pgvector/pgvector-raku) Ruby | [pgvector-ruby](https://github.com/pgvector/pgvector-ruby), [Neighbor](https://github.com/ankane/neighbor) Rust | [pgvector-rust](https://github.com/pgvector/pgvector-rust) Swift | [pgvector-swift](https://github.com/pgvector/pgvector-swift) Tcl | [pgvector-tcl](https://github.com/pgvector/pgvector-tcl) Zig | [pgvector-zig](https://github.com/pgvector/pgvector-zig) ## 常见问题 #### 单个表中可以存储多少个向量? 在 Postgres 中,非分区表默认限制为 32 TB。分区表可以拥有数千个该大小的分区。 #### 是否支持复制? 是的,pgvector 使用预写日志 (WAL),这允许复制和时间点恢复。 #### 如果我想索引超过 2,000 维的向量怎么办? 您可以使用[半精度向量](#half-precision-vectors)或[半精度索引](#half-precision-indexing)来索引最多 4,000 维,或使用[二进制量化](#binary-quantization)来索引最多 64,000 维。其他选项是[索引子向量](#indexing-subvectors)(适用于支持它的模型)或[降维](https://en.wikipedia.org/wiki/Dimensionality_reduction)。 #### 我可以在同一列中存储不同维度的向量吗? 您可以使用 `vector` 作为类型(而不是 `vector(n)`)。 ``` CREATE TABLE embeddings (model_id bigint, item_id bigint, embedding vector, PRIMARY KEY (model_id, item_id)); ``` 但是,您只能在具有相同维度的行上创建索引(使用[表达式](https://www.postgresql.org/docs/current/indexes-expressional.html)和[部分](https://www.postgresql.org/docs/current/indexes-partial.html)索引): ``` 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; ``` #### 我可以存储更高精度的向量吗? 您可以使用 `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}'); ``` 或者,添加一个[检查约束](https://www.postgresql.org/docs/current/ddl-constraints.html)以确保数据可以转换为 `vector` 类型并具有预期的维度。 ``` ALTER TABLE items ADD CHECK (vector_dims(embedding::vector) = 3); ``` 使用[表达式索引](https://www.postgresql.org/docs/current/indexes-expressional.html)进行索引(以较低精度): ``` 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; ``` #### 索引需要放入内存吗? 不需要,但与其他索引类型一样,如果放入内存,您可能会看到更好的性能。您可以使用以下命令获取索引的大小: ``` SELECT pg_size_pretty(pg_relation_size('index_name')); ``` ## 故障排除 #### 为什么查询没有使用索引? 查询需要有 `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; ``` 此外,如果表很小,表扫描可能会更快。 #### 为什么查询没有使用并行表扫描? 规划器在成本估算中不考虑[非行内存储](https://www.postgresql.org/docs/current/storage-toast.html),这可能使串行扫描看起来更便宜。您可以使用以下命令降低查询的并行扫描成本: ``` 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; ``` #### 添加 HNSW 索引后查询结果为什么变少了? 结果受动态候选列表(`hnsw.ef_search`)大小的限制,默认为 40。由于死元组或查询中的过滤条件,结果可能更少。启用[迭代索引扫描](#iterative-index-scans)有助于解决此问题。 此外,请注意 `NULL` 向量不会被索引(余弦距离的零向量也不会)。 #### 添加 IVFFlat 索引后查询结果为什么变少了? 索引可能是在数据对于列表数量来说太少的情况下创建的。在表有更多数据之前删除索引。 ``` DROP INDEX index_name; ``` 结果也可能受 probes 数量(`ivfflat.probes`)的限制。启用[迭代索引扫描](#iterative-index-scans)可以解决此问题。 此外,请注意 `NULL` 向量不会被索引(余弦距离的零向量也不会)。 ## 参考 - [Vector](#vector-type) - [Halfvec](#halfvec-type) - [Bit](#bit-type) - [Sparsevec](#sparsevec-type) ### Vector 类型 每个向量占用 `4 * dimensions + 8` 字节的存储空间。每个元素是一个单精度浮点数(如 Postgres 中的 `real` 类型),并且所有元素必须是有限的(无 `NaN`、`Infinity` 或 `-Infinity`)。向量最多可以有 16,000 维。 ### Vector 操作符 操作符 | 描述 | 添加 --- | --- | --- \+ | 逐元素加法 | \- | 逐元素减法 | \* | 逐元素乘法 | 0.5.0 \|\| | 连接 | 0.7.0 <-> | 欧几里得距离 | <#> | 负内积 | <=> | 余弦距离 | <+> | 出租车距离 | 0.7.0 ### Vector 函数 函数 | 描述 | 添加 --- | --- | --- binary_quantize(vector) → bit | 二进制量化 | 0.7.0 cosine_distance(vector, vector) → double precision | 余弦距离 | inner_product(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) → vector | 子向量 | 0.7.0 vector_dims(vector) → integer | 维度数 | vector_norm(vector) → double precision | 欧几里得范数 | ### Vector 聚合函数 函数 | 描述 | 添加 --- | --- | --- avg(vector) → vector | 平均值 | sum(vector) → vector | 和 | 0.5.0 ### Halfvec 类型 每个半精度向量占用 `2 * dimensions + 8` 字节的存储空间。每个元素是一个半精度浮点数,并且所有元素必须是有限的(无 `NaN`、`Infinity` 或 `-Infinity`)。半精度向量最多可以有 16,000 维。 ### 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 ### Halfvec 函数 函数 | 描述 | 添加 --- | --- | --- binary_quantize(halfvec) → bit | 二进制量化 | 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 ### Halfvec 聚合函数 函数 | 描述 | 添加 --- | --- | --- avg(halfvec) → halfvec | 平均值 | 0.7.0 sum(halfvec) → halfvec | 和 | 0.7.0 ### Bit 类型 每个位向量占用 `dimensions / 8 + 8` 字节的存储空间。有关更多信息,请参阅 [Postgres 文档](https://www.postgresql.org/docs/current/datatype-bit.html)。 ### Bit 操作符 操作符 | 描述 | 添加 --- | --- | --- <~ | 汉明距离 | 0.7.0 <%> | Jaccard 距离 | 0.7.0 ### Bit 函数 函数 | 描述 | 添加 --- | --- | --- hamming_distance(bit, bit) → double precision | 汉明距离 | 0.7.0 jaccard_distance(bit, bit) → double precision | Jaccard 距离 | 0.7.0 ### Sparsevec 类型 每个稀疏向量占用 `8 * non-zero elements + 16` 字节的存储空间。每个元素是一个单精度浮点数,并且所有元素必须是有限的(无 `NaN`、`Infinity` 或 `-Infinity`)。稀疏向量最多可以有 16,000 个非零元素。 ### Sparsevec 操作符 操作符 | 描述 | 添加 --- | --- | --- <-> | 欧几里得距离 | 0.7.0 <#> | 负内积 | 0.7.0 <=> | 余弦距离 | 0.7.0 <+> | 出租车距离 | 0.7.0 ### 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 ## 安装说明 - Linux 和 Mac ### Postgres 位置 如果您的机器有多个 Postgres 安装,请使用以下命令指定 [pg_config](https://www.postgresql.org/docs/current/app-pgconfig.html) 的路径: ``` export PG_CONFIG=/Library/PostgreSQL/18/bin/pg_config ``` 然后重新运行安装说明(如有必要,在 `make` 之前运行 `make clean`)。如果 `make install` 需要 `sudo`,请使用: ``` sudo --preserve-env=PG_CONFIG make install ``` Mac 上的一些常见路径是: - EDB 安装程序 - `/Library/PostgreSQL/18/bin/pg_config` - Homebrew (arm64) - `/opt/homebrew/opt/postgresql@18/bin/pg_config` - Homebrew (x86-64) - `/usr/local/opt/postgresql@18/bin/pg_config` 注意:将 `18` 替换为您的 Postgres 服务器版本 ### 缺少头文件 如果编译失败并显示 `fatal error: postgres.h: No such file or directory`,请确保服务器上已安装 Postgres 开发文件。 对于 Ubuntu 和 Debian,请使用: ``` sudo apt install postgresql-server-dev-18 ``` 注意:将 `18` 替换为您的 Postgres 服务器版本 ### 缺少 SDK 如果编译失败并且输出在 Mac 上包含 `warning: no such sysroot directory`,则您的 Postgres 安装指向一个不再存在的路径。 ``` pg_config --cppflags ``` 重新安装 Postgres 以解决此问题。 ### 可移植性 默认情况下,pgvector 在某些平台上使用 `-march=native` 编译以获得最佳性能。但是,如果尝试在另一台机器上运行编译后的扩展,这可能会导致 `Illegal instruction` 错误。 要编译以便移植,请使用: ``` make OPTFLAGS="" ``` ## 安装说明 - Windows ### 缺少头文件 如果编译失败并显示 `Cannot open include file: 'postgres.h': No such file or directory`,请确保 `PGROOT` 正确。 ### 架构不匹配 如果编译失败并显示 `error C2196: case value '4' already used`,请确保您使用的是 `x64 Native Tools Command Prompt`。然后运行 `nmake /F Makefile.win clean` 并重新运行安装说明。 ### 缺少符号 如果链接失败并在 Postgres 17.0-17.2 中显示 `unresolved external symbol float_to_shortest_decimal_bufn`,请升级到 Postgres 17.3+。 ### 权限 如果安装失败并显示 `Access is denied`,请以管理员身份重新运行安装说明。 ## 其他安装方法 ### Docker 使用以下命令获取 [Docker 镜像](https://hub.docker.com/r/pgvector/pgvector): ``` docker pull pgvector/pgvector:pg18-trixie ``` 这会将 pgvector 添加到 [Postgres 镜像](https://hub.docker.com/_/postgres)(将 `18` 替换为您的 Postgres 服务器版本,并以相同方式运行它)。 支持的标签有: - `pg18-trixie`, `0.8.2-pg18-trixie` - `pg18-bookworm`, `0.8.2-pg18-bookworm`, `pg18`, `0.8.2-pg18` - `pg17-trixie`, `0.8.2-pg17-trixie` - `pg17-bookworm`, `0.8.2-pg17-bookworm`, `pg17`, `0.8.2-pg17` - `pg16-trixie`, `0.8.2-pg16-trixie` - `pg16-bookworm`, `0.8.2-pg16-bookworm`, `pg16`, `0.8.2-pg16` - `pg15-trixie`, `0.8.2-pg15-trixie` - `pg15-bookworm`, `0.8.2-pg15-bookworm`, `pg15`, `0.8.2-pg15` - `pg14-trixie`, `0.8.2-pg14-trixie` - `pg14-bookworm`, `0.8.2-pg14-bookworm`, `pg14`, `0.8.2-pg14` - `pg13-trixie`, `0.8.2-pg13-trixie` - `pg13-bookworm`, `0.8.2-pg13-bookworm`, `pg13`, `0.8.2-pg13` 您也可以手动构建镜像: ``` git clone --branch v0.8.2 https://github.com/pgvector/pgvector.git cd pgvector docker build --pull --build-arg PG_MAJOR=18 -t myuser/pgvector . ``` 如果增加 `maintenance_work_mem`,请确保 `--shm-size` 至少是该大小,以避免并行 HNSW 索引构建出错。 ``` docker run --shm-size=1g ... ``` ### Homebrew 对于 Homebrew Postgres,您可以使用: ``` brew install pgvector ``` 注意:这只会将其添加到 `postgresql@18` 和 `postgresql@17` formulas ### PGXN 从 [PostgreSQL Extension Network](https://pgxn.org/dist/vector) 安装: ``` pgxn install vector ``` ### APT Debian 和 Ubuntu 软件包可从 [PostgreSQL APT Repository](https://wiki.postgresql.org/wiki/Apt) 获取。按照[设置说明](https://wiki.postgresql.org/wiki/Apt#Quickstart)操作并运行: ``` sudo apt install postgresql-18-pgvector ``` 注意:将 `18` 替换为您的 Postgres 服务器版本 ### Yum RPM 软件包可从 [PostgreSQL Yum Repository](https://yum.postgresql.org/) 获取。按照您的发行版的[设置说明](https://www.postgresql.org/download/linux/redhat/)操作并运行: ``` sudo yum install pgvector_18 # 或 sudo dnf install pgvector_18 ``` 注意:将 `18` 替换为您的 Postgres 服务器版本 ### pkg 使用以下命令安装 FreeBSD 软件包: ``` pkg install postgresql17-pgvector ``` 或使用以下命令安装 port: ``` cd /usr/ports/databases/pgvector make install ``` ### APK 使用以下命令安装 Alpine 软件包: ``` apk add postgresql-pgvector ``` ### conda-forge 对于 Conda Postgres,从 [conda-forge](https://anaconda.org/conda-forge/pgvector) 安装: ``` conda install -c conda-forge pgvector ``` 此方法由 [@mmcauliffe](https://github.com/mmcauliffe) 进行[社区维护](https://github.com/conda-forge/pgvector-feedstock) ### Postgres.app 下载包含 Postgres 15+ 的[最新版本](https://postgresapp.com/downloads.html)。 ## 托管 Postgres pgvector 可在[这些提供商](https://github.com/pgvector/pgvector/issues/54)上使用。 ## 升级 [安装](#installation)最新版本(使用与原始安装相同的方法)。然后在要升级的每个数据库中运行: ``` ALTER EXTENSION vector UPDATE; ``` 您可以使用以下命令检查当前数据库中的版本: ``` SELECT extversion FROM pg_extension WHERE extname = 'vector'; ``` ## 致谢 感谢: - [PASE: PostgreSQL Ultra-High-Dimensional Approximate Nearest Neighbor Search Extension](https://dl.acm.org/doi/pdf/10.1145/3318464.3386131) - [Faiss: A Library for Efficient Similarity Search and Clustering of Dense Vectors](https://github.com/facebookresearch/faiss) - [Using the Triangle Inequality to Accelerate k-means](https://cdn.aaai.org/ICML/2003/ICML03-022.pdf) - [k-means++: The Advantage of Careful Seeding](https://theory.stanford.edu/~sergei/papers/kMeansPP-soda.pdf) - [Concept Decompositions for Large Sparse Text Data using Clustering](https://www.cs.utexas.edu/users/inderjit/public_papers/concept_mlj.pdf) - [Efficient and Robust Approximate Nearest Neighbor Search using Hierarchical Navigable Small World Graphs](https://arxiv.org/ftp/arxiv/papers/1603/1603.09320.pdf) ## 历史 查看[更新日志](https://github.com/pgvector/pgvector/blob/master/CHANGELOG.md) ## 贡献 鼓励大家帮助改进这个项目。您可以通过以下几种方式提供帮助: - [报告错误](https://github.com/pgvector/pgvector/issues) - 修复错误并[提交 pull requests](https://github.com/pgvector/pgvector/pulls) - 编写、阐明或修复文档 - 建议或添加新功能 要开始开发: ``` 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-means 指标: ``` make clean && PG_CFLAGS="-DIVFFLAT_KMEANS_DEBUG" make && make install ``` 贡献者资源 - [Extension Building Infrastructure](https://www.postgresql.org/docs/current/extend-pgxs.html) - [Index Access Method Interface Definition](https://www.postgresql.org/docs/current/indexam.html) - [Generic WAL Records](https://www.postgresql.org/docs/current/generic-wal.html)
标签:AI 应用开发, ANN, Apex, Embedding, pgvector, PostgreSQL, Postgres 扩展, RAG, SQL, 余弦相似度, 向量搜索, 向量数据库, 向量检索, 多线程, 大模型, 客户端加密, 客户端加密, 开源扩展, 数据库增强, 数据库插件, 机器学习, 检索增强生成, 测试用例, 深度学习基础设施, 生成式 AI, 相似性搜索, 系统审计, 语义搜索, 距离计算, 高维向量