ARTICLE DETAIL

资讯详情

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

揭秘亿级向量背后的毫秒级检索:Qdrant 的 HNSW 向量索引是如何跑起来的

揭秘亿级向量背后的毫秒级检索:Qdrant 的 HNSW 向量索引是如何跑起来的 揭秘亿级向量背后的毫秒级检索Qdrant 的 HNSW 向量索引是如何跑起来的【免费下载链接】qdrantQdrant - High-performance, massive-scale Vector Database and Vector Search Engine for the next generation of AI. Also available in the cloud https://cloud.qdrant.io/项目地址: https://gitcode.com/GitHub_Trending/qd/qdrant向量数据到千万级以后逐个比对的相似性检索就撑不住了一次查询要硬算上千万次距离。向量数据库 Qdrant 用 HNSW 这种分层图索引解决它——第一跳直接跳到目标附近再逐层精确定位让海量数据也能毫秒级返回。读代码之前先搞懂 HNSW一张三级快递网想象往全国寄快递。邮政系统不会让每个分拣中心两两直连而是三级网络干线飞机顶层全国枢纽极少但每个枢纽覆盖面极大一跳就跨越大半个国家城际高铁中层每个城市只连自己的几个邻居几跳就到省最后一公里货车底层覆盖每条街巷最后把件送到门口HNSW 就是这种分层地图层数越高节点越少但每个节点看得更远给下层当捷径。贪婪下探搜索从最顶层入口出发每层贪婪地走向最近的节点再下探全程不扫全图随机定层新向量插入时用概率决定它最高能到第几层越高层概率越低天然维持上疏下密小数据退化暴力数据量小时暴力扫一遍比查图更快Qdrant 按阈值自动切换策略这个索引住在集合的哪个位置它在每个 Segment存储段内部段是 Qdrant 建索引和做优化的最小单位HNSWIndex 结构体走读图和向量被刻意拆开最能代表实现的核心结构是 hnsw.rs 里的HNSWIndex。看这个结构体要回答的问题是图在哪、向量在哪、过滤搜索靠什么。先看一眼全貌——图里只存谁连谁的拓扑向量本体根本不在图里pub struct HNSWIndex { id_tracker: ArcAtomicRefCellIdTrackerEnum, vector_storage: ArcAtomicRefCellVectorStorageEnum, quantized_vectors: ArcAtomicRefCellOptionQuantizedVectors, payload_index: ArcAtomicRefCellStructPayloadIndex, config: HnswGraphConfig, path: PathBuf, graph: GraphLayers, // 图本体 searches_telemetry: HNSWSearchesTelemetry, is_on_disk: bool, }逐字段理解id_tracker记录哪些点还活着vector_storage存向量本体quantized_vectors是可选的压缩副本在压缩版上打分会更省算力事后再用原向量精排payload_index负责过滤搜索graph才是图本身。图与向量分离就是 Qdrant 能把索引放磁盘上的根基只有图需要常驻向量按需读取。再钻进图内部graph_layers.rs 的GraphLayers只有四个成员pub struct GraphLayers { pub(super) hnsw_m: HnswM, pub(super) links: GraphLinks, // 邻接表节点连向哪些节点 pub(super) entry_points: EntryPoints, // 每层的入口点 pub(super) visited_pool: VisitedPool, // 访问表对象池 } pub const HNSW_GRAPH_FILE: str graph.bin; // 入口与构建参数 pub const HNSW_LINKS_FILE: str links.bin; // 邻接表本体看完应该理解两件事图在磁盘上拆成两个文件graph.bin存参数和入口点links.bin存邻接表真正允许上磁盘的只有邻接表visited_pool则是把每次查询要用的已访问标记表做成对象池复用高 QPS 下不产生分配抖动。工程取舍三个决定构建速度和内存占用的决策其一前 256 个点单线程其余并行。HNSW 全并行构建有个经典坑多线程同时往空图里插点容易形成断开的孤岛召回率下降。build.rs 的策略是分两段走pub const SINGLE_THREADED_HNSW_BUILD_THRESHOLD: usize 256; // 发布构建 // ① 前 256 个点单线程逐个插入 for vector_id in first_few_ids { insert_point(vector_id)?; } // ② 剩下的交给 Rayon 线程池并行插入 if !ids.is_empty() { pool.install(|| ids.into_par_iter().try_for_each(insert_point))?; }单线程先铺一个小而连通的种子核后续并行线程都有稳定锚点可插图连通性和构建速度两头都要。debug 构建里这个阈值是 32方便在测试里更快复现连通性问题。其二邻接表住哪三档开关。邻接表links占了 HNSW 索引的大部分内存。hnsw.rs 里把用户配置的memory映射为三种驻留策略let memory hnsw_config.memory_placement().clamp_to_low_memory(); let residency match memory { Memory::Cold GraphLinksResidency::Cold, // 从磁盘懒加载 Memory::Cached GraphLinksResidency::Cached, // 预热进页缓存 Memory::Pinned GraphLinksResidency::Pinned, // 常驻堆内存不驱逐 }; let graph GraphLayers::load(path, residency, do_convert)?;Cold 换容量Pinned 换延迟取舍在两者之间。值得注意clamp_to_low_memory()节点整体进入低内存模式时Pinned 会被悄悄降级成 Cold——索引照样能跑只是慢一点用户无感。此外代码里还有压缩版邻接表links_compressed.bin进一步压小磁盘占用。其三改配置不等于推倒重建。参数变化需要重建时代码先尝试复用旧图GraphLayersHealer把旧节点映射到新节点、逐条修补边只对增量新点执行插入。这正是 Qdrant 的索引优化是平滑的后台过程而不是停机重建索引参数怎么调四个真正关键的旋钮config.rs 里的参数不多真正需要关心的就四个参数作用推荐值影响m上层每节点连接数底层自动翻倍为 2×m16越大召回越高、图越大、构建越慢ef_construct构建时的候选集宽度100越大图质量越好、构建越久full_scan_threshold低于此向量数直接暴力扫默认 20KB内部按向量大小换算成条数越大越多查询走暴力扫、省建图开销max_indexing_threads建图线程数2~8越大构建越快、构建期 CPU 越满按数据量选组合十万向量以下不用调或把 full_scan_threshold 调大让暴力扫描兜底建图开销近乎为零百万~千万、在线低延迟m16、ef_construct100 起步memory设 Cached 预热页缓存千万以上、内存紧张m16、memory设 Cold 让邻接表落盘用一点延迟换内存容量full_scan_threshold容易误解配置时以 KB 为单位但 hnsw.rs 会先除以平均向量大小换算成向量条数同一份配置在不同维度下依然成立。定位搜索瓶颈时项目自带性能剖析工具链可以用调用图看时间花在哪场景怎么选什么数据适合 HNSW、什么时候别用适合大规模近似检索千万到十亿级向量、在线毫秒级 P99是 HNSW 的主场带过滤的检索Qdrant 把 payload 过滤索引直接织进图搜索——graph_layers.rs 里有专门的 ACORN 过滤搜索变体而不是先找邻居再筛高选择率条件下召回不塌稠密稀疏混合同一集合可并存稠密与稀疏向量字段各自走对应索引不适合极小数据集十万以下暴力扫描够用建 HNSW 图纯属白花钱要求 100% 精确召回它是近似算法严苛场景需配合暴力校验或量化重排写多读极少建图有成本超高写入率下构建与优化会持续占用资源与同类方案的差异点相比FAISS 当索引引擎 外面再包一层过滤的做法Qdrant 的特征是把过滤搜索、量化打分、磁盘驻留都当索引内部的一等公民——量化副本和 payload 索引是HNSWIndex的直系成员图邻接表可以落盘、可以压缩。所以它能在图常驻、向量在盘的姿态下扛住千万级规模。收尾Qdrant 的 HNSW 就三件事分离、取舍、不停机——图与向量拆开、按内存选驻留、重建时迁移旧图。演进方向代码里已能读到GPU 加速构建、压缩邻接表、更激进的降内存策略。【免费下载链接】qdrantQdrant - High-performance, massive-scale Vector Database and Vector Search Engine for the next generation of AI. Also available in the cloud https://cloud.qdrant.io/项目地址: https://gitcode.com/GitHub_Trending/qd/qdrant创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表