第18章 向量数据库
本章目标:
理解向量数据库的工作原理,以及 HNSW、IVF、PQ 等索引算法。
18.1 为什么需要向量数据库?
假设你有 100 万篇文章,每篇文章都有一个 768 维的 Embedding 向量。
用户输入一个 query,你需要找到最相似的 10 篇文章。
暴力搜索:
text
计算 query 与 100万个向量的余弦相似度
时间复杂度:O(N × d) = O(100万 × 768) ≈ 7.68亿次乘法
太慢了!
向量数据库的作用:
用近似最近邻(ANN)算法,在牺牲少量精度的情况下,大幅提升检索速度。
18.2 相似度度量
| 度量方式 | 公式 | 适用场景 |
|---|---|---|
| 余弦相似度 | cos(a,b)=a⋅b∣a∣∣b∣\cos(a,b) = \frac{a \cdot b}{|a| |b|}cos(a,b)=∣a∣∣b∣a⋅b | 文本语义相似度 |
| 欧氏距离 | d(a,b)=∑(ai−bi)2d(a,b) = \sqrt{\sum(a_i-b_i)^2}d(a,b)=∑(ai−bi)2 | 图像特征 |
| 内积 | a⋅b=∑aibia \cdot b = \sum a_i b_ia⋅b=∑aibi | 归一化后等价于余弦 |
对于 Embedding Model 的输出(L2 归一化后),余弦相似度 = 内积。
18.3 HNSW(Hierarchical Navigable Small World)
HNSW 是目前最流行的 ANN 算法,被 Chroma、Milvus 等广泛使用。
18.3.1 核心思想
HNSW 构建一个多层图结构:
#mermaid-svg-jbqfFsbJCZMO6xiV{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jbqfFsbJCZMO6xiV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jbqfFsbJCZMO6xiV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jbqfFsbJCZMO6xiV .error-icon{fill:#552222;}#mermaid-svg-jbqfFsbJCZMO6xiV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jbqfFsbJCZMO6xiV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jbqfFsbJCZMO6xiV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jbqfFsbJCZMO6xiV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jbqfFsbJCZMO6xiV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jbqfFsbJCZMO6xiV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jbqfFsbJCZMO6xiV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jbqfFsbJCZMO6xiV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jbqfFsbJCZMO6xiV .marker.cross{stroke:#333333;}#mermaid-svg-jbqfFsbJCZMO6xiV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jbqfFsbJCZMO6xiV p{margin:0;}#mermaid-svg-jbqfFsbJCZMO6xiV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jbqfFsbJCZMO6xiV .cluster-label text{fill:#333;}#mermaid-svg-jbqfFsbJCZMO6xiV .cluster-label span{color:#333;}#mermaid-svg-jbqfFsbJCZMO6xiV .cluster-label span p{background-color:transparent;}#mermaid-svg-jbqfFsbJCZMO6xiV .label text,#mermaid-svg-jbqfFsbJCZMO6xiV span{fill:#333;color:#333;}#mermaid-svg-jbqfFsbJCZMO6xiV .node rect,#mermaid-svg-jbqfFsbJCZMO6xiV .node circle,#mermaid-svg-jbqfFsbJCZMO6xiV .node ellipse,#mermaid-svg-jbqfFsbJCZMO6xiV .node polygon,#mermaid-svg-jbqfFsbJCZMO6xiV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jbqfFsbJCZMO6xiV .rough-node .label text,#mermaid-svg-jbqfFsbJCZMO6xiV .node .label text,#mermaid-svg-jbqfFsbJCZMO6xiV .image-shape .label,#mermaid-svg-jbqfFsbJCZMO6xiV .icon-shape .label{text-anchor:middle;}#mermaid-svg-jbqfFsbJCZMO6xiV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jbqfFsbJCZMO6xiV .rough-node .label,#mermaid-svg-jbqfFsbJCZMO6xiV .node .label,#mermaid-svg-jbqfFsbJCZMO6xiV .image-shape .label,#mermaid-svg-jbqfFsbJCZMO6xiV .icon-shape .label{text-align:center;}#mermaid-svg-jbqfFsbJCZMO6xiV .node.clickable{cursor:pointer;}#mermaid-svg-jbqfFsbJCZMO6xiV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jbqfFsbJCZMO6xiV .arrowheadPath{fill:#333333;}#mermaid-svg-jbqfFsbJCZMO6xiV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jbqfFsbJCZMO6xiV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jbqfFsbJCZMO6xiV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jbqfFsbJCZMO6xiV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jbqfFsbJCZMO6xiV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jbqfFsbJCZMO6xiV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jbqfFsbJCZMO6xiV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jbqfFsbJCZMO6xiV .cluster text{fill:#333;}#mermaid-svg-jbqfFsbJCZMO6xiV .cluster span{color:#333;}#mermaid-svg-jbqfFsbJCZMO6xiV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jbqfFsbJCZMO6xiV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jbqfFsbJCZMO6xiV rect.text{fill:none;stroke-width:0;}#mermaid-svg-jbqfFsbJCZMO6xiV .icon-shape,#mermaid-svg-jbqfFsbJCZMO6xiV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jbqfFsbJCZMO6xiV .icon-shape p,#mermaid-svg-jbqfFsbJCZMO6xiV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jbqfFsbJCZMO6xiV .icon-shape .label rect,#mermaid-svg-jbqfFsbJCZMO6xiV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jbqfFsbJCZMO6xiV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jbqfFsbJCZMO6xiV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jbqfFsbJCZMO6xiV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 第 0 层 密集短程连接(出口层)
第 1 层 中等密度
第 2 层 稀疏长程连接(入口层)
向下降落
向下降落
节点A
节点D
节点G
节点A
节点B
节点D
节点E
节点G
节点A
节点B
节点C
节点D
节点E
节点F
节点G
搜索从最顶层(第 2 层,入口) 进入,利用稀疏的长程连接快速跳到目标附近;然后逐层向下降落 ,每一层的图越来越密;最终在第 0 层(出口) 用密集的短程连接做精确搜索,找到最近邻。
注:层数(这里画了 3 层)只是示意,实际 HNSW 的层数由构建时随机决定(每个节点的最高层数按指数分布采样)。其中 第 0 层(Layer 0)是官方约定的最底层,包含全部节点;层号越大越往上、图越稀疏。
一个好用的类比:多粒度导航
HNSW 的分层,本质上很像对同一批数据建立不同粗细粒度的导航图------就像看地图时从世界地图逐级放大到城市街区:
#mermaid-svg-lBma3EshD2vy4fZ6{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-lBma3EshD2vy4fZ6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-lBma3EshD2vy4fZ6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-lBma3EshD2vy4fZ6 .error-icon{fill:#552222;}#mermaid-svg-lBma3EshD2vy4fZ6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-lBma3EshD2vy4fZ6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-lBma3EshD2vy4fZ6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-lBma3EshD2vy4fZ6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-lBma3EshD2vy4fZ6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-lBma3EshD2vy4fZ6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-lBma3EshD2vy4fZ6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-lBma3EshD2vy4fZ6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-lBma3EshD2vy4fZ6 .marker.cross{stroke:#333333;}#mermaid-svg-lBma3EshD2vy4fZ6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-lBma3EshD2vy4fZ6 p{margin:0;}#mermaid-svg-lBma3EshD2vy4fZ6 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-lBma3EshD2vy4fZ6 .cluster-label text{fill:#333;}#mermaid-svg-lBma3EshD2vy4fZ6 .cluster-label span{color:#333;}#mermaid-svg-lBma3EshD2vy4fZ6 .cluster-label span p{background-color:transparent;}#mermaid-svg-lBma3EshD2vy4fZ6 .label text,#mermaid-svg-lBma3EshD2vy4fZ6 span{fill:#333;color:#333;}#mermaid-svg-lBma3EshD2vy4fZ6 .node rect,#mermaid-svg-lBma3EshD2vy4fZ6 .node circle,#mermaid-svg-lBma3EshD2vy4fZ6 .node ellipse,#mermaid-svg-lBma3EshD2vy4fZ6 .node polygon,#mermaid-svg-lBma3EshD2vy4fZ6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-lBma3EshD2vy4fZ6 .rough-node .label text,#mermaid-svg-lBma3EshD2vy4fZ6 .node .label text,#mermaid-svg-lBma3EshD2vy4fZ6 .image-shape .label,#mermaid-svg-lBma3EshD2vy4fZ6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-lBma3EshD2vy4fZ6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-lBma3EshD2vy4fZ6 .rough-node .label,#mermaid-svg-lBma3EshD2vy4fZ6 .node .label,#mermaid-svg-lBma3EshD2vy4fZ6 .image-shape .label,#mermaid-svg-lBma3EshD2vy4fZ6 .icon-shape .label{text-align:center;}#mermaid-svg-lBma3EshD2vy4fZ6 .node.clickable{cursor:pointer;}#mermaid-svg-lBma3EshD2vy4fZ6 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-lBma3EshD2vy4fZ6 .arrowheadPath{fill:#333333;}#mermaid-svg-lBma3EshD2vy4fZ6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-lBma3EshD2vy4fZ6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-lBma3EshD2vy4fZ6 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lBma3EshD2vy4fZ6 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-lBma3EshD2vy4fZ6 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lBma3EshD2vy4fZ6 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-lBma3EshD2vy4fZ6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-lBma3EshD2vy4fZ6 .cluster text{fill:#333;}#mermaid-svg-lBma3EshD2vy4fZ6 .cluster span{color:#333;}#mermaid-svg-lBma3EshD2vy4fZ6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-lBma3EshD2vy4fZ6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-lBma3EshD2vy4fZ6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-lBma3EshD2vy4fZ6 .icon-shape,#mermaid-svg-lBma3EshD2vy4fZ6 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lBma3EshD2vy4fZ6 .icon-shape p,#mermaid-svg-lBma3EshD2vy4fZ6 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-lBma3EshD2vy4fZ6 .icon-shape .label rect,#mermaid-svg-lBma3EshD2vy4fZ6 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lBma3EshD2vy4fZ6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-lBma3EshD2vy4fZ6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-lBma3EshD2vy4fZ6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 世界地图
只标大洲/大城市
国家地图
标主要城市
省级地图
标城市和主干道
城市地图
标每条街道
对应到 HNSW:
| 层 | 粒度 | 地图类比 |
|---|---|---|
| 顶层(最稀疏) | 最粗粒度:极少节点 + 超长程跳跃 | 世界地图(只标大洲/大城市) |
| 上中层 | 粗粒度 | 国家地图(标主要城市) |
| 中间层 | 中粒度 | 省级地图(标城市和主干道) |
| 第 0 层(最密集,含全部点) | 最细粒度:全部节点 + 短程连接 | 城市地图(每条街道都有) |
搜索就是从粗到细逐级放大:先在"世界地图"上快速跳到目标国家/城市附近,再逐级切到"国家地图""省级地图"缩小范围,最后在"城市地图"上精确定位。层数越多,放大过程就分得越细。
但要注意 HNSW 和传统"多级索引"(如 B+ 树、分层聚类)有一个本质区别:
- 传统分层索引 :上层是下层的摘要/聚合,一个上层节点"代表"下面一堆点(父子隶属关系)。
- HNSW :上层的点本身就是下层点的抽样子集 。节点 A 出现在第 2 层,意味着 A 也存在于第 1 层和第 0 层,只是它在高层额外拥有长程连接。层与层之间靠"同一个点的副本"连接(就是上图
A2 → A1 → A0那条降落线),不是父子摘要关系。
传统分层索引:上层 = 下层的"压缩摘要"HNSW:上层 = 下层的"抽样子集"\text{传统分层索引:上层 = 下层的"压缩摘要"} \qquad \text{HNSW:上层 = 下层的"抽样子集"}传统分层索引:上层 = 下层的"压缩摘要"HNSW:上层 = 下层的"抽样子集"
18.3.2 搜索过程
#mermaid-svg-T4iQqElYVa7O50cq{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-T4iQqElYVa7O50cq .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-T4iQqElYVa7O50cq .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-T4iQqElYVa7O50cq .error-icon{fill:#552222;}#mermaid-svg-T4iQqElYVa7O50cq .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-T4iQqElYVa7O50cq .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-T4iQqElYVa7O50cq .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-T4iQqElYVa7O50cq .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-T4iQqElYVa7O50cq .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-T4iQqElYVa7O50cq .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-T4iQqElYVa7O50cq .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-T4iQqElYVa7O50cq .marker{fill:#333333;stroke:#333333;}#mermaid-svg-T4iQqElYVa7O50cq .marker.cross{stroke:#333333;}#mermaid-svg-T4iQqElYVa7O50cq svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-T4iQqElYVa7O50cq p{margin:0;}#mermaid-svg-T4iQqElYVa7O50cq .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-T4iQqElYVa7O50cq .cluster-label text{fill:#333;}#mermaid-svg-T4iQqElYVa7O50cq .cluster-label span{color:#333;}#mermaid-svg-T4iQqElYVa7O50cq .cluster-label span p{background-color:transparent;}#mermaid-svg-T4iQqElYVa7O50cq .label text,#mermaid-svg-T4iQqElYVa7O50cq span{fill:#333;color:#333;}#mermaid-svg-T4iQqElYVa7O50cq .node rect,#mermaid-svg-T4iQqElYVa7O50cq .node circle,#mermaid-svg-T4iQqElYVa7O50cq .node ellipse,#mermaid-svg-T4iQqElYVa7O50cq .node polygon,#mermaid-svg-T4iQqElYVa7O50cq .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-T4iQqElYVa7O50cq .rough-node .label text,#mermaid-svg-T4iQqElYVa7O50cq .node .label text,#mermaid-svg-T4iQqElYVa7O50cq .image-shape .label,#mermaid-svg-T4iQqElYVa7O50cq .icon-shape .label{text-anchor:middle;}#mermaid-svg-T4iQqElYVa7O50cq .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-T4iQqElYVa7O50cq .rough-node .label,#mermaid-svg-T4iQqElYVa7O50cq .node .label,#mermaid-svg-T4iQqElYVa7O50cq .image-shape .label,#mermaid-svg-T4iQqElYVa7O50cq .icon-shape .label{text-align:center;}#mermaid-svg-T4iQqElYVa7O50cq .node.clickable{cursor:pointer;}#mermaid-svg-T4iQqElYVa7O50cq .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-T4iQqElYVa7O50cq .arrowheadPath{fill:#333333;}#mermaid-svg-T4iQqElYVa7O50cq .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-T4iQqElYVa7O50cq .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-T4iQqElYVa7O50cq .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-T4iQqElYVa7O50cq .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-T4iQqElYVa7O50cq .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-T4iQqElYVa7O50cq .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-T4iQqElYVa7O50cq .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-T4iQqElYVa7O50cq .cluster text{fill:#333;}#mermaid-svg-T4iQqElYVa7O50cq .cluster span{color:#333;}#mermaid-svg-T4iQqElYVa7O50cq div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-T4iQqElYVa7O50cq .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-T4iQqElYVa7O50cq rect.text{fill:none;stroke-width:0;}#mermaid-svg-T4iQqElYVa7O50cq .icon-shape,#mermaid-svg-T4iQqElYVa7O50cq .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-T4iQqElYVa7O50cq .icon-shape p,#mermaid-svg-T4iQqElYVa7O50cq .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-T4iQqElYVa7O50cq .icon-shape .label rect,#mermaid-svg-T4iQqElYVa7O50cq .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-T4iQqElYVa7O50cq .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-T4iQqElYVa7O50cq .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-T4iQqElYVa7O50cq :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 从最高层开始
粗粒度导航
找到大致方向
下降到下一层
更精细搜索
重复直到第0层
在第0层精确搜索
找到最近邻
18.3.3 HNSW 的参数
| 参数 | 说明 | 默认值 |
|---|---|---|
| M | 每个节点的最大连接数 | 16 |
| ef_construction | 构建时的搜索宽度 | 200 |
| ef_search | 搜索时的候选集大小 | 50 |
M 越大,精度越高,但内存和构建时间也越大。
18.4 IVF(Inverted File Index)
IVF 是另一种常用的 ANN 算法:
18.4.1 核心思想
- 训练阶段 :用 K-Means 把所有向量聚成
nlist个簇 - 索引阶段:每个向量存入最近的簇
- 搜索阶段 :只在最近的
nprobe个簇中搜索
#mermaid-svg-nBpq05PwMg6XbwEO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nBpq05PwMg6XbwEO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nBpq05PwMg6XbwEO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nBpq05PwMg6XbwEO .error-icon{fill:#552222;}#mermaid-svg-nBpq05PwMg6XbwEO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nBpq05PwMg6XbwEO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nBpq05PwMg6XbwEO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nBpq05PwMg6XbwEO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nBpq05PwMg6XbwEO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nBpq05PwMg6XbwEO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nBpq05PwMg6XbwEO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nBpq05PwMg6XbwEO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nBpq05PwMg6XbwEO .marker.cross{stroke:#333333;}#mermaid-svg-nBpq05PwMg6XbwEO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nBpq05PwMg6XbwEO p{margin:0;}#mermaid-svg-nBpq05PwMg6XbwEO .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nBpq05PwMg6XbwEO .cluster-label text{fill:#333;}#mermaid-svg-nBpq05PwMg6XbwEO .cluster-label span{color:#333;}#mermaid-svg-nBpq05PwMg6XbwEO .cluster-label span p{background-color:transparent;}#mermaid-svg-nBpq05PwMg6XbwEO .label text,#mermaid-svg-nBpq05PwMg6XbwEO span{fill:#333;color:#333;}#mermaid-svg-nBpq05PwMg6XbwEO .node rect,#mermaid-svg-nBpq05PwMg6XbwEO .node circle,#mermaid-svg-nBpq05PwMg6XbwEO .node ellipse,#mermaid-svg-nBpq05PwMg6XbwEO .node polygon,#mermaid-svg-nBpq05PwMg6XbwEO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nBpq05PwMg6XbwEO .rough-node .label text,#mermaid-svg-nBpq05PwMg6XbwEO .node .label text,#mermaid-svg-nBpq05PwMg6XbwEO .image-shape .label,#mermaid-svg-nBpq05PwMg6XbwEO .icon-shape .label{text-anchor:middle;}#mermaid-svg-nBpq05PwMg6XbwEO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-nBpq05PwMg6XbwEO .rough-node .label,#mermaid-svg-nBpq05PwMg6XbwEO .node .label,#mermaid-svg-nBpq05PwMg6XbwEO .image-shape .label,#mermaid-svg-nBpq05PwMg6XbwEO .icon-shape .label{text-align:center;}#mermaid-svg-nBpq05PwMg6XbwEO .node.clickable{cursor:pointer;}#mermaid-svg-nBpq05PwMg6XbwEO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-nBpq05PwMg6XbwEO .arrowheadPath{fill:#333333;}#mermaid-svg-nBpq05PwMg6XbwEO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nBpq05PwMg6XbwEO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nBpq05PwMg6XbwEO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nBpq05PwMg6XbwEO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-nBpq05PwMg6XbwEO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nBpq05PwMg6XbwEO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-nBpq05PwMg6XbwEO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nBpq05PwMg6XbwEO .cluster text{fill:#333;}#mermaid-svg-nBpq05PwMg6XbwEO .cluster span{color:#333;}#mermaid-svg-nBpq05PwMg6XbwEO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nBpq05PwMg6XbwEO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nBpq05PwMg6XbwEO rect.text{fill:none;stroke-width:0;}#mermaid-svg-nBpq05PwMg6XbwEO .icon-shape,#mermaid-svg-nBpq05PwMg6XbwEO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nBpq05PwMg6XbwEO .icon-shape p,#mermaid-svg-nBpq05PwMg6XbwEO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-nBpq05PwMg6XbwEO .icon-shape .label rect,#mermaid-svg-nBpq05PwMg6XbwEO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nBpq05PwMg6XbwEO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nBpq05PwMg6XbwEO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nBpq05PwMg6XbwEO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 所有向量
K-Means 聚类
nlist=100个簇
每个向量分配到最近的簇
搜索时只查 nprobe=10 个簇
在这些簇中精确搜索
| 参数 | 说明 | 权衡 |
|---|---|---|
| nlist | 簇的数量 | 大→精度高,慢 |
| nprobe | 搜索的簇数 | 大→精度高,慢 |
18.5 PQ(Product Quantization)
PQ 用于压缩向量,减少内存占用:
18.5.1 核心思想
把 768 维向量分成 8 段,每段 96 维,对每段独立量化:
#mermaid-svg-X0jd2BkO0P7QLRxV{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-X0jd2BkO0P7QLRxV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-X0jd2BkO0P7QLRxV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-X0jd2BkO0P7QLRxV .error-icon{fill:#552222;}#mermaid-svg-X0jd2BkO0P7QLRxV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-X0jd2BkO0P7QLRxV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-X0jd2BkO0P7QLRxV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-X0jd2BkO0P7QLRxV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-X0jd2BkO0P7QLRxV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-X0jd2BkO0P7QLRxV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-X0jd2BkO0P7QLRxV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-X0jd2BkO0P7QLRxV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-X0jd2BkO0P7QLRxV .marker.cross{stroke:#333333;}#mermaid-svg-X0jd2BkO0P7QLRxV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-X0jd2BkO0P7QLRxV p{margin:0;}#mermaid-svg-X0jd2BkO0P7QLRxV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-X0jd2BkO0P7QLRxV .cluster-label text{fill:#333;}#mermaid-svg-X0jd2BkO0P7QLRxV .cluster-label span{color:#333;}#mermaid-svg-X0jd2BkO0P7QLRxV .cluster-label span p{background-color:transparent;}#mermaid-svg-X0jd2BkO0P7QLRxV .label text,#mermaid-svg-X0jd2BkO0P7QLRxV span{fill:#333;color:#333;}#mermaid-svg-X0jd2BkO0P7QLRxV .node rect,#mermaid-svg-X0jd2BkO0P7QLRxV .node circle,#mermaid-svg-X0jd2BkO0P7QLRxV .node ellipse,#mermaid-svg-X0jd2BkO0P7QLRxV .node polygon,#mermaid-svg-X0jd2BkO0P7QLRxV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-X0jd2BkO0P7QLRxV .rough-node .label text,#mermaid-svg-X0jd2BkO0P7QLRxV .node .label text,#mermaid-svg-X0jd2BkO0P7QLRxV .image-shape .label,#mermaid-svg-X0jd2BkO0P7QLRxV .icon-shape .label{text-anchor:middle;}#mermaid-svg-X0jd2BkO0P7QLRxV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-X0jd2BkO0P7QLRxV .rough-node .label,#mermaid-svg-X0jd2BkO0P7QLRxV .node .label,#mermaid-svg-X0jd2BkO0P7QLRxV .image-shape .label,#mermaid-svg-X0jd2BkO0P7QLRxV .icon-shape .label{text-align:center;}#mermaid-svg-X0jd2BkO0P7QLRxV .node.clickable{cursor:pointer;}#mermaid-svg-X0jd2BkO0P7QLRxV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-X0jd2BkO0P7QLRxV .arrowheadPath{fill:#333333;}#mermaid-svg-X0jd2BkO0P7QLRxV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-X0jd2BkO0P7QLRxV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-X0jd2BkO0P7QLRxV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-X0jd2BkO0P7QLRxV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-X0jd2BkO0P7QLRxV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-X0jd2BkO0P7QLRxV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-X0jd2BkO0P7QLRxV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-X0jd2BkO0P7QLRxV .cluster text{fill:#333;}#mermaid-svg-X0jd2BkO0P7QLRxV .cluster span{color:#333;}#mermaid-svg-X0jd2BkO0P7QLRxV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-X0jd2BkO0P7QLRxV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-X0jd2BkO0P7QLRxV rect.text{fill:none;stroke-width:0;}#mermaid-svg-X0jd2BkO0P7QLRxV .icon-shape,#mermaid-svg-X0jd2BkO0P7QLRxV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-X0jd2BkO0P7QLRxV .icon-shape p,#mermaid-svg-X0jd2BkO0P7QLRxV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-X0jd2BkO0P7QLRxV .icon-shape .label rect,#mermaid-svg-X0jd2BkO0P7QLRxV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-X0jd2BkO0P7QLRxV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-X0jd2BkO0P7QLRxV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-X0jd2BkO0P7QLRxV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 原始向量
768维 × float32
= 3072 bytes
分成8段
每段96维
每段量化为
1个字节(256个码字)
压缩后
8 bytes
压缩比 384:1
| 方案 | 内存 | 精度 |
|---|---|---|
| 原始 float32 | 3072 bytes | 100% |
| float16 | 1536 bytes | ~100% |
| PQ (8段) | 8 bytes | ~90% |
18.6 主流向量数据库对比
| 数据库 | 特点 | 适用场景 |
|---|---|---|
| FAISS | Facebook 开源,纯内存,速度最快 | 研究、小规模 |
| Chroma | 轻量,易用,本地部署 | 开发、原型 |
| Milvus | 分布式,生产级 | 大规模生产 |
| Qdrant | Rust 实现,高性能 | 生产 |
| Weaviate | 支持混合搜索 | 生产 |
| Pinecone | 云服务,全托管 | 快速上线 |
18.7 FAISS 使用示例
python
import faiss
import numpy as np
# 创建索引
d = 768 # 向量维度
n = 100000 # 向量数量
# 生成随机向量(实际使用时替换为真实 Embedding)
vectors = np.random.random((n, d)).astype('float32')
faiss.normalize_L2(vectors) # L2 归一化
# 创建 HNSW 索引
index = faiss.IndexHNSWFlat(d, 32) # M=32
index.add(vectors)
# 搜索
query = np.random.random((1, d)).astype('float32')
faiss.normalize_L2(query)
k = 10 # 返回最近的 10 个
distances, indices = index.search(query, k)
print("最近邻索引:", indices[0])
print("相似度:", distances[0])
18.8 Chroma 使用示例
python
import chromadb
from chromadb.utils import embedding_functions
# 创建客户端
client = chromadb.Client()
# 使用 BGE 作为 Embedding 函数
ef = embedding_functions.SentenceTransformerEmbeddingFunction(
model_name="BAAI/bge-base-zh-v1.5"
)
# 创建集合
collection = client.create_collection(
name="my_docs",
embedding_function=ef
)
# 添加文档
collection.add(
documents=[
"苹果是一种水果",
"香蕉也是水果",
"苹果公司发布了新产品",
"深度学习是人工智能的一个分支"
],
ids=["doc1", "doc2", "doc3", "doc4"]
)
# 查询
results = collection.query(
query_texts=["什么是水果?"],
n_results=2
)
print(results['documents'])
# [['苹果是一种水果', '香蕉也是水果']]
18.9 混合搜索(Hybrid Search)
只用向量搜索有时不够,现代系统通常结合关键词搜索:
#mermaid-svg-nPmAbtxhrjpcDYvg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nPmAbtxhrjpcDYvg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nPmAbtxhrjpcDYvg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nPmAbtxhrjpcDYvg .error-icon{fill:#552222;}#mermaid-svg-nPmAbtxhrjpcDYvg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nPmAbtxhrjpcDYvg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nPmAbtxhrjpcDYvg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nPmAbtxhrjpcDYvg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nPmAbtxhrjpcDYvg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nPmAbtxhrjpcDYvg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nPmAbtxhrjpcDYvg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nPmAbtxhrjpcDYvg .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nPmAbtxhrjpcDYvg .marker.cross{stroke:#333333;}#mermaid-svg-nPmAbtxhrjpcDYvg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nPmAbtxhrjpcDYvg p{margin:0;}#mermaid-svg-nPmAbtxhrjpcDYvg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nPmAbtxhrjpcDYvg .cluster-label text{fill:#333;}#mermaid-svg-nPmAbtxhrjpcDYvg .cluster-label span{color:#333;}#mermaid-svg-nPmAbtxhrjpcDYvg .cluster-label span p{background-color:transparent;}#mermaid-svg-nPmAbtxhrjpcDYvg .label text,#mermaid-svg-nPmAbtxhrjpcDYvg span{fill:#333;color:#333;}#mermaid-svg-nPmAbtxhrjpcDYvg .node rect,#mermaid-svg-nPmAbtxhrjpcDYvg .node circle,#mermaid-svg-nPmAbtxhrjpcDYvg .node ellipse,#mermaid-svg-nPmAbtxhrjpcDYvg .node polygon,#mermaid-svg-nPmAbtxhrjpcDYvg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nPmAbtxhrjpcDYvg .rough-node .label text,#mermaid-svg-nPmAbtxhrjpcDYvg .node .label text,#mermaid-svg-nPmAbtxhrjpcDYvg .image-shape .label,#mermaid-svg-nPmAbtxhrjpcDYvg .icon-shape .label{text-anchor:middle;}#mermaid-svg-nPmAbtxhrjpcDYvg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-nPmAbtxhrjpcDYvg .rough-node .label,#mermaid-svg-nPmAbtxhrjpcDYvg .node .label,#mermaid-svg-nPmAbtxhrjpcDYvg .image-shape .label,#mermaid-svg-nPmAbtxhrjpcDYvg .icon-shape .label{text-align:center;}#mermaid-svg-nPmAbtxhrjpcDYvg .node.clickable{cursor:pointer;}#mermaid-svg-nPmAbtxhrjpcDYvg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-nPmAbtxhrjpcDYvg .arrowheadPath{fill:#333333;}#mermaid-svg-nPmAbtxhrjpcDYvg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nPmAbtxhrjpcDYvg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nPmAbtxhrjpcDYvg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nPmAbtxhrjpcDYvg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-nPmAbtxhrjpcDYvg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nPmAbtxhrjpcDYvg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-nPmAbtxhrjpcDYvg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nPmAbtxhrjpcDYvg .cluster text{fill:#333;}#mermaid-svg-nPmAbtxhrjpcDYvg .cluster span{color:#333;}#mermaid-svg-nPmAbtxhrjpcDYvg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nPmAbtxhrjpcDYvg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nPmAbtxhrjpcDYvg rect.text{fill:none;stroke-width:0;}#mermaid-svg-nPmAbtxhrjpcDYvg .icon-shape,#mermaid-svg-nPmAbtxhrjpcDYvg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nPmAbtxhrjpcDYvg .icon-shape p,#mermaid-svg-nPmAbtxhrjpcDYvg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-nPmAbtxhrjpcDYvg .icon-shape .label rect,#mermaid-svg-nPmAbtxhrjpcDYvg .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nPmAbtxhrjpcDYvg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nPmAbtxhrjpcDYvg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nPmAbtxhrjpcDYvg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户 Query
向量搜索
语义相关
BM25 关键词搜索
精确匹配
RRF 融合
Reciprocal Rank Fusion
最终排序结果
| 搜索方式 | 优点 | 缺点 |
|---|---|---|
| 向量搜索 | 语义理解,同义词 | 精确词匹配差 |
| 关键词搜索 | 精确匹配 | 不理解语义 |
| 混合搜索 | 两者兼顾 | 实现复杂 |
本章总结
#mermaid-svg-AjMT9Jigood016YY{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-AjMT9Jigood016YY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-AjMT9Jigood016YY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-AjMT9Jigood016YY .error-icon{fill:#552222;}#mermaid-svg-AjMT9Jigood016YY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-AjMT9Jigood016YY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-AjMT9Jigood016YY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-AjMT9Jigood016YY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-AjMT9Jigood016YY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-AjMT9Jigood016YY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-AjMT9Jigood016YY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-AjMT9Jigood016YY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-AjMT9Jigood016YY .marker.cross{stroke:#333333;}#mermaid-svg-AjMT9Jigood016YY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-AjMT9Jigood016YY p{margin:0;}#mermaid-svg-AjMT9Jigood016YY .edge{stroke-width:3;}#mermaid-svg-AjMT9Jigood016YY .section--1 rect,#mermaid-svg-AjMT9Jigood016YY .section--1 path,#mermaid-svg-AjMT9Jigood016YY .section--1 circle,#mermaid-svg-AjMT9Jigood016YY .section--1 polygon,#mermaid-svg-AjMT9Jigood016YY .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .section--1 text{fill:#ffffff;}#mermaid-svg-AjMT9Jigood016YY .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-AjMT9Jigood016YY .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .edge-depth--1{stroke-width:17;}#mermaid-svg-AjMT9Jigood016YY .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AjMT9Jigood016YY .disabled,#mermaid-svg-AjMT9Jigood016YY .disabled circle,#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:lightgray;}#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:#efefef;}#mermaid-svg-AjMT9Jigood016YY .section-0 rect,#mermaid-svg-AjMT9Jigood016YY .section-0 path,#mermaid-svg-AjMT9Jigood016YY .section-0 circle,#mermaid-svg-AjMT9Jigood016YY .section-0 polygon,#mermaid-svg-AjMT9Jigood016YY .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-AjMT9Jigood016YY .section-0 text{fill:black;}#mermaid-svg-AjMT9Jigood016YY .node-icon-0{font-size:40px;color:black;}#mermaid-svg-AjMT9Jigood016YY .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-AjMT9Jigood016YY .edge-depth-0{stroke-width:14;}#mermaid-svg-AjMT9Jigood016YY .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-AjMT9Jigood016YY .disabled,#mermaid-svg-AjMT9Jigood016YY .disabled circle,#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:lightgray;}#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:#efefef;}#mermaid-svg-AjMT9Jigood016YY .section-1 rect,#mermaid-svg-AjMT9Jigood016YY .section-1 path,#mermaid-svg-AjMT9Jigood016YY .section-1 circle,#mermaid-svg-AjMT9Jigood016YY .section-1 polygon,#mermaid-svg-AjMT9Jigood016YY .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .section-1 text{fill:black;}#mermaid-svg-AjMT9Jigood016YY .node-icon-1{font-size:40px;color:black;}#mermaid-svg-AjMT9Jigood016YY .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .edge-depth-1{stroke-width:11;}#mermaid-svg-AjMT9Jigood016YY .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AjMT9Jigood016YY .disabled,#mermaid-svg-AjMT9Jigood016YY .disabled circle,#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:lightgray;}#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:#efefef;}#mermaid-svg-AjMT9Jigood016YY .section-2 rect,#mermaid-svg-AjMT9Jigood016YY .section-2 path,#mermaid-svg-AjMT9Jigood016YY .section-2 circle,#mermaid-svg-AjMT9Jigood016YY .section-2 polygon,#mermaid-svg-AjMT9Jigood016YY .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .section-2 text{fill:#ffffff;}#mermaid-svg-AjMT9Jigood016YY .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-AjMT9Jigood016YY .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .edge-depth-2{stroke-width:8;}#mermaid-svg-AjMT9Jigood016YY .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AjMT9Jigood016YY .disabled,#mermaid-svg-AjMT9Jigood016YY .disabled circle,#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:lightgray;}#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:#efefef;}#mermaid-svg-AjMT9Jigood016YY .section-3 rect,#mermaid-svg-AjMT9Jigood016YY .section-3 path,#mermaid-svg-AjMT9Jigood016YY .section-3 circle,#mermaid-svg-AjMT9Jigood016YY .section-3 polygon,#mermaid-svg-AjMT9Jigood016YY .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .section-3 text{fill:black;}#mermaid-svg-AjMT9Jigood016YY .node-icon-3{font-size:40px;color:black;}#mermaid-svg-AjMT9Jigood016YY .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .edge-depth-3{stroke-width:5;}#mermaid-svg-AjMT9Jigood016YY .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AjMT9Jigood016YY .disabled,#mermaid-svg-AjMT9Jigood016YY .disabled circle,#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:lightgray;}#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:#efefef;}#mermaid-svg-AjMT9Jigood016YY .section-4 rect,#mermaid-svg-AjMT9Jigood016YY .section-4 path,#mermaid-svg-AjMT9Jigood016YY .section-4 circle,#mermaid-svg-AjMT9Jigood016YY .section-4 polygon,#mermaid-svg-AjMT9Jigood016YY .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .section-4 text{fill:black;}#mermaid-svg-AjMT9Jigood016YY .node-icon-4{font-size:40px;color:black;}#mermaid-svg-AjMT9Jigood016YY .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .edge-depth-4{stroke-width:2;}#mermaid-svg-AjMT9Jigood016YY .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AjMT9Jigood016YY .disabled,#mermaid-svg-AjMT9Jigood016YY .disabled circle,#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:lightgray;}#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:#efefef;}#mermaid-svg-AjMT9Jigood016YY .section-5 rect,#mermaid-svg-AjMT9Jigood016YY .section-5 path,#mermaid-svg-AjMT9Jigood016YY .section-5 circle,#mermaid-svg-AjMT9Jigood016YY .section-5 polygon,#mermaid-svg-AjMT9Jigood016YY .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .section-5 text{fill:black;}#mermaid-svg-AjMT9Jigood016YY .node-icon-5{font-size:40px;color:black;}#mermaid-svg-AjMT9Jigood016YY .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .edge-depth-5{stroke-width:-1;}#mermaid-svg-AjMT9Jigood016YY .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AjMT9Jigood016YY .disabled,#mermaid-svg-AjMT9Jigood016YY .disabled circle,#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:lightgray;}#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:#efefef;}#mermaid-svg-AjMT9Jigood016YY .section-6 rect,#mermaid-svg-AjMT9Jigood016YY .section-6 path,#mermaid-svg-AjMT9Jigood016YY .section-6 circle,#mermaid-svg-AjMT9Jigood016YY .section-6 polygon,#mermaid-svg-AjMT9Jigood016YY .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .section-6 text{fill:black;}#mermaid-svg-AjMT9Jigood016YY .node-icon-6{font-size:40px;color:black;}#mermaid-svg-AjMT9Jigood016YY .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .edge-depth-6{stroke-width:-4;}#mermaid-svg-AjMT9Jigood016YY .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AjMT9Jigood016YY .disabled,#mermaid-svg-AjMT9Jigood016YY .disabled circle,#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:lightgray;}#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:#efefef;}#mermaid-svg-AjMT9Jigood016YY .section-7 rect,#mermaid-svg-AjMT9Jigood016YY .section-7 path,#mermaid-svg-AjMT9Jigood016YY .section-7 circle,#mermaid-svg-AjMT9Jigood016YY .section-7 polygon,#mermaid-svg-AjMT9Jigood016YY .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .section-7 text{fill:black;}#mermaid-svg-AjMT9Jigood016YY .node-icon-7{font-size:40px;color:black;}#mermaid-svg-AjMT9Jigood016YY .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .edge-depth-7{stroke-width:-7;}#mermaid-svg-AjMT9Jigood016YY .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AjMT9Jigood016YY .disabled,#mermaid-svg-AjMT9Jigood016YY .disabled circle,#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:lightgray;}#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:#efefef;}#mermaid-svg-AjMT9Jigood016YY .section-8 rect,#mermaid-svg-AjMT9Jigood016YY .section-8 path,#mermaid-svg-AjMT9Jigood016YY .section-8 circle,#mermaid-svg-AjMT9Jigood016YY .section-8 polygon,#mermaid-svg-AjMT9Jigood016YY .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .section-8 text{fill:black;}#mermaid-svg-AjMT9Jigood016YY .node-icon-8{font-size:40px;color:black;}#mermaid-svg-AjMT9Jigood016YY .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .edge-depth-8{stroke-width:-10;}#mermaid-svg-AjMT9Jigood016YY .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AjMT9Jigood016YY .disabled,#mermaid-svg-AjMT9Jigood016YY .disabled circle,#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:lightgray;}#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:#efefef;}#mermaid-svg-AjMT9Jigood016YY .section-9 rect,#mermaid-svg-AjMT9Jigood016YY .section-9 path,#mermaid-svg-AjMT9Jigood016YY .section-9 circle,#mermaid-svg-AjMT9Jigood016YY .section-9 polygon,#mermaid-svg-AjMT9Jigood016YY .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .section-9 text{fill:black;}#mermaid-svg-AjMT9Jigood016YY .node-icon-9{font-size:40px;color:black;}#mermaid-svg-AjMT9Jigood016YY .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .edge-depth-9{stroke-width:-13;}#mermaid-svg-AjMT9Jigood016YY .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AjMT9Jigood016YY .disabled,#mermaid-svg-AjMT9Jigood016YY .disabled circle,#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:lightgray;}#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:#efefef;}#mermaid-svg-AjMT9Jigood016YY .section-10 rect,#mermaid-svg-AjMT9Jigood016YY .section-10 path,#mermaid-svg-AjMT9Jigood016YY .section-10 circle,#mermaid-svg-AjMT9Jigood016YY .section-10 polygon,#mermaid-svg-AjMT9Jigood016YY .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .section-10 text{fill:black;}#mermaid-svg-AjMT9Jigood016YY .node-icon-10{font-size:40px;color:black;}#mermaid-svg-AjMT9Jigood016YY .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .edge-depth-10{stroke-width:-16;}#mermaid-svg-AjMT9Jigood016YY .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AjMT9Jigood016YY .disabled,#mermaid-svg-AjMT9Jigood016YY .disabled circle,#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:lightgray;}#mermaid-svg-AjMT9Jigood016YY .disabled text{fill:#efefef;}#mermaid-svg-AjMT9Jigood016YY .section-root rect,#mermaid-svg-AjMT9Jigood016YY .section-root path,#mermaid-svg-AjMT9Jigood016YY .section-root circle,#mermaid-svg-AjMT9Jigood016YY .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-AjMT9Jigood016YY .section-root text{fill:#ffffff;}#mermaid-svg-AjMT9Jigood016YY .section-root span{color:#ffffff;}#mermaid-svg-AjMT9Jigood016YY .section-2 span{color:#ffffff;}#mermaid-svg-AjMT9Jigood016YY .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-AjMT9Jigood016YY .edge{fill:none;}#mermaid-svg-AjMT9Jigood016YY .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-AjMT9Jigood016YY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 向量数据库
索引算法
HNSW 多层图
IVF 倒排索引
PQ 向量压缩
主流数据库
FAISS 研究
Chroma 开发
Milvus 生产
搜索策略
纯向量搜索
混合搜索
重排序
本章思考题
- 为什么 ANN(近似最近邻)比精确最近邻更实用?
- HNSW 的多层结构为什么能加速搜索?
- PQ 压缩会损失精度,在什么场景下可以接受这种损失?
- 混合搜索中,如何平衡向量搜索和关键词搜索的权重?
下一章预告
下一章我们讲 RAG(Retrieval-Augmented Generation)。
这是目前最实用的 LLM 应用架构,把向量数据库和 LLM 结合起来。