ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

05-向量索引原理:暴力检索、IVF、HNSW 索引加速

05-向量索引原理:暴力检索、IVF、HNSW 索引加速 向量索引原理暴力检索、IVF、HNSW 索引加速作者黒漂技术佬 | 理解索引才算真正理解向量数据库为什么需要索引向量数据库的核心操作是给定一个查询向量在 N 条向量中找到最相似的 TopK 条。最直接的方法是逐条计算相似度排序取前K。这叫暴力检索Flat简单粗暴但慢——N 条向量就要算 N 次相似度。1万条还行100万条就要算100万次1亿条……你自己算吧。索引的存在就是为了解决这个问题用空间结构加速邻近查找让你不用遍历全部向量就能定位到候选集。代价是索引可能漏掉少数真正最近邻的向量精度损失但换来的是几个数量级的速度提升。这就是 ANN近似最近邻的核心思想——用可接受的精度损失换取不可接受的速度差距。暴力检索Flat IndexFlat 索引就是不做任何优化直接存所有向量查询时逐条计算相似度。查询向量 Q ↓ 遍历全部N条向量逐个计算相似度 ↓ 排序取TopK ↓ 返回结果特点精度 100%没有漏掉任何向量速度 O(N)N 越大越慢内存占用 向量原始大小没有额外开销适用场景数据量小几千到几万条精度要求绝对不能有损。在无人售货柜场景商品只有50种每种拍3张参考图总共150条向量——Flat 索引完全够用150次计算眨眼完成没必要搞复杂索引。FAISS 中创建 Flat 索引importfaiss# 内积索引向量已归一化时等价余弦相似度indexfaiss.IndexFlatIP(512)# L2距离索引indexfaiss.IndexFlatL2(512)index.add(vectors)# 直接添加所有向量D,Iindex.search(query,k5)# 暴力搜索IVFInverted File索引IVF 的核心思想先分组再组内搜索。想象你在一座大城市找最近的便利店。暴力做法是挨家挨户敲门问IVF 的做法是先把城市分成若干区域你先定位到最近的几个区域然后只在这几个区域里搜索。原理聚类分组用 K-means 对所有向量做聚类分成nlist个组每个组叫一个桶建立倒排表每个桶记录属于该桶的所有向量 ID查询时计算查询向量与各聚类中心的距离找到最近的nprobe个桶只在这些桶内做 Flat 检索全部向量 → K-means聚类 → nlist个桶 ↓ 查询向量 → 找最近nprobe个桶 → 桶内暴力检索 → TopK结果关键参数nlist聚类数量通常设为 sqrt(N) 到 4×sqrt(N)nprobe查询时搜索的桶数越大精度越高、速度越慢nprobe 的调节是 IVF 的精髓nprobe1 只搜1个桶速度极快但精度低nprobenlist 搜全部桶等价于暴力检索实际中 nprobe 取 10-50在速度和精度间取得平衡。# FAISS IVF 索引nlist100# 聚类数quantizerfaiss.IndexFlatL2(512)# 聚类用Flat索引indexfaiss.IndexIVFFlat(quantizer,512,nlist)# 先训练K-means聚类index.train(vectors)index.add(vectors)# 搜索时设置nprobeindex.nprobe10# 搜索10个桶D,Iindex.search(query,k5)注意IVF 索引需要先train——这是 K-means 聚类的过程数据量太少低于 nlist×30聚类效果差IVF 反不如 Flat。适用场景数据量中等到大几十万到几百万需要速度和精度的平衡。HNSWHierarchical Navigable Small WorldHNSW 是目前向量索引的明星算法速度和精度都顶尖。核心思想多层跳表式图结构从粗到细逐层搜索。原理HNSW 构建了一个多层图顶层少量节点长距离连接——用于粗筛快速跳到查询向量附近的大区域中间层节点渐多连接渐密——逐层缩小搜索范围底层全部节点短距离连接——精搜找到真正最近邻顶层(Layer 2): ○ —— ○ —— ○ 稀疏连接大范围跳跃 ↓ 中层(Layer 1): ○—○—○—○—○—○ 中等密度缩小范围 ↓ 底层(Layer 0): ○○○○○○○○○○○○ 密集连接精确搜索搜索过程从顶层随机入口节点开始在当前层贪心搜索每次跳到离查询向量更近的邻居节点当当前层无法再更近时下降到下一层重复直到底层在底层做精搜返回 TopK就像你在地图上找一家店先看省界级别的大范围定位顶层再看城市级别缩小范围中层最后在街区级别精确定位底层——层层递进不用遍历整张地图。关键参数M每个节点的最大邻居数影响图的密度。常用值 16-64efConstruction建图时的搜索宽度越大图质量越高、建图越慢。常用值 200-500efSearch查询时的搜索宽度越大精度越高、查询越慢。常用值 50-200# FAISS HNSW 索引indexfaiss.IndexHNSWFlat(512,M32)# M32邻居数index.hnsw.efConstruction200# 建图参数index.hnsw.efSearch100# 搜索参数index.add(vectors)D,Iindex.search(query,k5)特点查询速度快比 IVF 快 2-10倍精度高召回率通常 95%内存占用比 IVF 大图的连接关系需要存储增量添加向量方便不需要重新训练适用场景数据量大百万级以上对查询速度和精度都有高要求。智慧农业平台存储百万级作物病害图片特征——HNSW 让检索从秒级降到毫秒级病害识别响应速度大幅提升。PQProduct Quantization向量压缩PQ 不是索引而是向量压缩技术通常跟 IVF 组合使用IVFPQ解决内存不够的问题。原理把一个高维向量切成 M 个子段每个子段独立量化用少量代表值近似原始值。比如一个 512 维向量原始: [v1, v2, ..., v512] → 每个值占4字节 → 总共2048字节 PQ: 切成M8段每段64维 每段用256个代表值(codebook)近似 → 每段只存1字节(code ID) 总共8字节 → 压缩256倍代价相似度计算不再精确而是近似——但近似在 ANN 世界里本来就是常态PQ 只是在压缩维度上又加了一层近似。# FAISS IVFPQ 索引nlist100m8# PQ子段数quantizerfaiss.IndexFlatL2(512)indexfaiss.IndexIVFPQ(quantizer,512,nlist,m,8)# 每子段8bitindex.train(vectors)index.add(vectors)index.nprobe10D,Iindex.search(query,k5)适用场景内存受限、数据量极大。比如嵌入式设备只有 2GB 内存却要存 100 万条 512 维向量——原始向量需要 2GBIVFPQ 只需要几十MB。索引选择策略数据量内存充足内存受限推荐索引1万——Flat精确够快1万-100万充足—IVF平衡速度精度100万充足—HNSW快速高精度100万—受限IVFPQ压缩加速嵌入式端—受限IVFPQ或 Flat选择逻辑很简单数据量小 → Flat别折腾数据量中等 → IVF调 nprobe 控制精度/速度数据量大、内存充足 → HNSW速度精度双优数据量大、内存不够 → IVFPQ压缩存储别过度优化——50条向量用 HNSW建图时间比检索时间还长100万条向量用 Flat一次检索能让你等到怀疑人生。选索引就像选车通勤5公里骑自行车就行别开坦克。各索引原理图示┌─────────────────────────────────────────────────────┐ │ Flat: 查询 → 遍历全部向量 → 排序 → TopK │ │ 精度:★★★★★ 速度:★☆☆☆☆ 内存:★★☆☆☆ │ │ 适合: 小数据量 │ ├─────────────────────────────────────────────────────┤ │ IVF: 查询 → 定位nprobe个桶 → 桶内遍历 → TopK │ │ 精度:★★★★☆ 速度:★★★★☆ 内存:★★★☆☆ │ │ 适合: 中等数据量 │ ├─────────────────────────────────────────────────────┤ │ HNSW: 查询 → 顶层粗跳 → 逐层精搜 → 底层TopK │ │ 精度:★★★★★ 速度:★★★★★ 内存:★★★★☆ │ │ 适合: 大数据量、高要求 │ ├─────────────────────────────────────────────────────┤ │ IVFPQ: 查询 → 定位桶 → 压缩向量近似计算 → TopK │ │ 精度:★★★☆☆ 速度:★★★★☆ 内存:★☆☆☆☆ │ │ 适合: 大数据量、内存受限 │ └─────────────────────────────────────────────────────┘实际工程中先用 Flat 验证业务可行性数据量增长后再换 IVF 或 HNSW。索引可以随时重建但业务逻辑别一开始就绑定某种索引——让数据量决定索引选择而不是反过来。
返回列表