行业资讯
HNSW 向量索引为什么又快又准?M、efConstruction、efSearch 调优实战
HNSW 向量索引为什么又快又准M、efConstruction、efSearch 调优实战向量库已经建好查询也从秒级降到了毫秒级但召回率忽高忽低把参数调大又发现内存和 P95 延迟一起上涨——这通常不是模型问题而是 HNSW 的三个核心参数没有按阶段调。本文不背参数表而是从一次查询如何在图中移动讲起再给出一套可复现的 pgvector 建索引、检索与 RecallK 调优流程。一、HNSW 到底解决了什么问题有 N 条 d 维向量时精确检索需要计算查询向量与大量候选的距离朴素代价近似为 O(Nd)。它结果最准确却很难在千万级数据和高并发下保持低延迟。HNSWHierarchical Navigable Small World把向量组织成“可导航的小世界图”相似向量互相连边再叠加多层结构。上层节点少、边跨度大用来快速接近目标区域越往下节点越密最终在 Layer 0 做精细搜索。它牺牲极少量精确性换取显著减少的距离计算次数。图 1HNSW 的“高速路 街区”结构。原创教学图Image2 生成用于解释层级、入口点和下降路径。一个好记的类比是上层像城市高速路负责跨区域跳转底层像街区道路负责找到具体门牌。没有上层搜索容易在局部图里走很久底层不够连通又可能错过真正的近邻。pgvector 官方也明确说明HNSW 创建的是多层图与 IVFFlat 相比它通常有更好的速度—召回率权衡但建索引更慢、占用更多内存而且不需要预先训练。图 2pgvector README 中的 HNSW 说明。来源pgvector 项目原始页面https://github.com/pgvector/pgvector二、一次查询是怎样跑完的查询从最高层入口点开始每一步比较当前节点的邻居向距离查询向量更近的节点移动当本层无法继续改善时就从当前节点下降一层。到 Layer 0 后不再只保留单一路径而是维护一个候选队列扩展更多近邻最后返回距离最小的 Top-K。图 3从入口点到 Top-K 的搜索路径。原创教学图Image2 生成。候选队列Layer 0上层稀疏图查询向量 q候选队列Layer 0上层稀疏图查询向量 qloop[每个上层]loop[候选数未超过 efSearch]从入口点开始1贪心移动到更近节点2下降一层3放入入口及其近邻4取当前最近候选并扩展邻居5更新候选与已访问集合6按距离返回 Top-K7这里最关键的是HNSW 不是“沿一条线走到底”。上层采用近似贪心导航底层通过候选队列保留多条可能路径。候选越多越不容易被局部最优误导但需要计算的距离也越多。三、M、efConstruction、efSearch 分别控制什么1. M图的连接密度M控制每层节点允许保留的最大连接数。M 较大时图更连通搜索有更多路线召回上限通常更高代价是索引更大、构建和查询时需要处理更多边。它属于索引结构参数修改后通常需要重建索引。2. efConstruction建图时看多远efConstruction是插入节点、选择邻居时使用的动态候选列表大小。数值越大建图时比较的候选越多图质量通常更高但建索引时间和写入成本也会上升。它影响的是图的先天质量不能靠查询时临时修改来补全所有结构缺陷。3. efSearch每次查询看多少候选efSearch是查询阶段的动态候选列表大小也是最适合在线调节的旋钮。增大它通常提高召回率同时增加查询延迟。pgvector 默认值为 40可在事务中用SET LOCAL只调整当前查询。图 4pgvector 官方给出的 M、ef_construction 与 hnsw.ef_search 含义及默认值。来源pgvector 项目原始页面https://github.com/pgvector/pgvector#hnsw图 5三个参数的生效阶段与主要代价。原创教学图Image2 生成。一句话区分M 决定路网密度efConstruction 决定修路认真程度efSearch 决定这次导航愿意探索多少条路。四、用 pgvector 跑通一个可调优示例下面以 768 维余弦距离为例。索引操作符类与查询运算符必须匹配vector_cosine_ops对应余弦距离运算符。CREATEEXTENSIONIFNOTEXISTSvector;CREATETABLEdocuments(id bigserialPRIMARYKEY,titletextNOTNULL,embedding vector(768)NOTNULL);CREATEINDEXdocuments_embedding_hnswONdocumentsUSINGhnsw(embedding vector_cosine_ops)WITH(m16,ef_construction100);ANALYZEdocuments;查询时把目标向量绑定为参数不要把长向量直接拼接进 SQLBEGIN;SETLOCALhnsw.ef_search100;SELECTid,title,1-(embedding$1::vector)AScosine_similarityFROMdocumentsORDERBYembedding$1::vectorLIMIT10;COMMIT;注意要让 HNSW 索引参与近邻查询通常需要ORDER BY使用距离运算符本身并配合LIMIT。不要只写ORDER BY 1 - distance DESC后就默认规划器一定能识别为同一种索引排序。五、正确调参先建立精确基准再扫 efSearch没有“标准答案参数”。向量分布、维度、数据量、Top-K、过滤比例、并发量与硬件都会改变最优点。可靠方法是用业务查询集画出召回率—延迟曲线。定义 RecallKRecallK |近似检索 Top-K ∩ 精确检索 Top-K| / K建议按以下顺序测试从真实流量抽取有代表性的查询向量至少覆盖热门、长尾与过滤查询。用精确检索生成每个查询的 Top-K 基准答案。固定 M 和 efConstruction依次测试 efSearch40、80、120、200。同时记录 RecallK、P50/P95/P99、QPS、CPU、索引大小和构建时间。找到满足召回目标的最小 efSearch若继续增大仍到不了目标再提高 M 或 efConstruction 并重建索引。否否是是否是准备代表性查询集用精确检索生成 Top-K 基准建立 HNSW 索引并记录大小与构建时间依次测试 efSearch40、80、120、200召回率达标吗提高 efSearch 后仍无明显提升提高 M 或 efConstruction 并重建索引P95 延迟达标吗降低 efSearch 或优化过滤条件固定参数并持续监控召回与延迟可作为第一轮实验起点而不是生产环境定论场景MefConstructionefSearch 扫描区间百万级、内存敏感1664–10040 / 80 / 120更重视召回率24–32100–20080 / 120 / 200Top-K 较大先从 16–24 开始100–200不低于 K并继续向上扫描六、带过滤条件时为什么结果可能突然变少普通 HNSW 先沿向量图找候选再应用属性过滤时候选可能大量被过滤掉。过滤越严格最终不足 K 条的概率越高。此时单纯增加 efSearch 有时有效但会增加延迟更稳妥的方案还包括为过滤字段建立 payload/关系索引、使用分区以及采用支持过滤感知或迭代扫描的实现。图 6Qdrant 官方对过滤搜索与 HNSW 图连通性问题的说明。来源Qdrant Documentation原始页面https://qdrant.tech/documentation/manage-data/indexing/#filterable-hnsw-index在 pgvector 中过滤通常在索引扫描后应用。新版 pgvector 提供 iterative index scans可在结果不足时继续扫描但启用前仍应先给高选择性过滤字段建立普通索引并检查执行计划。七、最常见的五个误区只看延迟不测召回率10 ms 的错误结果没有业务价值。efSearch 小于 Top-K 还期待稳定结果至少让候选规模覆盖 K再用实测决定余量。修改 M 后不重建索引M 和 efConstruction 是建图阶段参数。把参数调大当成必然线性收益收益会递减延迟和内存却继续增加。忽略过滤条件与数据更新过滤、删除、写入和数据分布漂移都会改变曲线。总结HNSW 的速度来自分层导航准确性来自底层候选扩展。调优时牢记三个层次M 决定图的连接能力与内存成本efConstruction 决定建图质量与构建成本efSearch 决定单次查询的召回率—延迟取舍。最实用的顺序是**精确检索建立基准 → 扫描 efSearch → 观察召回与 P95 → 召回上限不足时再调整 M、efConstruction 并重建。**这样得到的不是“网上推荐参数”而是适合自己数据的可验证配置。
郑州网站建设
网页设计
企业官网