pgvector 快速上手:在 PostgreSQL 里存向量、建索引、跑相似查询
【免费下载链接】pgvectorOpen-source vector similarity search for Postgres项目地址: https://gitcode.com/GitHub_Trending/pg/pgvector
如果你已经用 PostgreSQL 存业务数据,现在又想让模型产出的 embedding 也放进同一个库里、并能按"相似度"取最近邻,pgvector 就是为此而生的扩展。它给 Postgres 加了一个向量数据类型,再配上 HNSW、IVFFlat 两种索引,让你用普通 SQL 完成插入、过滤和最近邻查询,不需要单独维护一套向量数据库。
项目定位:它是什么,适合谁
pgvector 是一个开源的 PostgreSQL 扩展,当前默认版本 0.8.6,支持 Postgres 13 及以上。它的价值可以概括为三点:
- 数据不搬家:向量列和业务字段(如用户 ID、分类、时间戳)在同一张表里,JOIN、事务、权限控制都能照常使用。
- 查询方式不变:最近邻查询就是一句
ORDER BY 距离 LIMIT n,任何会写 SQL 的语言(Python、Java、Go 等)都能直接驱动。 - 精度可调:不加索引时是精确搜索,加了近似索引后在速度上换来一定的召回率损失,中间还有余量可以调。
它也不适合所有场景:如果你的数据量是几亿级别、且对写入吞吐和分布式扩展要求极高,单独的向量数据库可能更合适;pgvector 的舒适区大致在"几十万到几千万条向量、单机或主从 Postgres 能装下"的规模。
最小上手路径:从建库到第一次查询
前置条件:一台已装好 PostgreSQL 13+ 的机器(Linux、macOS 或 Windows 均可)。
第 1 步:拿到源码并编译安装。Linux/macOS 下只需三条命令,需要本地有git、make和 Postgres 开发头文件:
git clone --branch v0.8.6 https://gitcode.com/GitHub_Trending/pg/pgvector cd pgvector && make && make installWindows 用户则用 Visual Studio 的x64 Native Tools Command Prompt,设置好PGROOT后执行nmake /F Makefile.win和nmake /F Makefile.win install,仓库里已附带Makefile.win。
第 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]'); SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;如果第二条查询返回的两行中,[4,5,6]排在[1,2,3]前面,说明距离计算和排序都正常,扩展已经跑通。
核心用法拆解
用法一:按不同相似度选对距离算子
目的:模型输出的 embedding 各有特性,选错距离会让"相似"的含义跑偏。
pgvector 提供六种距离算子,最常用的是前三个:
| 算子 | 含义 | 适用场景 |
|---|---|---|
<-> | L2 距离(欧氏距离) | 通用默认选择 |
<#> | 负内积 | 检索相关性,值越小越相似 |
<=> | 余弦距离 | 只关心方向、不关心幅度的场景,如文本 embedding |
关键步骤:距离只写在ORDER BY里即可生效,无需建索引:
-- 余弦相似度(取值 0~1,越大越相似) SELECT id, 1 - (embedding <=> '[3,1,2]') AS sim FROM items ORDER BY embedding <=> '[3,1,2]' LIMIT 5;判断标准:用EXPLAIN看执行计划,出现Seq Scan且结果集可接受,就没问题;如果表已经很大、查询变慢,再进入用法二建索引。另注意<#>返回的是负内积,要展示相似度时记得乘 -1。
用法二:为最近邻查询建索引
目的:表里的向量多了以后,逐行算距离会拖慢查询,索引的作用就是让查询从"全表扫描"变成"只扫一小片"。
HNSW 与 IVFFlat 怎么选:
- HNSW:建索引不需要表里有数据,查询速度快、召回率相对更好;代价是构建慢、占内存多。适合查询 QPS 高的在线服务。
- IVFFlat:构建快、省内存,但建索引前必须先灌入一批数据(它内部要做聚类),且查询时靠
probes参数调召回率。适合数据量大、查询压力中等、内存紧张的情况。
关键步骤:以最常用的 L2 距离为例,两种索引各一条命令:
-- HNSW:空表也能建 CREATE INDEX ON items USING hnsw (embedding vector_l2_ops); -- IVFFlat:建之前表里要有数据,lists 参考值 = 行数/1000(百万行以内) CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 100);注意每个距离算子对应一个独立的索引:如果你既按<->查、又按<=>查,需要分别建vector_l2_ops和vector_cosine_ops的索引。
判断标准:
- 用
EXPLAIN (ANALYZE, BUFFERS)确认走了索引(HNSW 显示Index Scan using ...,IVFFlat 显示IVFFlat节点)。 - 近似索引会导致同一条查询结果随时间变化(和 B-tree 索引行为不同),上线前心里要有数。
- IVFFlat 想提高召回率,把
ivfflat.probes从默认 1 调大(如 10),代价是变慢;HNSW 则调hnsw.ef_search(默认 40)。
用法三:带过滤条件的向量查询
目的:真实业务几乎总是"在某个分类/时间范围内找最相似的 N 条",而不是无条件搜索。
关键步骤:假设查询长这样——
SELECT * FROM items WHERE category_id = 123 ORDER BY embedding <-> '[3,1,2]' LIMIT 5;处理思路按优先级排:
- 先给过滤列建普通 B-tree 索引:
CREATE INDEX ON items (category_id);当过滤条件命中行数很少时,Postgres 会先用 B-tree 缩出小集合再做精确距离计算,又快又准,这是最省事的方案。 - 过滤命中比例高时改用近似索引 + 迭代扫描:HNSW 默认只扫描 40 个候选,若过滤条件只放行 10% 的行,平均剩 4 条,可能不够填满
LIMIT。开启迭代扫描可让索引自动多扫一些:
SET hnsw.iterative_scan = strict_order;- 取值很少的过滤条件用部分索引:比如
category_id只有 3 种值,可以给每个值建一个WHERE (category_id = ...)的部分索引,把索引体积拆小。
判断标准:过滤后仍能稳定返回LIMIT要求的条数,且EXPLAIN显示先用 B-tree(或部分 HNSW)缩小范围,再用向量索引排序,就是理想形态。
常见坑与建议
现象 1:装了扩展,但vector类型不存在。可能原因:CREATE EXTENSION vector只在某一个数据库执行过,而你现在连的是另一个库——Postgres 的扩展是按库生效的。 处理:在目标库里补执行一次CREATE EXTENSION vector;;用SELECT extversion FROM pg_extension WHERE extname = 'vector';验证当前库是否已装、版本多少。
现象 2:加了 HNSW 索引,但执行计划还是全表扫描。可能原因:ORDER BY里的距离算子和索引上声明的ops对不上(比如索引建的是vector_cosine_ops,查询却用了<->),或者查询里没有LIMIT。 处理:让算子和ops一一对应;同时确认查询形态是"距离排序 + LIMIT",否则优化器会认为全表扫描更划算。
现象 3:IVFFlat 建好索引后,召回率明显偏低。可能原因:建索引时表里数据太少,聚类中心不准;或者probes停在默认值 1,只查了 1/100 的列表。 处理:数据积累到接近真实规模后重建索引,把lists按行数重新估一遍;查询侧把ivfflat.probes提到sqrt(lists)附近再观察召回率与耗时的平衡点。
现象 4:大表建 HNSW 索引特别慢。可能原因:图结构装不进maintenance_work_mem,构建过程反复落盘。构建时 Postgres 会打印hnsw graph no longer fits into maintenance_work_mem的 NOTICE,这就是信号。 处理:临时调大该参数(如SET maintenance_work_mem = '8GB';),同时可把max_parallel_maintenance_workers从默认 2 往上加。注意别让这两个参数把机器内存吃光,构建完记得改回去。
延伸与收尾
跑通最小路径之后,仓库里有几块内容值得按顺序看:
sql/vector.sql:扩展的完整 DDL,向量类型、算子和两种访问方法都在这里注册,适合想理解"扩展到底往库里装了什么"的读者。src/hnswbuild.c、src/ivfflat.c等源码文件:如果调参调不出理想召回率,可以从这里看构建和扫描逻辑;src/hnswvacuum.c则解释了索引如何跟随 VACUUM 收缩。test/t/目录下的回归测试:文件名本身就是一份实验清单,如043_hnsw_iterative_scan.pl演示迭代扫描、045_hnsw_low_memory_build.pl演示低内存构建,照着这些场景做一轮压测,比凭空猜参数有效得多。- 半精度与二进制向量:
halfvec能把存储和内存占用砍半,bit类型配汉明距离适合做粗排初筛,等向量规模上去以后可以回来再看这两个方向。
【免费下载链接】pgvectorOpen-source vector similarity search for Postgres项目地址: https://gitcode.com/GitHub_Trending/pg/pgvector
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考