1. 什么是量化
当 ES 的向量搜索规模在亿级甚至十亿级时,我们面临两个挑战:内存占用高和计算速度慢。ES 的向量量化是此时的重要优化策略,它巧妙结合了量化的速度优势和原始向量的精度优势,在性能和准确率之间取得平衡。量化(Quantization)本质是一种有损压缩技术,核心思想是将高精度的向量数据(通常是 32 位浮点数,float)转换为低精度表示(如 8 位整数,int8),它可以在召回率损失很少的情况下,大幅降低内存使用并提高查询速度。
2. 量化的内存和存储占用变化
如果您在索引 Mapping 设置中指定了量化,ES 在构建索引时除了生成原始精度数据存储外(假设为float32),还会额外生成一份对 float32 的量化精度数据存储。因此对于 float32 向量,int8, int4, bbq 量化分别可以将所需内存减少 4、8、32 倍,但也会降低向量精度并增加磁盘空间(分别增加 25%、12.5% 或 3.125%)。例如当使用 int8 量化 40GB 的浮点向量时,量化后的向量将额外占用 10GB 的磁盘空间,总磁盘使用量为 50GB,但内存使用量将减少到 10GB。
3. 量化的粗排与过采样
为了解决量化带来的精度损失问题,ES 的向量搜索分为了近似粗排和精确精排两个阶段:
粗排阶段:ES 使用量化后的查询向量,在基于量化数据构建的 HNSW 图索引上搜索,在每个分片完成搜索后,会得到一个包含 num_candidates 个文档 ID 和近似得分的列表。
精排阶段:通过设置 rescore_vector 指定 oversample 过采样系数,ES 将对每个分片返回的num_candidates个文档中的前 k*oversample 个文档,从磁盘上读取原始的 float32 向量,使用原始查询向量与这些原始文档向量进行高精度相似度计算,从中选出 Top k 个结果。
显然,过采样机制结合了使用量化向量进行近似检索的性能和内存优势,和使用原始向量对最佳候选者进行重新评分的准确性。实际上int8通常不需要过采样,int4通过设置1.5-2倍可以获得更高的精确度和召回率,bbq通常需要过采样,3×–5× 过采样通常足够了。
4. 量化的召回率评估
就我们的实践经验而言,不量化情况下召回率99%的话,int8量化召回率约96-97%,bbq量化召回率约90-94%,您需要特别留意,量化的召回率和数据规模有较高的相关性,数据集越大,量化带来的召回率损失越小,反之则越大。因此您应该在尽量大的数据集上来验证最终的召回率效果。
5. 举例
// Mapping 设置(向量采用 int8 量化)PUT /my-quantized-index{"mappings": {"properties": {"title": {"type": "text"},"title_vector": {"type": "dense_vector","dims": 768,"index": true,"similarity": "cosine","index_options": {"type": "int8_hnsw", // 启用 8位标量量化 HNSW 索引"m": 16,"ef_construction": 100}}}}}// 向量搜索(过采样)GET my-quantized-index/_search{"knn": {"field": "title_vector","query_vector": [0.15, 0.50, ..., 0.05], // 查询向量"k": 10, // 返回的 top k 结果数"num_candidates": 100, // 需要 >= k"rescore_vector": {"oversample": 2.0 // 过采样系数}}}