【存储工程】向量存储与 ANN 索引
内容提要
本文介绍近似最近邻搜索(ANN)在向量检索中的应用,涵盖暴力搜索、KD-Tree、LSH、HNSW及量化方法,并讨论FAISS索引选型、向量数据库架构及RAG场景实践。强调高维向量检索需平衡精度与速度,常用HNSW或IVF-PQ索引,并注意基准测试陷阱,以Recall@K评估质量。
延伸解读
高维检索为何必须近似
文章用维度灾难解释了高维向量检索的难点:当维度从2增至768时,最远与最近点距离比从48倍缩至1.3倍,精确最近邻失去区分度。这意味着KD-Tree等空间划分索引在高维下退化,暴力搜索虽精确但耗时巨大。因此工程上必须接受近似,用Recall@K衡量质量,以换取可接受的延迟。理解这一前提,有助于合理设定检索精度目标。
索引选型需权衡内存与召回
文章对比了Flat、IVF、PQ、HNSW等索引:Flat精确但内存高、查询慢;IVF通过粗量化缩小搜索范围;PQ大幅压缩内存但召回下降;HNSW无需训练、支持增量,但内存占用大。选型决策树建议:数据量小用Flat,内存充足用HNSW或IVF-Flat,内存紧张用IVF-PQ或SQ8。实际需根据业务的内存、延迟和召回要求权衡。
基准测试的常见陷阱
文章指出向量数据库基准测试易误导:只看QPS忽略Recall、只测离线批量查询、不测过滤场景、训练与查询数据同分布、忽略构建成本等。正确做法是在固定Recall下比较QPS,使用真实查询分布,测量p99延迟,并包含过滤场景。建议使用ann-benchmarks或VectorDBBench,但最终应构建贴合自身场景的基准测试。
RAG中向量检索的实践要点
在RAG管线中,向量检索质量直接影响最终答案。文章建议:分块大小256-512 token较合理;混合检索(向量+BM25)可提升专有名词查询的召回;重排序用交叉编码器但只对候选集进行;索引类型根据文档量选择,数据量大时需分布式数据库。此外,嵌入模型选择应基于自身数据测试,而非仅看排行榜。
Q&A
什么是近似最近邻搜索(ANN)?为什么需要它?
近似最近邻搜索(ANN)是一种在可接受的精度损失下,快速找到与查询向量最相似向量的方法。它通过牺牲一定的召回率来换取检索速度,将时间复杂度从线性降低到亚线性或对数级别。在深度学习时代,文本、图像等数据被编码为高维向量,ANN 成为搜索引擎、推荐系统和 RAG 等应用的核心技术。
向量检索中常用的相似度度量有哪些?如何选择?
常用的相似度度量有欧氏距离(L2)、余弦相似度和内积(IP)。欧氏距离适合绝对距离有物理意义的场景,如图像特征;余弦相似度关注方向,适合文本嵌入,实际中常通过L2归一化后用内积计算;内积在向量未归一化时还编码幅度信息,适合推荐系统。选择时需注意索引构建和查询必须使用同一种度量。
什么是维度灾难?它对向量索引有什么影响?
维度灾难是指随着向量维度增加,所有数据点之间的距离趋于相等,导致最近邻与最远邻的区分度下降。这使得基于空间划分的索引(如KD-Tree)在高维下退化为暴力搜索,精确最近邻搜索变得不可行。因此,高维向量检索必须采用近似方法,并用Recall@K等指标衡量质量。
HNSW索引的工作原理是什么?它有哪些优缺点?
HNSW(分层可导航小世界图)通过构建多层图结构,高层提供远程导航,底层进行精细搜索。查询时从顶层开始贪心搜索,逐层下降。优点是查询速度快、召回率可调(通过efSearch)、支持增量插入;缺点是内存占用大、构建慢、删除困难。
乘积量化(PQ)是如何压缩向量的?它有什么代价?
乘积量化将高维向量切分为多个子向量,对每个子空间独立进行K-Means聚类,用聚类中心的索引(通常1字节)编码子向量,从而大幅压缩存储。例如768维float32向量可压缩64倍。代价是召回率下降,通常Recall@10在0.5-0.7之间。
FAISS中如何选择索引类型?
选择索引类型需考虑数据量、内存、召回率要求等。数据量小于10万可用Flat;内存充足且需增量插入可选HNSW;内存不足时,若要求高召回率可用IVF+SQ8,否则用IVF+PQ。还可通过OPQ预处理或两阶段检索提升精度。
向量数据库相比FAISS等索引库有哪些优势?
向量数据库在索引库基础上提供了持久化、分布式、元数据过滤、CRUD、多租户等完整数据库能力。例如Milvus支持存算分离、日志即数据、读写分离;Qdrant支持WAL和Raft分片;Pinecone提供托管服务。
在RAG系统中,如何优化向量检索环节?
优化RAG向量检索包括:合理分块(256-512 token)、采用混合检索(向量+BM25)提升专有名词召回、使用交叉编码器重排序、根据文档量选择索引类型、定期重建索引、考虑多向量检索等。
向量数据库基准测试有哪些常见陷阱?
常见陷阱包括:只看QPS不看Recall、只测离线批量查询、不测过滤场景、训练和查询数据分布相同、忽略索引构建时间。正确做法是在固定Recall下比较QPS,使用真实查询分布,测量p99延迟,并包含过滤和并发场景。