向量索引量化压缩与检索精度权衡落地

日期:2026-08-07

一、项目背景

我们维护的向量库一开始规模不大,几百万条,浮点向量原样存,检索飞快。后来业务把商品图、文档、日志全塞进来,很快冲到几亿条,存储成本和内存都扛不住,检索也变慢。有人提议直接上乘积量化压一压,我们没急着拍板,因为之前在别的项目吃过量化掉召回的亏,这次想先把精度和成本的账算清楚再动。

这个项目是在已有的向量数据库层上做索引改造,Milvus 和 pgvector 两套都在用,我们统一了一套量化选型流程。底层目标就一个:在可接受召回损失内,把存储和延迟压下来。

二、落地场景

实际做了四块。标量量化与乘积量化选型,我们按向量维度和精度要求分别试了 INT8 标量和 PQ,对比召回。召回率压测,用固定测试集跑不同压缩比,画召回曲线找拐点。混合精度检索,高频热点向量保留浮点,长尾走量化,兼顾成本和精度。热点向量缓存,把被查得最多的那批放进内存,进一步压低延迟。

我们先拿商品图那一个集合试水,两亿条,压缩前全量浮点要吃近一 T 内存,明显不可持续。试点不急于全量切换,而是新旧索引并行跑,对比一周再决定。

三、关键技术挑战与解决思路

第一个挑战是精度损失可控。PQ 压缩比越高召回掉得越狠,盲目压到八倍召回能掉十几个点。我们没追求极限压缩,而是定了一条硬线:召回率不低于浮点基线的 97%,在线上测试集上反复调码本和分段数,找到刚好达标的压缩比,而不是压到最小。

第二个是召回兜底。量化索引即使达标,长尾查询仍可能漏。我们做了两路,量化索引做初筛,可疑边界结果再用少量浮点做精排兜底,牺牲一点延迟换回召回,长尾查询的漏检基本补回来。

第三个是内存与延迟的平衡。纯量化省内存但要多算一步解码,纯浮点快但吃内存。我们把热点集合放浮点、冷集合放量化,再加一层内存缓存兜热点,整体既不爆内存也不慢。

案例片段(已脱敏): 量化压测对比(示意):集合: items_img_200M  维度: 768 方案          压缩比   内存   召回率@10   检索P99 float32       1x      980G   1.000      18ms sq_int8       4x      245G   0.991      15ms pq(32x256)    8x      123G   0.962      22ms结论:选 sq_int8(召回 0.991 达标,内存降 75%),长尾查询走浮点精排兜底。

四、效果数据

商品图集合切到 INT8 标量量化后,我们看了一周。存储成本,内存占用从约 980G 降到约 245G,降了约 75%,服务器数量相应减下来。召回率,线上测试集稳定在约 0.99,高于我们定的 0.97 硬线,用户侧没感知到变化。检索 P99 从约 18 毫秒降到约 15 毫秒,因为数据更紧凑、缓存命中更好。内存占用整体平稳,不再随集合膨胀线性涨。

这里我得说句实话,INT8 不是万能,维度特别高或者分布很偏的向量,标量量化掉得比商品图多,这种集合我们没硬上,还是留了浮点,别为了统一而统一。

五、可复用经验总结

向量量化别一上来追最大压缩比,掉召回是慢刀子,用户不会马上骂你但慢慢就流失了,我们定的 97% 召回硬线救了好几次。长尾一定要兜底,量化索引初筛加浮点精排,这点延迟换召回值。热点和冷数据分开对待,别一套方案打天下,内存和延迟的账要分开算。先并行跑新旧再切,亿级数据一旦压错回滚极痛,并行对比一周的成本远小于翻车。

后来我们把这套量化选型流程做成接入检查单,新集合上向量库先测召回再定方案,不再凭感觉压。

附:选型之外的工程细节

量化切过去之后,我们遇到一个之前压测没暴露的问题:批量写入时,新旧索引交替会让检索抖动。我们改成了双写加灰度切读,先双写一段时间保证数据一致,再按流量比例把读逐步从浮点切到量化,全程可回退,上线那周没人熬夜。还有码本更新,量化索引的码本是离线训练的,文档分布一变码本可能过时,我们设了定期重训,重训完新码本和旧索引并行,确认召回不降再切换。存储省下来之后,我们把省出的服务器挪去跑召回精排的浮点实例,等于用省的钱把长尾精度补回来了。向量库这种基础设施,省成本和保精度是同一件事的两面,别割裂看。

我们还给量化索引加了在线召回监控,每千次查询抽一批用浮点重算对比,召回低于基线就告警,不等用户投诉。这个采样成本高但值得,毕竟量化是长期跑的东西,分布漂移是慢刀子。另外存储省下来的钱,我们没全省下,而是挪了一部分去加内存缓存热点,商品图这种高频集合命中缓存后几乎不走磁盘,延迟进一步压下来。向量库优化不是一次性的事,量化、缓存、监控三件套得长期配合,我们把它做成例行巡检项,每月看一眼召回和成本曲线。

向量索引这层我们踩过的坑基本都和精度与成本的拉扯有关,后续新集合上库,我们会先在小流量上压一遍召回再放大,不再凭经验直接定方案。