尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

RAG 必学:ANN 检索、HNSW 算法与 Milvus 核心概念详解

RAG 必学:ANN 检索、HNSW 算法与 Milvus 核心概念详解 目录向量存到哪里为什么普通数据库不够用最直觉的方案用 MySQL 存向量近似最近邻搜索向量检索的核心算法怎么不用逐个比较就能找到最相似的IVF倒排文件索引先分区再搜索2.1 IVF 的工作原理2.2 IVF 的优缺点HNSW分层可导航小世界图最主流的索引算法3.1 HNSW 的核心思想多层图结构3.2 用一个具体例子走一遍 HNSW 的检索过程3.3 为什么 HNSW 这么快3.4 HNSW 的代价内存占用索引算法对比怎么选主流向量数据库对比与选型主流方案对比为什么选 MilvusMilvus 核心概念和传统数据库做类比Collection 表Schema 表结构2.1 向量字段和标量字段的区别Index 索引Partition 分区一张图看懂 Milvus 的数据组织实际项目中的关键决策索引类型怎么选相似度度量怎么选分区策略设计性能调优的几个关键参数5.1 HNSW 索引参数5.2 IVF 索引参数小结与下一篇预告向量存到哪里为什么普通数据库不够用最直觉的方案用 MySQL 存向量既然向量就是一组浮点数那最直觉的想法就是——存 MySQL 呗。方案很简单在表里加一个TEXT或JSON字段把向量序列化成字符串存进去。检索的时候把所有向量读出来在应用层逐个计算余弦相似度排序取 Top-K。暴力搜索在数据量小的时候没问题但一旦数据量和并发量上去就完全不可用了。近似最近邻搜索答案是可以。这就是ANNApproximate Nearest Neighbor近似最近邻搜索的核心思想。注意这里的关键词是“近似”——ANN 不保证找到的一定是全局最相似的向量但它能在极短的时间内找到非常接近最优解的结果。打个比方暴力搜索就像你要在一个 100 万人的城市里找和你最像的人挨个去比对。ANN 则是先按区域划分再按特征缩小范围最后只在一小撮人里精确比较。你可能会错过某个住在偏远角落的“最佳匹配”但你找到的人已经足够像了而且速度快了几百倍。用数字来感受一下差距指标暴力搜索ANN 检索100 万向量查询耗时2~5 秒1~10 毫秒召回率Recall100%精确95%~99%近似是否需要专门索引不需要需要适用数据量 10 万百万~亿级1~10 毫秒 vs 2~5 秒速度差了几百到几千倍而召回率只损失了 1%~5%。在实际的 RAG 场景中这点精度损失几乎感知不到——你本来就是取 Top-K 个结果丢给大模型做参考少了一个排名第 47 的 chunk 对最终回答没有影响。这就是向量数据库存在的核心理由它不只是存向量更重要的是提供高效的 ANN 检索能力。普通数据库能存向量但做不了高效的 ANN 检索。一句话概括向量数据库 向量存储 ANN索引 高效检索。它是专门为“在海量向量中快速找到最相似的那几个”这件事而设计的。向量检索的核心算法怎么不用逐个比较就能找到最相似的两种最主流的 ANN 索引算法IVF 和 HNSW。IVF倒排文件索引先分区再搜索IVF 的全称是 Inverted File Index倒排文件索引。名字听起来很学术但思路非常直觉。2.1 IVF 的工作原理IVF 的核心思想就一句话把向量空间划分成若干个区域查询时只在最可能的几个区域里搜索。具体怎么做分两个阶段建索引阶段离线用聚类算法通常是 K-Means把所有向量分成nlist个簇cluster每个簇有一个中心点centroid代表这个簇里所有向量的平均位置每个向量被分配到离它最近的那个簇检索阶段在线拿到查询向量后先计算它和所有簇中心点的距离找到最近的nprobe个簇nprobe 是一个可调参数只在这nprobe个簇里的向量中做精确搜索2.2 IVF 的优缺点HNSW分层可导航小世界图最主流的索引算法HNSW 的全称是 Hierarchical Navigable Small World Graph分层可导航小世界图。名字很长但它是目前最主流、效果最好的 ANN 索引算法几乎所有向量数据库都把它作为默认或推荐的索引类型。3.1 HNSW 的核心思想多层图结构要理解 HNSW先从一个生活场景开始。假设你要找一个住在北京朝阳区、会写 Java、喜欢打篮球的人但你手上没有任何名单只能通过社交关系去找。你会怎么做你不会挨个问全中国 14 亿人。你会这样先在你认识的人里找——“谁在北京”——你的朋友老王在北京问老王——“你认识朝阳区的人吗”——老王介绍了他同事小李问小李——“你认识会写 Java 的人吗”——小李介绍了他的大学同学张三张三恰好也喜欢打篮球——找到了每一步你都在靠近目标而且每一步只需要问几个人不需要遍历所有人。HNSW 的思路和这个完全一样只不过把“人”换成了“向量”把“社交关系”换成了“图中的边”。HNSW 的核心结构是一个多层图最底层Layer 0包含所有向量每个向量和它附近的若干个向量相连往上每一层的向量数量越来越少随机抽取但连接的跨度越来越大最顶层只有很少的几个向量但它们之间的连接覆盖了整个向量空间检索的时候从最顶层开始快速定位到目标的大致区域然后逐层下降每一层都在更精细的范围内搜索最终在最底层找到最相似的向量。3.2 用一个具体例子走一遍 HNSW 的检索过程为了让你更直观地理解咱们用一个简化的例子走一遍。假设向量数据库里有 8 个向量A、B、C、D、E、F、G、HHNSW 建了 3 层图。现在要查询和向量 Q 最相似的向量。Layer 2顶层只有 A 和 E 两个向量从 A 开始计算 Q 和 A 的距离、Q 和 E 的距离发现 E 离 Q 更近移动到 ELayer 1中间层有 A、C、E、G 四个向量从 E 出发看 E 的邻居C 和 G计算 Q 和 C、Q 和 G 的距离发现 G 离 Q 更近移动到 GLayer 0底层所有 8 个向量都在从 G 出发看 G 的邻居F 和 H计算 Q 和 F、Q 和 H 的距离发现 H 离 Q 最近再看 H 的邻居没有比 H 更近的了结果H 是和 Q 最相似的向量3.3 为什么 HNSW 这么快HNSW 快的原因可以归结为两点第一多层结构实现了“粗到细”的搜索。顶层的少量向量帮你快速跳到目标附近底层的密集连接帮你精确定位。这和跳表Skip List的思想很像——如果你了解 Redis 的有序集合ZSet它底层用的就是跳表原理是相通的。第二“小世界”特性保证了图的连通性。在 HNSW 的图中任意两个向量之间只需要经过很少的“跳转”就能到达类似“六度分隔理论”——你和世界上任何一个人之间最多只隔 6 个人。这意味着搜索不会陷入死角总能快速逼近目标。3.4 HNSW 的代价内存占用HNSW 的检索速度和精度都很优秀但它有一个明显的代价内存占用大。M 自己有几个邻居名额efConstruction 帮你海选找邻居的范围大小索引算法对比怎么选主流向量数据库对比与选型主流方案对比为什么选 Milvus本系列选择 Milvus 作为向量数据库原因有几个开源且社区活跃Apache 2.0 协议截止 26.2.20 号 GitHub 上 42.8k star文档和社区资源丰富Java SDK 完善本系列的代码示例用 JavaMilvus 的 Java SDKio.milvus:milvus-sdk-java功能完整API 设计清晰支持大规模数据从几万到几十亿向量都能应对单机模式适合开发和中小规模集群模式适合大规模生产索引类型丰富HNSW、IVF_FLAT、IVF_SQ8、DISKANN 等都支持可以根据场景灵活选择标量过滤能力强支持在向量检索的同时按元数据字段过滤比如只在退货政策类的 chunk 里检索这在 RAG 场景中非常实用本地部署简单一个docker compose up -d就能启动开发环境零门槛Milvus 核心概念和传统数据库做类比在动手写代码之前先搞清楚 Milvus 里的几个核心概念。如果你用过 MySQL理解起来会很快——Milvus 的概念体系和关系型数据库有很多对应关系。Collection 表Collection 是 Milvus 中数据组织的基本单位对应 MySQL 中的表Table。一个 Collection 存储一类向量数据。比如在我们的电商客服知识库场景中可以创建一个名为customer_service_chunks的 Collection里面存所有客服知识库的 chunk 向量。如果你有多个业务场景比如客服知识库、商品搜索、内容推荐通常每个场景创建一个独立的 Collection。Schema 表结构Schema 定义了 Collection 中每条数据包含哪些字段对应 MySQL 中的表结构CREATE TABLE 时定义的列。一个典型的 RAG 场景的 Schema 包含三类字段字段类型示例说明主键字段idInt64 或 VarChar每条数据的唯一标识类似 MySQL 的主键向量字段vectorFloatVector存储 Embedding 向量需要指定维度标量字段chunk_text、doc_id、category 等存储元数据用于过滤和展示2.1 向量字段和标量字段的区别这里要特别说明一下向量字段和标量字段的区别因为这是 Milvus 和传统数据库最大的不同。标量字段存储的是普通数据字符串、数字、布尔值等和 MySQL 的列没什么区别。你可以对标量字段建索引、做等值查询、范围查询、模糊匹配等。向量字段存储的是高维浮点数数组比如 4096 维的 float 数组它不能做等值查询两个向量完全相等的概率几乎为零只能做相似度检索找最近的 Top-K 个。向量字段需要建专门的向量索引HNSW、IVF 等这和标量字段的 B 树索引是完全不同的东西。Index 索引Milvus 中的索引分两种向量索引为向量字段创建的 ANN 索引HNSW、IVF_FLAT 等用于加速向量相似度检索。这是 Milvus 的核心能力。标量索引为标量字段创建的索引用于加速过滤条件的执行。类似 MySQL 的 B 树索引。在 RAG 场景中通常需要同时用到两种索引向量索引用于找到语义最相似的 chunk标量索引用于按元数据过滤比如只搜索某个类别的 chunk。Partition 分区Partition 是 Collection 内部的数据分区对应 MySQL 的分区表。你可以按某个业务维度把数据分到不同的 Partition 里。比如按文档类别分区退货政策放一个 Partition物流规则放一个 Partition促销活动放一个 Partition。检索的时候可以指定只在某个 Partition 里搜索这样搜索范围更小速度更快。不过需要注意Partition 不是必须的。如果你的数据量不大 100 万或者没有明确的分区维度不分区也完全没问题。用标量过滤在 WHERE 条件里加category return_policy也能达到类似的效果只是在数据量很大时性能不如 Partition。一张图看懂 Milvus 的数据组织把上面的概念串起来Milvus 的数据组织结构是这样的和 MySQL 做个对照实际项目中的关键决策跑通了 demo接下来聊聊实际项目中你会遇到的几个关键决策。这些决策没有标准答案取决于你的数据量、性能要求和资源限制。索引类型怎么选前面的“索引算法对比”表格已经给了一个大致的方向这里再给一个更实操的决策流程先问自己数据量有多大 10 万条直接用FLAT暴力搜索就够了省去调参的麻烦10 万 ~ 500 万条优先选HNSW速度快、召回率高500 万 ~ 5000 万条看内存够不够。够就HNSW不够就IVF_SQ8向量压缩到原来的 1/45000 万条考虑DISKANN索引放磁盘或IVF_PQ更激进的压缩再问自己对召回率的要求有多高RAG 场景通常取 Top-5 到 Top-10对召回率的容忍度较高HNSW和IVF_FLAT都能满足如果是人脸识别、指纹匹配等对精度要求极高的场景可能需要FLAT或者把 HNSW 的参数调得很大对于大多数 RAG 项目HNSW是默认选择不需要纠结。相似度度量怎么选Milvus 支持三种相似度度量方式分区策略设计Milvus 的 Partition 可以按业务维度把数据分开存储检索时指定 Partition 可以缩小搜索范围。常见的分区策略性能调优的几个关键参数5.1 HNSW 索引参数5.2 IVF 索引参数小结与下一篇预告这一篇我们解决了向量存到哪里的问题。从暴力搜索的性能瓶颈出发理解了为什么需要专门的向量数据库学习了 IVF 和 HNSW 两种主流的 ANN 索引算法对比了市面上的向量数据库方案选定了 Milvus最后用 Java 代码跑通了从建表到检索的完整流程。到这里RAG 的离线数据准备链路已经打通了原始文档 → Tika 提取文本 → 分块 → 元数据管理 → 向量化 → 存入 Milvus。但数据准备好只是第一步。当用户真正提问的时候怎么从 Milvus 里检索出最相关的 chunk只靠向量相似度够吗答案是不够。纯向量检索有一个天然的短板——它擅长语义匹配但对关键词匹配不敏感。比如用户问订单号 2026012345 的物流状态这里面最关键的信息是订单号但向量检索可能会忽略这个精确的数字转而匹配一些语义上“像是在问物流”的 chunk。下一篇我们就来解决这个问题检索策略。会讲到关键词检索BM25、混合检索向量 关键词、以及重排序Reranking——这些策略组合起来才能让 RAG 系统的检索质量真正达到生产可用的水平。
返回列表