pg_vectorsearch:Timescale 的 PRISM 索引声称比 pgvector IVFFlat 和 HNSW 更快
Timescale 发布了 pg_vectorsearch,这是一个开源的 PostgreSQL 扩展,提供了一种名为 PRISM 的新近似最近邻索引,该项目声称在查询和索引构建方面都明显快于 pgvector 的 IVFFlat 和 HNSW。该扩展明确标注为 alpha 版本,仅供测试而非生产使用,但它引入了一种独特的架构选择:分区和压缩,而非 HNSW 的图遍历。
pg_vectorsearch 是什么
pg_vectorsearch 是一个用于高性能近似最近邻(ANN)搜索的 PostgreSQL 扩展,由 Timescale 在 PostgreSQL 许可证下发布。其核心组件是 PRISM(Partitioned Routing Index for Similarity Matching),一种用 C 语言实现的 PostgreSQL 原生索引访问方法。
该扩展声称的功能包括:
- PRISM 索引 用于 100M+ 向量——IVF 风格,具有分层路由
- RaBitQ 量化,具有两阶段搜索的理论误差界
- SIMD 优化的距离计算(AVX2、AVX512、NEON)
- 动态更新——插入、更新和删除,支持通过
prism_rebalance进行 posting list 拆分 - pgvector 兼容性——可以直接索引现有的
vector和halfvec列
仓库带有明显的状态警告:“状态:alpha。仅供测试,不用于生产。预发布版本之间可能无法升级;计划删除并重新创建扩展及其索引。”
PRISM 索引的工作原理
PRISM 在概念上类似于 pgvector 的 IVFFlat,但将 IVFFlat 的扁平质心列表替换为分层质心树,并添加了基于量化的过滤。Timescale 将结果描述为“一个在查询和索引构建方面都明显快于 pgvector 的 IVFFlat 和 HNSW 的索引。”
该索引使用分层质心树将向量分区到簇中,并依赖 PostgreSQL 缓冲区缓存将质心树保持在内存中。向量经过 RaBitQ 量化后存储在 posting list 中,页面布局针对 SIMD 距离计算进行了优化。RaBitQ 编码带有误差界,搜索时可以排除不可能成为最近邻的向量,因此需要针对表中存储的全精度值进行重新排序的向量数量大大减少。
文档中的查询流程如下:
查询流程:
1. 遍历质心树找到最近的簇(缓冲区缓存)
2. 扫描 posting list 以获取候选向量(缓冲区缓存,异步 I/O)
3. RaBitQ 两阶段过滤:估计 → 误差界 → 重新排序
4. 从堆中进行全精度重新排序
5. 返回 k 个最近邻
该项目引用了 RaBitQ(SIGMOD 2024)、SPFresh 的 LIRE 协议(SOSP 2023)、SPANN(NeurIPS 2021)和 Google 的 ScaNN for AlloyDB 白皮书作为其研究基础。
性能声明
Timescale 随附的公告博客文章提出了具体的基准测试声明。该扩展的作者 jascha_eng 在 Hacker News 上引用了这篇文章的摘要:
TLDR:我们正在发布 pg_vectorsearch,这是一个新的开源 PostgreSQL 扩展,使向量搜索变得更快、更具成本效益。其新的 PRISM 索引使用分区和压缩,而不是 HNSW 的基于图的方法,以更少的内存和显著更快的索引构建提供更快的查询。在 1 亿个向量时,PRISM 在一台内存比 HNSW 少 4 倍的机器上实现了 6 毫秒的查询延迟,索引构建速度快 20 倍以上。
GitHub README 指出,“与基于图的 HNSW 相比,PRISM 在 1 亿向量数据集上、内存仅为四分之一的实例上,在相同召回率下速度更快。”
Hacker News 评论者 esafak 对这些数字的呈现方式提出了质疑,认为基准测试应该放在前面:“如果你速度快,难道不应该先展示基准测试吗?请提供 QPS 和精确度/召回率。”仓库本身在抓取的内容中没有重现完整的 QPS 对比召回率表格;它链接到了公告文章和调优指南。
安装与使用
pg_vectorsearch 需要 PostgreSQL 18 或更高版本,并带有开发头文件、GNU C11 编译器(GCC 11+ 或 Clang 14+)和 Meson 构建系统。CBLAS 是可选的,但可以加速 RaBitQ 编码。
# 发布构建
meson setup builddir --buildtype=release
# 构建并安装到 PostgreSQL
meson install -C builddir
有两种使用路径,两者构建相同的索引并使用相同的运算符(<->、<#>、<=>)和调优参数。
原生类型
如果你从零开始或不使用 pgvector,可以将向量存储在 pg_vectorsearch 自己的 vec32(float32)或 vec16(float16)列中。不需要其他扩展。
CREATE EXTENSION pg_vectorsearch;
-- PLAIN 将向量内联存储。EXTERNAL(默认)会将超过约 2 kB 的值进行 TOAST,
-- 重新排序时会产生额外的获取开销,规划器无法将其计入成本。
CREATE TABLE items (
id serial PRIMARY KEY,
embedding vec32(3) STORAGE PLAIN
);
-- 先加载数据;索引在 CREATE INDEX 时根据行数确定大小。
-- 500 行足以让规划器使用该索引。
INSERT INTO items (embedding)
SELECT ARRAY[i::real, (i % 7)::real, (i % 5)::real]::vec32
FROM generate_series(1, 1000) i;
-- 对于内积或余弦,请参阅下面的运算符类。
CREATE INDEX ON items USING prism (embedding vec32_l2_ops);
-- 0 = 自动(约 0.95 召回率)。提高以获得更高召回率,降低以获得更快速度。
SET prism.nprobe = 40;
SELECT * FROM items
ORDER BY embedding <-> '[3,1,2]'
LIMIT 5;
现有 pgvector 表
如果你已经有一个使用 pgvector 的 vector 或 halfvec 列的表,可以直接在其上构建 PRISM 索引,无需更改表或查询。vec32 和 vec16 与 pgvector 的 vector 和 halfvec 二进制兼容,但名称不同,因此两个扩展可以并行安装,甚至可以在同一模式中安装。
CREATE EXTENSION vector;
CREATE TABLE documents (
id bigserial PRIMARY KEY,
body text,
embedding vector(384)
);
CREATE INDEX documents_embedding_hnsw
ON documents USING hnsw (embedding vector_l2_ops);
-- 在 pgvector 旁边安装 pg_vectorsearch,并在现有列上构建索引。
-- 该列不会被重写或复制。
CREATE EXTENSION pg_vectorsearch;
CREATE INDEX documents_embedding_prism
ON documents USING prism (embedding vec32_l2_ops);
README 指出,PRISM 通常更快,因此当两者都存在时,规划器应优先选择它,并建议在删除旧索引之前使用 EXPLAIN 进行验证。
运算符类
根据距离度量和列类型选择运算符类。L2 是默认值。
| 距离 | 运算符 | vec32 / vector |
vec16 / halfvec |
|---|---|---|---|
| L2 | <-> |
vec32_l2_ops |
vec16_l2_ops |
| 内积 | <#> |
vec32_ip_ops |
vec16_ip_ops |
| 余弦 | <=> |
vec32_cosine_ops |
vec16_cosine_ops |
当替换 HNSW 索引时,pgvector 的 vector_<metric>_ops 映射到 vec32_<metric>_ops,halfvec_<metric>_ops 映射到 vec16_<metric>_ops。
调优与维护
默认值是根据大规模基准测试调整的,文档指出大多数部署只需调整 prism.nprobe。设置 prism.nprobe = 0 会选择自动值,目标召回率约为 0.95。
关于维护,README 解释说,插入会追加到向量路由到的 posting list 中,因此随着行的到达,列表会增长,并且不会自行拆分。除了 REINDEX 之外,prism_rebalance 过程会就地拆分过大的列表。
社区提出的采用限制
Hacker News 评论者 devy 列举了三个实际障碍,供任何考虑替换现有 pgvector HNSW 索引的人参考:
- pg_vectorsearch 使用一个称为 PRISM 的量化 IVF 索引。PRISM 的向量维度上限为 1968。如果你之前的 HNSW 索引维度超过这个数字,你就没办法了(至少目前是这样,直到他们修复)。
- pg_vectorsearch 要求 PostgreSQL 版本 18 或更高。如果你运行的 PG 版本低于此,你需要先迁移数据库。许多遗留的 PG 生产环境仍在使用 PG 14 或 15,迁移成本过高,无法仅为了试用而进行。
- pg_vectorsearch 昨天刚发布,显然还是 alpha 版本。除了 Timescale 之外,还没有在生产环境中经过实战测试。此外,由于它太新,它不在 Azure 的允许扩展列表或任何其他 Hyperscale 托管 PG 实例的允许扩展列表中。
第三点得到了 swe_dima 的回应:“遗憾的是,如果云提供商不在托管 Postgres 上提供它,那么没有多少人可以使用它……”
过滤、量化和开放问题
几位评论者提出了 README 未宣传的功能。Rapzid 询问该索引是否支持过滤,并根据文档得出结论,它仅支持后过滤:“它支持过滤吗?编辑:仅后过滤。我不明白人们如何高效地使用这些索引实现租户/用户/权限范围。”
potomushto 指出缺少二进制量化和汉明距离支持:“有趣,我没有看到提到对位精度和汉明距离运算符的支持,后者应该会更快且更节省存储。”
其他人要求进行项目尚未发布的比较。thomasahle 询问 PRISM 与 Roar graph 相比如何,dmix 询问它与 ParadeDB 的 pg_search 相比如何,jakobedding 询问它与 pgvectorscale 相比如何。arunmu 更进一步,质疑了策略:“这些人难道不也写了 pgvectorscale 吗?它现在似乎无人维护。为什么创建一个新索引,而不是在 pgvectorscale 上添加或改进?”
竞争背景
评论者 EgregiousCube 报告说在生产环境中运行 VectorChord,并将此次发布视为向内存高效索引更广泛趋势的一部分:“我目前正在运行 VectorChord,我很喜欢它——在快速后端磁盘的支持下,它将我的 Postgres 成本减半。很高兴看到低内存向量索引工具的竞争。RAMageddon 似乎正在激励人们寻找更多方法来利用现代 NVMe 驱动器的速度!”
ilumanty 表达了相反的愿望,希望 PostgreSQL 之外也存在同类索引:“如果 SQLite 支持类似的东西,那就太棒了。”
alexpadula 提出了一个更轻松的观察,指出仓库的 PRISM 标志图像:“PRISM 的黑暗面!仓库上的图片 100% 受平克·弗洛伊德的《月之暗面》启发。”
要点
pg_vectorsearch 是一个 PostgreSQL 18+ 扩展,将 HNSW 的图结构替换为分层 IVF 风格的分区树,加上 RaBitQ 量化,并带有误差界过滤。Timescale 自己的数据声称在内存比 HNSW 少 4 倍的机器上,1 亿向量的查询延迟为 6 毫秒,索引构建速度快 20 倍以上。然而,该扩展是 alpha 版本,需要 PostgreSQL 18,尚未列入托管云允许列表,并且根据社区报告,维度上限为 1968,支持后过滤而非过滤搜索。该项目在列级别与 pgvector 兼容,因此可以在不重写表或查询的情况下与现有的 HNSW 索引一起进行评估。