向量存储


存向量这件事本身很简单,难的是带着过滤条件、在可接受的延迟内、用能负担得起的内存,找到”差不多最近”的那几条。索引结构解决前半句,工程能力解决后半句。

一、向量存储在系统里承担什么

从调用方的角度看,向量存储要提供的接口只有几个:写入一批向量和它的元数据、按某个向量找最近邻、带过滤条件找、删除。看起来很薄,实际上每个都能展开成一堆取舍。

它和普通数据库的差别在于”最近邻”这件事只能近似。精确的 k 近邻要与每个向量算一遍距离,复杂度 O(N·d),一千万条 1024 维向量就是一万亿次乘加,任何硬件都吃不下。于是全部转向近似最近邻(ANN),用一小部分召回率换几个数量级的加速。

这带来一个必须一开始就建立的认知:向量检索的召回率和延迟不是调优问题,而是配置问题。同一份数据、同一个索引,把参数调大一档,召回上升、延迟上升、内存不变;换一种索引结构,则是另一种形状的取舍曲线。没有”最优配置”,只有”在给定资源和延迟预算下的最优点”。

规模这一维值得单独说,因为每跨一个数量级,工程重心都会变:

规模 工程重心
十万以内 别引入新组件,用已有的数据库加扩展就够
百万级 索引参数与内存预算开始重要,量化值得考虑
千万级 单机内存开始吃紧,要上磁盘索引或分片
亿级及以上 变成分布式存储与运维问题,选型空间收窄到少数几个系统

二、三种索引结构

近邻检索的索引结构经过几十年演进,工程上真正在用的收敛成三类。

暴力检索

不算索引,就是把所有向量存下来,查询时逐个算距离。召回率百分之百,结果精确,延迟随数据量线性增长。

它的工程价值在于两点:一是给其他索引当”精确率基准”,用来量近似索引到底丢了多少召回;二是十万条以内的规模,它常常比建索引更快,省掉了构建时间和图结构的内存开销。很多向量库把它叫 FLAT 或 brute force。

聚类加倒排:IVF 家族

先用 k 均值把向量聚成 nlist 个簇,每个簇有一个中心点,所有向量按所属簇存进倒排列表。查询时只算查询向量与簇中心的距离,选最近的 nprobe 个簇,只在簇内做精确比较。

复杂度从 O(N·d) 降到大约 O(nprobe/nlist × N·d)。nlist 和 nprobe 是唯一的两个旋钮:nlist 越大簇越细、召回越依赖 nprobe;nprobe 越大召回越高、延迟越高。

IVF 的两个工程约束要注意。一是需要训练:簇中心由数据决定,所以建索引前要先跑一遍聚类,训练数据的质量和数量会影响索引效果。二是边界效应:正确答案如果落在相邻簇的边界上,而那个簇没被选中,就永远召不回来——这不是参数没调好,是结构本身的特性。

在 IVF 之上叠一层乘积量化就得到 IVF-PQ:把向量切成若干子空间,每个子空间用少量比特编码成聚类中心的编号,于是向量被压成几十个字节。压缩比可以做到十几到几十倍,代价是距离计算变成查表近似,召回进一步下降。

图:HNSW 与它的家族

HNSW 是分层可导航小世界图。每个点在第 0 层有最多 2M 条连边,上层最多 M 条;上层点稀疏、边长长,用来做粗跳转,下层点密、边短,用来做精确定位。查询从最上层的入口开始,每层贪心走到局部最近的点,再下沉到下一层,像跳表一样逐层细化。

三个参数决定它的行为:

参数 作用 调大的代价
M 每个点的连边数 内存和构建时间上升,召回上升
ef_construction 建图时的候选队列长度 建索引变慢,图的质量变好
ef_search 查询时的候选队列长度 延迟上升,召回上升

它的优点很直观:查询接近对数复杂度,召回率通常明显高于同规模的 IVF,而且是纯内存结构、不依赖训练。缺点同样直接:图结构吃内存,而且删除很别扭——删掉一个点会破坏图的连通性,所以多数实现是打墓碑标记,查询时跳过,空间不回收,到一定程度需要重建。

内存这部分值得算清楚,因为它常被误解成”很大”。图结构的开销主要在第 0 层的连边:每个点最多 2M 条边、每条边存一个 4 字节的节点编号,M 取 16 时就是约 128 字节/点;上层贡献的连边总数与点数同量级,可以忽略。一百万点的图结构约 128 MB,而 1024 维单精度向量本身是 4 GB——图只占百分之三。但如果把向量量化到每点 1 KB,同样的图就占到 12%,这时候它就不能再被当成零头。

三类结构的对比:

结构 查询复杂度 内存 是否需训练 增删改 典型召回
暴力(FLAT) O(N·d) 仅向量 否 自由 100%(精确)
IVF / IVF-PQ 约 O(nprobe/nlist·N·d) 低 是 较自由 中到高
HNSW 约 O(log N) 高 否 插入容易,删除要墓碑 高

还有一类结构面向单机放不下十亿级的场景:磁盘索引(DiskANN 一线)。它把图和向量放在 SSD 上,靠精心设计的布局把随机读次数压到可接受的范围,用延迟换容量。当内存装不下全量向量时,这是比”加机器”更常见的选择。

参数的起点值

索引参数的默认值通常偏保守,直接上线会得到”能用但不够好”的结果。下面这些是有据可依的起点,实际值要靠自己的数据量出来。

索引 参数 起点 调整方向
HNSW M 16(通用)、32 到 64(高召回要求) 调大:召回升、内存升、构建变慢
HNSW ef_construction 200 调大:图质量更好、构建更慢
HNSW ef_search 40 到 64 起步,按召回目标最高调到 200 上下 调大:召回升、延迟升
IVF nlist 取 √N 的若干倍(常见做法在四倍上下) 调大:簇更细,需要同时提高 nprobe
IVF nprobe 从 nlist 的百分之一量级起 调大:召回升、延迟升
PQ 子空间数 每子空间放 4 维(即维度除以 4) 子空间越多越准,压缩比越低
PQ 每子空间比特 8 调大:更准、更占内存

调参的经验顺序是:先固定 ef_search 测召回曲线,确定达标所需的最小值;再用这个值去测延迟是否满足预算;两者冲突时回头改索引结构或量化方式,而不是在两个参数之间反复拉锯。

稀疏向量与倒排

词法检索的倒排索引本身就是一种稀疏向量检索:词表维度可以是几万到几十万,每个文档只有其中很少的维度非零。学习到的稀疏表示(SPLADE 一线)把这种倒排索引用了起来,只不过权重由模型学出来,还支持把查询扩展成相关词。

它的价值在于和稠密检索互补:稠密向量擅长语义泛化,稀疏表示对精确词、罕见词、编号这类 token 更敏感。多数向量库对稀疏向量的支持和稠密向量不在一个层次上,接入前要确认清楚——能存稀疏向量不等于能高效地做稀疏检索。

三、量化:把内存降下来

向量本身是内存的大头,所以压缩的收益最直接。常见做法按压缩比排序:

方式 每点内存(1024 维) 相对单精度 召回影响
单精度 fp32 4 KB 1× 基准
半精度 fp16 2 KB 2× 几乎无损
标量量化 int8 1 KB 4× 很小
二值量化 128 字节 32× 明显,需要重排补偿
乘积量化 8 到 64 字节 64 到 500× 中等,取决于子空间数与比特数

百万级向量、1024 维的账很好算:单精度 4 GB、半精度 2 GB、int8 1 GB、二值 128 MB。这就是为什么”内存不够先量化”是对的默认动作,加机器的性价比通常不如压缩。

二值量与乘积量化都会让距离估计失真,标准的补偿方式是两段式检索:先用压缩向量召回一个较大的候选集(比如 200 条),再用原始向量(或半精度向量)对候选重算距离并取前 k 条。原始向量要不要留在库里,是选型时要确认的一个能力点——有些系统压缩后不保留原向量,就无法做这一步补偿。

四、过滤:最容易被低估的一块

业务查询几乎都带条件:只看某个租户的、只看最近一年的、只看已发布版本的。过滤和向量检索的交互方式有三种,代价差别很大。

先过滤再检索(pre-filter)。先用条件筛出候选集合,再在集合内做向量检索。召回率理论上最高,但如果条件筛完只剩几百条,向量索引就没意义了;更麻烦的是多数图索引无法在”只包含部分点”的子图上高效遍历。

先检索再过滤(post-filter)。先按向量找出 top-k 再筛条件。实现最简单,但结果数不可控——pgvector 的文档里给过一个很清楚的例子:条件只匹配 10% 的行、HNSW 的 ef_search 取默认的 40 时,平均只有 4 行能通过过滤。用户要的是 10 条,返回 4 条,看起来就是”检索坏了”。

过滤感知的检索(in-filter)。把谓词下沉到索引遍历里,图在搜索时会跳过不满足条件的点,但仍然沿着连通性继续走,直到凑够候选。这是效果最好的做法,也是实现难度最高的:图索引需要专门设计(ACORN 一线就是这个方向的工作),倒排类索引相对容易。

工程上的处理手段有这么几种,可以组合用:

  • 提高候选量。把召回数从 50 提到 200 或 500,让过滤后有足够的存活结果。代价是延迟和重排成本
  • 迭代式扫描。pgvector 从 0.8.0 起支持这个模式:过滤后行数不够时自动继续往索引深处扫描,直到凑够结果或达到上限。这是”先检索再过滤”的补救
  • 把高频过滤字段做成物理结构。按租户分区、按时间分表、按类型建独立集合,让过滤在进入检索前就完成
  • 候选集放大加二次筛选,用于权限这类会变化的标签

判断自己是否踩了这个坑,有个简单的办法:统计”返回结果数少于请求数”的请求占比。这个比例高,说明过滤和检索在打架,调索引参数没有用。

五、度量与数据类型

距离度量必须和嵌入模型的训练目标一致,这是最容易出错又最难发现的一类问题。

余弦相似度和内积在向量归一化之后是等价的:

$$\cos(\mathbf{q}, \mathbf{d}) = \frac{\mathbf{q} \cdot \mathbf{d}}{\lVert \mathbf{q} \rVert \lVert \mathbf{d} \rVert} = \mathbf{q}_{\text{norm}} \cdot \mathbf{d}_{\text{norm}}$$

所以入库时统一做归一化、距离度量选内积或余弦,能消掉一层不确定性。欧氏距离则在归一化后有单调关系 $\lVert \mathbf{q} - \mathbf{d} \rVert^2 = 2 - 2\cos(\mathbf{q}, \mathbf{d})$,排序结果一致,但不等价于可以为所欲为地混用——很多库把”内积”和”余弦”实现成两套代码路径,选错会得到完全无意义的结果,而且不报错。

维度上限是另一个容易撞上的墙。不是所有库都能索引任意维度的向量,pgvector 的清单很典型:

类型 可索引的最大维度 说明
vector(单精度) 2000 超了只能存不能索引
halfvec(半精度) 4000 高维模型的常见出路
bit(二值) 64000 配合二值量化使用

维度越高的模型(比如 3072 维、4096 维)越容易撞上限。有的模型支持套娃式截断(先按低维检索再补算),有的库支持降维索引,这些都要在选型时确认。

六、选型要看的能力清单

索引类型和性能只是选型的一部分,真正会让项目卡住的往往是下面这些。

能力 要确认什么 踩坑后果
过滤方式 是 pre、post 还是过滤感知;是否支持迭代扫描 过滤后结果数不足,召回断崖
更新语义 是否支持原地更新;删除是真删还是墓碑;空间回收方式 大量更新后索引退化、空间不释放
一致性与持久化 是否有 WAL、崩溃恢复、与业务库的一致性方案 重启丢数据、向量与业务数据不一致
多租户 集合隔离、分区、行过滤,以及租户数量上限 租户多时元数据或连接数爆炸
混合检索 是否内置全文检索与融合;稀疏向量支持到什么程度 要把两套系统拼起来,一致性自己解决
量化与重排 压缩后是否保留原始向量 无法做二段式重排补偿召回
扩展方式 单机到分布式的路径、分片与副本、扩容是否需要停机 到千万级才发现要重搭
生态与迁移 SDK 完整度、与编排框架的集成、导入导出的便利程度 迁移成本高于预期
许可证 商用限制、多租户 SaaS 限制、品牌条款 商用后被迫重构
成本结构 内存型还是磁盘型;托管是按节点还是按用量 账单随数据量非线性上涨

七、主流系统逐个说

下面按类别过一遍目前主流的选择。定位和许可证取自各仓库当前状态(2026 年 10 月)。先给一张横向总表,细节在后面。

系统 许可证 索引 过滤 适合规模 运维成本
pgvector PostgreSQL HNSW、IVFFlat SQL WHERE 加迭代扫描 百万到千万 无(挂在现有库上)
pgvectorscale PostgreSQL DiskANN 思路 同上 千万到亿 低
Qdrant Apache 2.0 HNSW(过滤感知) 过滤下沉进图遍历 千万 中
Milvus Apache 2.0 HNSW、IVF、DiskANN、SCANN、GPU 标量索引加范围检索 亿级以上 高
Weaviate BSD-3 与自有许可混合 HNSW、FLAT 过滤与混合检索内建 千万 中
Vespa Apache 2.0 HNSW 搜索出身,能力完整 千万到亿 中高
Elasticsearch Elastic License 2.0 与 SSPL HNSW 极强(倒排加列存) 千万 中,已有则低
OpenSearch Apache 2.0 HNSW 同上 千万 中
Redis 分段变化,见下文 HNSW、FLAT 有限 百万 低
LanceDB Apache 2.0 IVF-PQ、HNSW 支持 单机磁盘容量内 极低
Chroma Apache 2.0 HNSW 基础 十万以内 极低
Typesense GPL-3.0 HNSW 强(搜索出身) 百万到千万 低
Meilisearch MIT HNSW(较新) 强 百万级 低
ClickHouse Apache 2.0 HNSW(25.8 起) 极强(SQL) 千万,偏分析 中
Apache Doris Apache 2.0 HNSW、IVF、IVF On-Disk 先过滤再检索,要求二级索引 千万,偏分析 中
DuckDB VSS、sqlite-vec MIT、Apache 2.0 HNSW、暴力 基础 十万以内 无

数据库型

pgvector(PostgreSQL 许可)。Postgres 的向量扩展,支持 HNSW 与 IVFFlat 两种索引,向量类型有单精度、半精度、稀疏、位四种,索引维度上限分别是 2000、4000、64000。它最大的优势不是性能,而是向量和业务数据在同一个库里:同一次事务写业务表和向量表,过滤条件就是普通的 SQL WHERE,权限体系、备份、监控全部复用。从 0.8.0 起支持迭代式索引扫描,缓解了过滤后行数不足的问题。

适合的规模是一百万到一千万条向量,判断依据是单表索引的内存与构建时间。要注意的是维度上限、以及过滤条件的选择性——选择性差的条件会让 Postgres 的查询计划在向量索引和常规索引之间选错,需要人工干预。

配置上有几个关键项值得记住:

SET hnsw.ef_search = 64;                 -- 查询期召回与延迟的主要旋钮
SET hnsw.iterative_scan = strict_order;  -- 过滤后结果不足时继续向索引深处扫描
SET hnsw.max_scan_tuples = 20000;        -- 迭代扫描的上限,防止一次查询扫太久
SET ivfflat.max_probes = 100;            -- 用 IVFFlat 时对应的上限

建索引时不要漏掉并行:CREATE INDEX ... USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 200) 配合 max_parallel_maintenance_workers,是百万元素级构建时间的主要差别来源。

配套的 pgvectorscale(PostgreSQL 许可)用 DiskANN 思路的索引把单机容量推到更大规模,是 pgvector 内存不够时的自然升级路径。

Qdrant(Apache 2.0)。Rust 实现,主打”过滤与向量检索一起做好”:过滤条件在 HNSW 遍历中生效,不需要靠放大候选来补。支持稠密、稀疏、多向量三种表示,支持标量、乘积、二值三种量化,也能把向量放在磁盘上。单机性能强,分布式是分片加副本的常规设计,运维复杂度明显低于 Milvus。默认选择里最”没有明显短板”的一个,适合需要强过滤、千万级规模、又不想扛分布式运维的场景。

Milvus(Apache 2.0)。云原生分布式向量库,把系统与检索引擎分离,支持 HNSW、IVF、FLAT、SCANN、DiskANN 以及各自的量化变体,还支持 mmap 降低内存占用和 GPU 索引(NVIDIA CAGRA)。元数据有标量索引、支持范围检索。它的定位是亿级及以上:组件多(依赖 etcd、对象存储、消息队列),运维成本高,换来的是水平扩展能力和完整的周边(GUI、CDC 同步、监控、Spark/Kafka 连接器)。

Weaviate(BSD-3 与自有许可混合)。模块化设计,可以内置向量化模块(在库侧调用嵌入模型),内置 BM25 与向量混合检索并在服务端完成融合,多租户是内建能力,向量压缩支持量化与多向量编码。适合希望少写编排代码、把混合检索和租户隔离交给数据库的场景。要留意的是许可:主体是 BSD-3,部分企业功能在自有许可下;某些版本的许可调整也发生过,商用前读一眼 LICENSE。

Vespa(Apache 2.0)。老牌的检索引擎,向量只是它能力的一部分。它真正的强项是排序表达式:可以把向量相似度、BM25 分数、业务字段、机器学习模型输出写进同一个排序函数里,做高度定制的相关性排序。实时写入与检索能力强,适合”排序逻辑复杂、需要在线调整权重”的场景。代价是概念多、学习曲线陡。

Elasticsearch / OpenSearch。全文检索领域的老牌选手,向量是后加的能力:dense_vector 字段配 HNSW 索引,支持量化压缩,能与 BM25 做混合检索。过滤能力是它相对向量库的绝对优势——倒排索引与列存支持的复杂条件、聚合、排序都是成熟的。许可证需要分清:Elasticsearch 从 7.11 起使用 Elastic License 2.0 与 SSPL 双许可,对外提供托管服务有约束;OpenSearch 是它的 Apache 2.0 分支,能力接近但生态略小。已有 ES 的团队用它起步通常比引入新组件划算。

Redis(许可情况复杂)。内存数据库加向量检索(HNSW 与 FLAT),延迟极低,适合缓存与向量检索共存的场景。许可证要特别看清楚:7.2 及以前是 BSD-3,7.4 到 7.8 是 RSALv2 或 SSPLv1 二选一,8.0 起提供 AGPLv3 选项;另外部分 Intel 优化(Leanvec 之类)是闭源的、只在 RSALv2 下可用。内存成本高是它作为向量库的固有短板。

LanceDB(Apache 2.0)。嵌入式向量库,底层是 Lance 列式格式,向量和原始数据(图片、音频、文本)放在一起,支持 IVF-PQ 与 HNSW。定位是本地与边缘:单进程、零运维、直接从磁盘检索,适合桌面应用、单机分析、以及把向量数据当作”带索引的数据文件”来管理的场景。

Chroma(Apache 2.0)。开发体验优先的嵌入式向量库,API 简单,在原型和教学场景里出镜率很高。定位是单机与中小规模,把”带过滤的向量查询”做得很顺手。生产环境大规模使用前建议评估它的持久化与并发能力。

Typesense / Meilisearch。轻量全文检索引擎,都在近两年补上了向量与混合检索。Typesense 采用 GPL-3.0,它的文档里专门解释了理由:GPL 对”作为独立服务运行”的用法是宽松的,只有当修改并分发时才触发义务;如果要把引擎代码嵌进自己的程序里,这条许可就要重新评估。Meilisearch 是 MIT,语义检索与混合检索是较新的能力,适合从全文检索起步、逐步加上语义的路径。

ClickHouse(Apache 2.0)。分析型数据库,25.8 起提供原生的向量相似度索引(基于 usearch 的 HNSW)。它的价值在分析场景:先用 SQL 做大规模过滤与聚合,再对筛出来的子集做向量检索,或者反过来把向量检索结果与业务指标做关联分析。不适合当作纯粹的向量库来用。

Apache Doris(Apache 2.0)。MPP 架构的实时分析数据库,4.0 起原生支持 ANN 向量检索,底层基于 Faiss,索引有 HNSW、内存版 IVF,以及把倒排列表放磁盘、靠缓存服务的 IVF On-Disk 三种。向量以定长数组存储,没有引入新的数据类型。它和 ClickHouse 属于同一类:向量是分析引擎的一个扩展,价值在于向量检索、关键词检索和结构化分析写在同一条 SQL 里——倒排索引做过滤、ANN 做语义召回、聚合与关联分析都在同一个引擎内完成。

几个实现细节值得记:它采用先过滤再检索(pre-filter)语义,代价是过滤字段必须建过二级索引(例如倒排索引),否则会退化成暴力计算以保证结果正确;支持按距离范围检索,也能和 TopN 组合;量化有标量(int8、int4)和乘积量化,官方给出的对比里,768 维百万级数据集上 int8 把索引从 3.1 GB 压到 1 GB 左右。约束上有两点要注意:ANN 索引只能建在 Duplicate Key 表模型,或者开启 merge-on-write 的 Unique Key 表上;查询时距离函数必须和索引的度量类型一致,内积还必须配合降序排序才会走索引。

官方文档里还贴了一组压测数据(32 核 64 GB 双节点、百万级 768 维数据集):240 并发下约 3300 QPS、平均延迟 71 毫秒、召回率 91%;换成 int8 量化后召回降到 88%,暴力检索则只有不到 4 QPS。厂商公布的数据不能直接替代自测,但这组数字的量级能说明它的定位——它不是要和专用向量库比单点性能,而是把”分析库已有的数据”直接变成可检索的向量库。

部署形态上,它的经典架构是存算一体:只需要部署 FE 和 BE 两类进程,不依赖外部对象存储或共享文件系统,一套集群自己管自己的存储。3.0 起增加了存算分离模式,元数据与数据落到对象存储、计算节点无状态,换来弹性伸缩和成本优化。对向量检索而言这个区别的实际影响是:存算一体模式下索引常驻本地内存,延迟更可控;存算分离模式下要关注索引缓存的命中率,冷启动后的第一次查询会明显更慢。

DuckDB 与 SQLite 系。嵌入式数据库的向量扩展:DuckDB 的 VSS 扩展提供 HNSW 索引,SQLite 生态里有 sqlite-vec 这类扩展。适合数据量不大、希望”零依赖、单文件”的场景,比如本地工具、离线分析、桌面上跑的检索。

服务化的库(不是数据库)

FAISS(MIT)、hnswlib(Apache 2.0)、DiskANN(MIT)、cuVS(Apache 2.0)、USearch(Apache 2.0)这些是索引库而不是数据库。它们只提供”建索引、查近邻”的能力,持久化、并发控制、过滤、更新、监控都要自己写。适合两类场景:研究评测(换索引结构做对比),以及把索引嵌入到自己系统里的深度定制。直接拿它们当服务层用,通常会在元数据管理、崩溃恢复、在线更新这些地方反复踩坑。

Annoy(Apache 2.0)值得单独提一句:它是早期广泛使用的内存型索引,只读、适合构建后不再变化的场景,但仓库更新已经很慢,新项目不建议选它。

托管服务

Pinecone。托管向量库的代表,serverless 架构把存储与计算分离,按用量计费,不需要关心分片和副本。适合不想运维、快速验证的场景;数据出境、长期成本、厂商锁定是三个要在决策里写明的问题。

Zilliz Cloud(Milvus 的商业版)、Azure AI Search(内置混合检索与语义排序)、MongoDB Atlas Vector Search(向量与文档数据同库)、AWS 的 OpenSearch Serverless 与 Aurora pgvector 属于同一类:把开源自建形态做成了托管。如果已经在用对应的云生态,这类服务往往是阻力最小的选择。国内云厂商(阿里云、腾讯云、百度等)也都有托管向量检索服务,合规和网络延迟上有优势,接口与生态的成熟度需要单独评估。

八、按场景选

把上面的内容压成一条决策路径:

  1. 已经在用 PostgreSQL、数据量在千万以内:直接上 pgvector,不引入新组件。内存不够就加 pgvectorscale 或开量化
  2. 已经在用 Elasticsearch/OpenSearch、且全文检索是刚需:用它的向量能力做混合检索,不要为了向量再引一套系统
  3. 过滤条件复杂、需要千万级单机:Qdrant 是默认答案,过滤感知是它区别于通用向量库的地方
  4. 亿级以上、团队有分布式运维能力:Milvus 或直接买托管
  5. 本地、边缘、桌面应用:LanceDB、DuckDB VSS、sqlite-vec 这类嵌入式方案
  6. 数据本来就在分析库里(Doris、ClickHouse):用引擎自带的向量能力,省掉一次数据搬运和一条同步链路,代价是索引能力不如专用库
  7. 排序逻辑复杂、要在线调权重:Vespa
  8. 完全不想运维、且合规允许:托管服务
  9. 只是做算法评测:FAISS 或 hnswlib,别搭服务

反过来的三种反模式也值得记住:为十万条向量上分布式系统;先定向量库再定嵌入模型(两者耦合,换了模型要全量重建);只看索引性能不看过滤能力(过滤才是生产环境里的主要矛盾)。

九、容量与性能怎么算

动手前先把内存算清楚,这是唯一能在选型阶段精确计算的指标。

$$\text{内存} \approx N \times d \times b_{\text{向量}} + N \times b_{\text{图}} + \text{元数据开销}$$

举个例子:一亿条 1024 维单精度向量,向量本身 400 GB,图结构(M 取 16,约 128 字节/点)再加 13 GB。这个量级决定了必须走量化或者磁盘索引——量化到 int8 是 100 GB,二值量化到 128 字节/点是 13 GB,加上图结构的 13 GB 只有 26 GB,单机就能放下。

延迟这一侧无法靠公式给出可信答案,只能实测。要测的项有四个:

  • 召回率。拿黄金查询集,用暴力检索做基准,量近似索引到底丢了多少。这一项必须自测,任何厂商的公开数据都不能替代
  • p50 与 p99 延迟,以及在目标 QPS 下的延迟曲线(多数系统在低并发下延迟很好看,到 50% 负载时会翻倍)
  • 过滤条件下的召回与延迟。用真实的选择性分布测(比如选择性 10%、1%、0.1% 各测一组),这是最容易出问题的一组数据
  • 索引构建时间与内存峰值。构建过程往往比查询更吃资源,在线扩容时的构建时间直接决定运维窗口

十、运维

索引构建。大批量导入后再建索引,比边导入边建快得多。构建过程要预留内存峰值,多数实现会同时持有原始数据和图结构。能做到并行构建的(pgvector 支持并行建索引)要把并行度利用起来,构建时间常常是小时和分钟的区别。

增量写入与退化。图索引在持续插入后会退化:新点只和邻近的少数点连边,逐渐形成”孤岛”,召回率缓慢下降。缓解办法是控制写入模式(尽量批量)、定期重建、以及在写入量大的系统里把索引分成”历史段”与”增量段”。

删除。多数实现的删除是墓碑标记,空间不回收,需要定期重建或触发空间的整理。删除率高的系统要专门设计这个流程,否则磁盘和内存会只涨不降。

一致性。向量库和业务库的双写很难保证原子性。常见的做法是以业务库为准,用变更日志(CDC 或消息队列)异步同步到向量库,并保证同步是幂等的(按内容哈希或版本号去重);对一致性要求高的场景,接受”检索结果可能陈旧几秒”并在产品上明说。

迁移与升级。索引格式会随版本变化,大版本升级常常需要重建索引;更换嵌入模型更是必然全量重建。把”重建”设计成常规能力:保留原始片段、记录模型版本、支持双索引灰度切换,比任何一次性的优化都重要。

监控。至少要盯这几项:召回率(用固定的黄金集定期跑)、p99 延迟、内存与磁盘水位、索引构建队列长度、返回结果数为零的请求占比(过滤打架的信号)、向量与业务数据的行数差(同步滞后的信号)。

十一、常见误解

“向量库就是存向量。” 存向量是最简单的部分,难点在带过滤的近邻查询、更新与删除语义、以及和数据的一致性。

“选召回率最高的索引就行。” 索引性能的差异常常被过滤条件的交互掩盖。先量清楚过滤的选择性分布,再谈索引。

“内存越大越好。” 量化加两段式重排是更划算的路线:省下的是持续的成本,付出的是可控的召回损失。

“量化一定掉点。” 半精度几乎无损,int8 的损失通常很小。只有二值量化和激进的乘积量化需要认真评估,并且用重排补偿。

“托管一定贵,自建一定便宜。” 小规模下托管的账单通常低于自建的人力与机器;规模上去之后才反过来。分界线大致在”是否需要专人运维”这个判断上。

“向量库能顺带做全文检索。” 多数系统的全文能力是后来补的,和成熟的搜索引擎不在一个水平。混合检索是刚需时,选型的天平应该偏向搜索出身的系统。

参考

  • pgvector — HNSW 与 IVFFlat 索引、向量类型与维度上限、迭代式索引扫描(README 中的过滤算术)
  • pgvectorscale — 基于 DiskANN 思路的 Postgres 向量索引扩展
  • Qdrant — 过滤感知检索、量化、稀疏与多向量支持
  • Milvus — 分布式架构、索引类型清单与 GPU 索引
  • Weaviate — 混合检索、多租户与向量压缩
  • Vespa — 排序表达式与向量检索的结合
  • Elasticsearch / OpenSearch — dense_vector 与混合检索,注意两者的许可差异
  • Redis — 向量检索能力与各版本的许可差异(LICENSE 中列明)
  • LanceDB — 嵌入式列式向量库
  • Chroma — 轻量嵌入式向量库
  • Typesense — GPL-3.0 的检索引擎,README 中有许可选择的解释
  • Meilisearch — MIT,全文加语义的混合检索
  • ClickHouse 向量相似度索引文档 — 基于 usearch 的 HNSW 索引
  • Apache Doris 向量检索文档 — 4.0 起的 ANN 索引、pre-filter 语义、量化对比与压测数据
  • DuckDB — 嵌入式分析数据库,向量检索由 VSS 扩展提供
  • sqlite-vec — SQLite 的向量检索扩展
  • FAISS / hnswlib / DiskANN / cuVS / USearch — 索引库而非数据库
  • Annoy — 早期的内存型索引,仓库更新已放缓
  • Pinecone 文档 — serverless 架构与存储计算分离

文章作者: Halensea
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Halensea !
 本篇
向量存储 向量存储
向量存储不只是"存向量"——它要在一个不能同时满足召回、延迟、内存的三角里做取舍,还要把标量过滤、增删改、权限和一致性一并解决。索引结构决定了前一半,工程能力决定了后一半
2026-10-20
下一篇 
RAG从文档切分到答案引用 RAG从文档切分到答案引用
检索增强生成要解决的不是"让模型知道更多",而是在一个固定的上下文预算里,从百万级片段中挑出真正该进窗口的那几个——这是一个排序问题,也是一个误差会逐级累积的工程链路
2026-10-20
  目录