Long-form

RIP, vector database 深读:当 ANN 不再是主索引,搜索架构走向何方

5 min read ·

9 月 30 日,turbopuffer 发了一篇标题相当炸裂的博客:RIP, vector database。HN 上 261 分,评论区第一反应几乎都是「向量数据库死了?」——读完原文你会发现恰恰相反:向量搜索活得好好的,被安葬的是把 ANN 索引当主键的存储架构。这篇帖子之所以值得深读,是因为它完整复盘了一个专用引擎从「专用红利」走向「专用枷锁」的全过程,而这条曲线几乎每个做基础设施的团队都会走到。

一、v1:一个 ID 和一个向量

turbopuffer 出道时的定位是 serverless 向量数据库:对象存储是事实源,NVMe 与内存做分层缓存,用经济性换性能。2023 年当时的主流是图索引(HNSW 一类),但图的随机游走访问模式与对象存储的高随机读延迟相性极差。turbopuffer 选择了层次聚类路线:从 SPANN 起家,后来迁移到 SPFresh 以支持增量索引。

布局逻辑是向量聚成组、组的质心再聚成组,层层向上形成单根树。存储层暴露为一个有序唯一的键值映射,每个向量拿到一个由 ClusterId 和 LocalId 组成的 ANN 地址,文档的一切内容都挂在这个地址下:

K::Vector(C0L0) = vec![0.45, 0.32, ...]
K::Id(C0L0)     = 7
K::Vector(C1L4) = vec![0.64, -0.48, ...]
K::Id(C1L4)     = C0        // 质心本身再向上聚类

这套设计在「文档等于一个向量」的世界里近乎完美:每个文档只存一份,块状读写契合对象存储,官方后来把单索引推到 1000 亿以上向量、200ms p99、每秒 1000+ 查询 的水平。Cursor 和 Notion 是最早的客户背书。

二、v2:世界不再只有一个向量

转折发生在需求多样化之后。客户开始要属性过滤和全文检索,turbopuffer 的做法是把它们都建模成指向 ANN 地址的倒排索引:

K::AttrIndex("genus", "Fratercula") -> vec![C0L3, C1L2, C1L9, ...]
K::FTS("description", "Atlantic")   -> vec![(C0L0, 2, 37), (C9L4, 1, 42), ...]

随后聚合、正则搜索、模糊匹配、稀疏向量、属性排序陆续上线——全部围绕同一个向量主布局。这里埋下了后来的三个结构性问题。

其一,存储放大。 一旦文档有多个向量表示(文档嵌套、late interaction),每个向量地址下都要复制一份完整文档内容,这直接导致了官方文档里那个不太体面的「每命名空间向量列数上限」。

其二,写放大。 SPFresh 为了维持聚类质量会做增量再平衡,移动向量就要移动挂在其 ANN 地址下的全部东西:属性、倒排索引、全文条目一起搬。官方的原话是「更新一个向量可能搬动数百个属性及其索引」,而索引吞吐的调优已经进入边际收益递减区间。这是一个典型的主键选错导致的级联成本——错的不是任何单个组件,而是组织键。

其三,向量化受限。 现代查询引擎靠向量化的块循环吃饭:DuckDB 用 2048 行的批次,ClickHouse 到 65000 行左右,Lucene 的 posting 块是 256 个文档,而 turbopuffer 的 ANN 聚类最优块大小是 100 到 200 个文档。所有查询计划都被迫沿用 ANN 的块大小,想要大块扫描的计划只能饿着。官方给过一个数字:全文检索 v1 的 posting 列表沿聚类边界切分,中位块只有约 1.5 个 posting;v2 把 posting 重组成固定 256 大小的独立块之后,索引缩小 10 倍、查询最快快 20 倍。posting 能这么做,是因为它独立存储、指回文档,布局不必跟着聚类走。

三、v3:把 ANN 降级为普通索引

解法说破了一文不值:不要用 ANN 地址当主键。文档内容与各索引各自组织,ANN 索引降级为与其他索引平级的二级索引,指向文档的新主键。难的不是想法,是迁移——v3 团队把正确性放在第一位,本月刚达成「CI 全绿」的里程碑,接下来进入公开的性能打磨期,基准数据会在 turbopuffer.com/v3 持续公布,性能全面打平之前不会推生产。

值得玩味的是标题的修辞策略:这家公司用「RIP, vector database」宣告的其实是自家架构的成人礼——当一项能力从核心卖点变成普通功能,它就应该从主键的位置上退下来。类似的剧本在数据库史上反复上演:B 树曾经是全文检索的主索引,倒排索引上位之后 B 树退回二级;行存曾经包办一切分析查询,列存上位之后 OLAP 分家。搜索引擎正在经历同样的一步。

四、对行业的三个判断

第一,「RAG 基建 = 向量库」的时代正在收尾。 Agent 与 RAG 应用的查询形态早已超出最近邻检索:过滤、聚合、正则、混合排序成为日常。一个引擎的向量成绩单不再是选型的充分条件,非向量查询能力应升级为一级评估项。turbopuffer 自己举的例子很说明问题:Linear 把同步引擎跑在它上面,这已经不是向量搜索的活。

第二,对象存储为底的 serverless 架构赢得了搜索这一局。 从 2023 年的「便宜但够用」到今天单索引千亿向量、每秒 25000+ 查询、每秒 1000 万+ 写入,这套经济模型被 Cursor、Notion、Linear 三类完全不同的负载反复验证。自建向量检索集群的必要性被进一步压缩。

第三,专用引擎的宿命是不断地「杀死昨天的自己」。 turbopuffer 敢于公开宣布推翻自己赖以成名的主架构,并把过程直播出来,这既是工程自信,也是品类竞争白热化的信号: Pinecone、Weaviate、Qdrant 与各类内嵌方案之间的差距正在缩小,差异化从「我有什么」转向「我的架构还剩多少演进空间」。

五、给你的行动清单

如果你的系统今天跑在向量数据库上,有三件事值得马上做:审计自己的查询里非向量查询的占比与延迟,它决定你在下一次架构迁移时的主动权;检查你的引擎对 late interaction、多向量文档的支持方式,存储放大问题会在你上 ColBERT 类检索时准时出现;关注 v3 的公开基准,如果它兑现了「所有查询计划全面变快」的承诺,迁移窗口就值得认真评估。

毕竟,Vector database 没死。死掉的只是「向量即一切」的架构假设——而这才是那篇博客真正的讣告对象。

Frequently asked questions

「RIP, vector database」是说向量数据库这个品类死了吗?
不是。标题里的 RIP 指的是向量主索引这一种内部架构,而不是向量搜索本身。turbopuffer 仍会继续提供向量搜索,只是把它从「整个存储引擎围绕它组织」降级为「众多二级索引之一」。恰恰因为向量搜索变得普通,它才不再配得上主索引的地位。
为什么 ANN 索引在对象存储上曾经是正确的主索引选择?
对象存储便宜但随机读延迟高,图索引(如 HNSW)的随机游走访问模式与之相性极差。SPANN 一类的层次聚类索引把向量分组、以块为单位读写,配合分层 NVMe 与内存缓存,能以极低成本提供可用性能。turbopuffer 正是靠这套权衡拿下 Cursor 与 Notion 等早期客户,单索引支撑过 1000 亿向量、200ms p99、每秒千级查询。
写放大的具体代价有多大?
文档的全部内容都挂在向量的 ANN 地址下。SPFresh 为保持聚类质量会做增量再平衡,移动一个向量就要把该地址下的全部属性、全文索引条目一起搬走。更新一个向量可能牵动数百个属性及其索引,官方坦言索引吞吐优化已经进入边际收益递减区间,这才下决心换主键。
v3 换主索引后,向量搜索性能会不会倒退?
官方明确说性能打平之前不会把 v3 推到生产。目前 v3 已实现 CI 全绿的里程碑,接下来的阶段是公开磨性能,基准数据会陆续发布。方向上向量搜索本身不受影响——SPFresh 聚类索引仍在,只是不再作为文档内容的组织主键,反而解除了它对其他查询计划的束缚。
这场架构变更对普通开发者选型有什么启示?
三点:一是专用引擎的专用红利会随负载多样化耗尽,选型要看路线图而不只看当前榜单;二是对象存储为底、分层缓存的 serverless 模式在搜索领域已成主流,自建向量库的必要性进一步下降;三是如果你正在做 RAG 或 Agent 记忆,混合查询(向量加过滤加聚合)会越来越常见,选引擎时应把非向量查询能力列为一级评估项。
// next.txt ›

Some outbound links in this post are affiliate links — see disclosure.