09 Milvus-向量索引原理

「milvus-course-ai.zip」
链接:https://pan.quark.cn/s/00f3d411bb6d

github:https://github.com/yuanmomoya/milvus

学习目标

学完本章后,你应该能够:

  • 解释 FLAT、IVF、HNSW、PQ、DISKANN 五大索引家族的核心思想。
  • 画出每种索引的搜索路径和数据结构。
  • 根据数据规模、内存预算和延迟要求选择索引。
  • 理解索引参数如何影响召回率、QPS 和内存。
  • 在 Milvus 中创建和切换不同索引。

索引的本质

向量索引的目标:用可控的召回损失换取数量级的搜索加速
#mermaid-svg-VNXldSzepTq6cxOd{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-VNXldSzepTq6cxOd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-VNXldSzepTq6cxOd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-VNXldSzepTq6cxOd .error-icon{fill:#552222;}#mermaid-svg-VNXldSzepTq6cxOd .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-VNXldSzepTq6cxOd .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-VNXldSzepTq6cxOd .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-VNXldSzepTq6cxOd .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-VNXldSzepTq6cxOd .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-VNXldSzepTq6cxOd .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-VNXldSzepTq6cxOd .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-VNXldSzepTq6cxOd .marker{fill:#333333;stroke:#333333;}#mermaid-svg-VNXldSzepTq6cxOd .marker.cross{stroke:#333333;}#mermaid-svg-VNXldSzepTq6cxOd svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-VNXldSzepTq6cxOd p{margin:0;}#mermaid-svg-VNXldSzepTq6cxOd .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-VNXldSzepTq6cxOd .cluster-label text{fill:#333;}#mermaid-svg-VNXldSzepTq6cxOd .cluster-label span{color:#333;}#mermaid-svg-VNXldSzepTq6cxOd .cluster-label span p{background-color:transparent;}#mermaid-svg-VNXldSzepTq6cxOd .label text,#mermaid-svg-VNXldSzepTq6cxOd span{fill:#333;color:#333;}#mermaid-svg-VNXldSzepTq6cxOd .node rect,#mermaid-svg-VNXldSzepTq6cxOd .node circle,#mermaid-svg-VNXldSzepTq6cxOd .node ellipse,#mermaid-svg-VNXldSzepTq6cxOd .node polygon,#mermaid-svg-VNXldSzepTq6cxOd .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-VNXldSzepTq6cxOd .rough-node .label text,#mermaid-svg-VNXldSzepTq6cxOd .node .label text,#mermaid-svg-VNXldSzepTq6cxOd .image-shape .label,#mermaid-svg-VNXldSzepTq6cxOd .icon-shape .label{text-anchor:middle;}#mermaid-svg-VNXldSzepTq6cxOd .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-VNXldSzepTq6cxOd .rough-node .label,#mermaid-svg-VNXldSzepTq6cxOd .node .label,#mermaid-svg-VNXldSzepTq6cxOd .image-shape .label,#mermaid-svg-VNXldSzepTq6cxOd .icon-shape .label{text-align:center;}#mermaid-svg-VNXldSzepTq6cxOd .node.clickable{cursor:pointer;}#mermaid-svg-VNXldSzepTq6cxOd .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-VNXldSzepTq6cxOd .arrowheadPath{fill:#333333;}#mermaid-svg-VNXldSzepTq6cxOd .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-VNXldSzepTq6cxOd .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-VNXldSzepTq6cxOd .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VNXldSzepTq6cxOd .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-VNXldSzepTq6cxOd .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VNXldSzepTq6cxOd .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-VNXldSzepTq6cxOd .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-VNXldSzepTq6cxOd .cluster text{fill:#333;}#mermaid-svg-VNXldSzepTq6cxOd .cluster span{color:#333;}#mermaid-svg-VNXldSzepTq6cxOd 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-VNXldSzepTq6cxOd .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-VNXldSzepTq6cxOd rect.text{fill:none;stroke-width:0;}#mermaid-svg-VNXldSzepTq6cxOd .icon-shape,#mermaid-svg-VNXldSzepTq6cxOd .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VNXldSzepTq6cxOd .icon-shape p,#mermaid-svg-VNXldSzepTq6cxOd .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-VNXldSzepTq6cxOd .icon-shape .label rect,#mermaid-svg-VNXldSzepTq6cxOd .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VNXldSzepTq6cxOd .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-VNXldSzepTq6cxOd .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-VNXldSzepTq6cxOd :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 暴力扫描 FLAT
ANN 索引
100 万向量
搜索方式
扫描 100 万次

延迟 ~500ms

召回 100%
扫描 ~1 万次

延迟 ~5ms

召回 95%+

所有 ANN 索引都在回答同一个问题:如何只看一小部分数据,就能大概率找到真正最近的 TopK?

不同索引用不同策略回答这个问题:

索引 策略 类比
IVF 先分区,只搜最近的几个区 先确定城市区域,再找具体地址
HNSW 建多层图,从粗到细导航 先走高速公路,再走小路
PQ 压缩向量,用近似距离筛选 先看缩略图,再看原图
DISKANN 图索引放磁盘,按需加载 地图太大放硬盘,翻到哪页看哪页

FLAT(暴力搜索)

FLAT 不是真正的索引,它保存原始向量,搜索时逐一计算距离。
#mermaid-svg-FSukWLClc8SNKzHl{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-FSukWLClc8SNKzHl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FSukWLClc8SNKzHl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FSukWLClc8SNKzHl .error-icon{fill:#552222;}#mermaid-svg-FSukWLClc8SNKzHl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FSukWLClc8SNKzHl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FSukWLClc8SNKzHl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FSukWLClc8SNKzHl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FSukWLClc8SNKzHl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FSukWLClc8SNKzHl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FSukWLClc8SNKzHl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FSukWLClc8SNKzHl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FSukWLClc8SNKzHl .marker.cross{stroke:#333333;}#mermaid-svg-FSukWLClc8SNKzHl svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FSukWLClc8SNKzHl p{margin:0;}#mermaid-svg-FSukWLClc8SNKzHl .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FSukWLClc8SNKzHl .cluster-label text{fill:#333;}#mermaid-svg-FSukWLClc8SNKzHl .cluster-label span{color:#333;}#mermaid-svg-FSukWLClc8SNKzHl .cluster-label span p{background-color:transparent;}#mermaid-svg-FSukWLClc8SNKzHl .label text,#mermaid-svg-FSukWLClc8SNKzHl span{fill:#333;color:#333;}#mermaid-svg-FSukWLClc8SNKzHl .node rect,#mermaid-svg-FSukWLClc8SNKzHl .node circle,#mermaid-svg-FSukWLClc8SNKzHl .node ellipse,#mermaid-svg-FSukWLClc8SNKzHl .node polygon,#mermaid-svg-FSukWLClc8SNKzHl .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FSukWLClc8SNKzHl .rough-node .label text,#mermaid-svg-FSukWLClc8SNKzHl .node .label text,#mermaid-svg-FSukWLClc8SNKzHl .image-shape .label,#mermaid-svg-FSukWLClc8SNKzHl .icon-shape .label{text-anchor:middle;}#mermaid-svg-FSukWLClc8SNKzHl .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FSukWLClc8SNKzHl .rough-node .label,#mermaid-svg-FSukWLClc8SNKzHl .node .label,#mermaid-svg-FSukWLClc8SNKzHl .image-shape .label,#mermaid-svg-FSukWLClc8SNKzHl .icon-shape .label{text-align:center;}#mermaid-svg-FSukWLClc8SNKzHl .node.clickable{cursor:pointer;}#mermaid-svg-FSukWLClc8SNKzHl .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FSukWLClc8SNKzHl .arrowheadPath{fill:#333333;}#mermaid-svg-FSukWLClc8SNKzHl .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FSukWLClc8SNKzHl .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FSukWLClc8SNKzHl .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FSukWLClc8SNKzHl .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FSukWLClc8SNKzHl .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FSukWLClc8SNKzHl .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FSukWLClc8SNKzHl .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FSukWLClc8SNKzHl .cluster text{fill:#333;}#mermaid-svg-FSukWLClc8SNKzHl .cluster span{color:#333;}#mermaid-svg-FSukWLClc8SNKzHl 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-FSukWLClc8SNKzHl .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FSukWLClc8SNKzHl rect.text{fill:none;stroke-width:0;}#mermaid-svg-FSukWLClc8SNKzHl .icon-shape,#mermaid-svg-FSukWLClc8SNKzHl .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FSukWLClc8SNKzHl .icon-shape p,#mermaid-svg-FSukWLClc8SNKzHl .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FSukWLClc8SNKzHl .icon-shape .label rect,#mermaid-svg-FSukWLClc8SNKzHl .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FSukWLClc8SNKzHl .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FSukWLClc8SNKzHl .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FSukWLClc8SNKzHl :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 查询向量
逐一计算距离
排序取 TopK
精确结果

特性

维度 表现
召回率 100%(精确搜索)
搜索速度 O(N),随数据量线性增长
内存 仅原始向量,无额外开销
构建时间 无(不需要构建)
适用规模 < 10 万条

在 Milvus 中使用

python 复制代码
index_params.add_index(
    field_name="embedding",
    index_type="FLAT",
    metric_type="COSINE",
)

何时用 FLAT

  • 数据量小(< 10 万),暴力扫描延迟可接受
  • 需要 100% 召回率的评测基准
  • 开发调试阶段,不想调索引参数

IVF(倒排文件索引)

IVF 的核心思想:先把向量空间聚成 nlist 个簇,搜索时只扫描最近的 nprobe 个簇

构建过程

#mermaid-svg-5Uog9Tald6FctqbN{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-5Uog9Tald6FctqbN .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5Uog9Tald6FctqbN .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5Uog9Tald6FctqbN .error-icon{fill:#552222;}#mermaid-svg-5Uog9Tald6FctqbN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5Uog9Tald6FctqbN .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5Uog9Tald6FctqbN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5Uog9Tald6FctqbN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5Uog9Tald6FctqbN .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5Uog9Tald6FctqbN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5Uog9Tald6FctqbN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5Uog9Tald6FctqbN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5Uog9Tald6FctqbN .marker.cross{stroke:#333333;}#mermaid-svg-5Uog9Tald6FctqbN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5Uog9Tald6FctqbN p{margin:0;}#mermaid-svg-5Uog9Tald6FctqbN .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5Uog9Tald6FctqbN .cluster-label text{fill:#333;}#mermaid-svg-5Uog9Tald6FctqbN .cluster-label span{color:#333;}#mermaid-svg-5Uog9Tald6FctqbN .cluster-label span p{background-color:transparent;}#mermaid-svg-5Uog9Tald6FctqbN .label text,#mermaid-svg-5Uog9Tald6FctqbN span{fill:#333;color:#333;}#mermaid-svg-5Uog9Tald6FctqbN .node rect,#mermaid-svg-5Uog9Tald6FctqbN .node circle,#mermaid-svg-5Uog9Tald6FctqbN .node ellipse,#mermaid-svg-5Uog9Tald6FctqbN .node polygon,#mermaid-svg-5Uog9Tald6FctqbN .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5Uog9Tald6FctqbN .rough-node .label text,#mermaid-svg-5Uog9Tald6FctqbN .node .label text,#mermaid-svg-5Uog9Tald6FctqbN .image-shape .label,#mermaid-svg-5Uog9Tald6FctqbN .icon-shape .label{text-anchor:middle;}#mermaid-svg-5Uog9Tald6FctqbN .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5Uog9Tald6FctqbN .rough-node .label,#mermaid-svg-5Uog9Tald6FctqbN .node .label,#mermaid-svg-5Uog9Tald6FctqbN .image-shape .label,#mermaid-svg-5Uog9Tald6FctqbN .icon-shape .label{text-align:center;}#mermaid-svg-5Uog9Tald6FctqbN .node.clickable{cursor:pointer;}#mermaid-svg-5Uog9Tald6FctqbN .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5Uog9Tald6FctqbN .arrowheadPath{fill:#333333;}#mermaid-svg-5Uog9Tald6FctqbN .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5Uog9Tald6FctqbN .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5Uog9Tald6FctqbN .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5Uog9Tald6FctqbN .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5Uog9Tald6FctqbN .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5Uog9Tald6FctqbN .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5Uog9Tald6FctqbN .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5Uog9Tald6FctqbN .cluster text{fill:#333;}#mermaid-svg-5Uog9Tald6FctqbN .cluster span{color:#333;}#mermaid-svg-5Uog9Tald6FctqbN 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-5Uog9Tald6FctqbN .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5Uog9Tald6FctqbN rect.text{fill:none;stroke-width:0;}#mermaid-svg-5Uog9Tald6FctqbN .icon-shape,#mermaid-svg-5Uog9Tald6FctqbN .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5Uog9Tald6FctqbN .icon-shape p,#mermaid-svg-5Uog9Tald6FctqbN .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5Uog9Tald6FctqbN .icon-shape .label rect,#mermaid-svg-5Uog9Tald6FctqbN .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5Uog9Tald6FctqbN .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5Uog9Tald6FctqbN .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5Uog9Tald6FctqbN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 全部向量
KMeans 聚类
簇 1: 中心 C1
簇 2: 中心 C2
簇 3: 中心 C3
簇 N: 中心 CN
倒排列表 1

属于簇 1 的所有向量
倒排列表 2
倒排列表 3
倒排列表 N

搜索过程

#mermaid-svg-laSycC6vizSw2LxA{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-laSycC6vizSw2LxA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-laSycC6vizSw2LxA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-laSycC6vizSw2LxA .error-icon{fill:#552222;}#mermaid-svg-laSycC6vizSw2LxA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-laSycC6vizSw2LxA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-laSycC6vizSw2LxA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-laSycC6vizSw2LxA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-laSycC6vizSw2LxA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-laSycC6vizSw2LxA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-laSycC6vizSw2LxA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-laSycC6vizSw2LxA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-laSycC6vizSw2LxA .marker.cross{stroke:#333333;}#mermaid-svg-laSycC6vizSw2LxA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-laSycC6vizSw2LxA p{margin:0;}#mermaid-svg-laSycC6vizSw2LxA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-laSycC6vizSw2LxA .cluster-label text{fill:#333;}#mermaid-svg-laSycC6vizSw2LxA .cluster-label span{color:#333;}#mermaid-svg-laSycC6vizSw2LxA .cluster-label span p{background-color:transparent;}#mermaid-svg-laSycC6vizSw2LxA .label text,#mermaid-svg-laSycC6vizSw2LxA span{fill:#333;color:#333;}#mermaid-svg-laSycC6vizSw2LxA .node rect,#mermaid-svg-laSycC6vizSw2LxA .node circle,#mermaid-svg-laSycC6vizSw2LxA .node ellipse,#mermaid-svg-laSycC6vizSw2LxA .node polygon,#mermaid-svg-laSycC6vizSw2LxA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-laSycC6vizSw2LxA .rough-node .label text,#mermaid-svg-laSycC6vizSw2LxA .node .label text,#mermaid-svg-laSycC6vizSw2LxA .image-shape .label,#mermaid-svg-laSycC6vizSw2LxA .icon-shape .label{text-anchor:middle;}#mermaid-svg-laSycC6vizSw2LxA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-laSycC6vizSw2LxA .rough-node .label,#mermaid-svg-laSycC6vizSw2LxA .node .label,#mermaid-svg-laSycC6vizSw2LxA .image-shape .label,#mermaid-svg-laSycC6vizSw2LxA .icon-shape .label{text-align:center;}#mermaid-svg-laSycC6vizSw2LxA .node.clickable{cursor:pointer;}#mermaid-svg-laSycC6vizSw2LxA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-laSycC6vizSw2LxA .arrowheadPath{fill:#333333;}#mermaid-svg-laSycC6vizSw2LxA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-laSycC6vizSw2LxA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-laSycC6vizSw2LxA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-laSycC6vizSw2LxA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-laSycC6vizSw2LxA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-laSycC6vizSw2LxA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-laSycC6vizSw2LxA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-laSycC6vizSw2LxA .cluster text{fill:#333;}#mermaid-svg-laSycC6vizSw2LxA .cluster span{color:#333;}#mermaid-svg-laSycC6vizSw2LxA 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-laSycC6vizSw2LxA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-laSycC6vizSw2LxA rect.text{fill:none;stroke-width:0;}#mermaid-svg-laSycC6vizSw2LxA .icon-shape,#mermaid-svg-laSycC6vizSw2LxA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-laSycC6vizSw2LxA .icon-shape p,#mermaid-svg-laSycC6vizSw2LxA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-laSycC6vizSw2LxA .icon-shape .label rect,#mermaid-svg-laSycC6vizSw2LxA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-laSycC6vizSw2LxA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-laSycC6vizSw2LxA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-laSycC6vizSw2LxA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 查询向量
计算与所有中心的距离
选择最近的 nprobe 个中心
扫描这 nprobe 个列表中的向量
排序取 TopK

参数详解

参数 阶段 作用 增大的影响
nlist 构建 聚类中心数量 每个列表更短,搜索更快,但边界效应增加
nprobe 搜索 探测的列表数量 召回更高,延迟更大

nlist 经验值nlist ≈ 4 × sqrt(N),N 为向量总数。100 万条 → nlist ≈ 4000。

nprobe 与召回的关系

nprobe / nlist 典型召回率 说明
1% 60-70% 太低,不建议
5% 85-90% 可接受
10% 92-96% 推荐起点
20%+ 97%+ 接近暴力扫描

IVF 变体

变体 区别 内存 精度
IVF_FLAT 列表中存原始向量
IVF_SQ8 列表中存 8bit 量化向量 低 ~25% 略低
IVF_PQ 列表中存 PQ 编码 很低 较低

在 Milvus 中使用

python 复制代码
index_params.add_index(
    field_name="embedding",
    index_type="IVF_FLAT",
    metric_type="COSINE",
    params={"nlist": 1024},
)

# 搜索时
search_params = {
    "metric_type": "COSINE",
    "params": {"nprobe": 64},
}

HNSW(分层可导航小世界图)

HNSW 是目前最流行的高性能索引。核心思想:建一张多层图,高层稀疏用于快速接近目标,底层密集用于精细搜索

数据结构

#mermaid-svg-pUNPHZLclPvJxuRH{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-pUNPHZLclPvJxuRH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-pUNPHZLclPvJxuRH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-pUNPHZLclPvJxuRH .error-icon{fill:#552222;}#mermaid-svg-pUNPHZLclPvJxuRH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-pUNPHZLclPvJxuRH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-pUNPHZLclPvJxuRH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-pUNPHZLclPvJxuRH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-pUNPHZLclPvJxuRH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-pUNPHZLclPvJxuRH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-pUNPHZLclPvJxuRH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-pUNPHZLclPvJxuRH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-pUNPHZLclPvJxuRH .marker.cross{stroke:#333333;}#mermaid-svg-pUNPHZLclPvJxuRH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-pUNPHZLclPvJxuRH p{margin:0;}#mermaid-svg-pUNPHZLclPvJxuRH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-pUNPHZLclPvJxuRH .cluster-label text{fill:#333;}#mermaid-svg-pUNPHZLclPvJxuRH .cluster-label span{color:#333;}#mermaid-svg-pUNPHZLclPvJxuRH .cluster-label span p{background-color:transparent;}#mermaid-svg-pUNPHZLclPvJxuRH .label text,#mermaid-svg-pUNPHZLclPvJxuRH span{fill:#333;color:#333;}#mermaid-svg-pUNPHZLclPvJxuRH .node rect,#mermaid-svg-pUNPHZLclPvJxuRH .node circle,#mermaid-svg-pUNPHZLclPvJxuRH .node ellipse,#mermaid-svg-pUNPHZLclPvJxuRH .node polygon,#mermaid-svg-pUNPHZLclPvJxuRH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-pUNPHZLclPvJxuRH .rough-node .label text,#mermaid-svg-pUNPHZLclPvJxuRH .node .label text,#mermaid-svg-pUNPHZLclPvJxuRH .image-shape .label,#mermaid-svg-pUNPHZLclPvJxuRH .icon-shape .label{text-anchor:middle;}#mermaid-svg-pUNPHZLclPvJxuRH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-pUNPHZLclPvJxuRH .rough-node .label,#mermaid-svg-pUNPHZLclPvJxuRH .node .label,#mermaid-svg-pUNPHZLclPvJxuRH .image-shape .label,#mermaid-svg-pUNPHZLclPvJxuRH .icon-shape .label{text-align:center;}#mermaid-svg-pUNPHZLclPvJxuRH .node.clickable{cursor:pointer;}#mermaid-svg-pUNPHZLclPvJxuRH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-pUNPHZLclPvJxuRH .arrowheadPath{fill:#333333;}#mermaid-svg-pUNPHZLclPvJxuRH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-pUNPHZLclPvJxuRH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-pUNPHZLclPvJxuRH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pUNPHZLclPvJxuRH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-pUNPHZLclPvJxuRH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pUNPHZLclPvJxuRH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-pUNPHZLclPvJxuRH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-pUNPHZLclPvJxuRH .cluster text{fill:#333;}#mermaid-svg-pUNPHZLclPvJxuRH .cluster span{color:#333;}#mermaid-svg-pUNPHZLclPvJxuRH 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-pUNPHZLclPvJxuRH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-pUNPHZLclPvJxuRH rect.text{fill:none;stroke-width:0;}#mermaid-svg-pUNPHZLclPvJxuRH .icon-shape,#mermaid-svg-pUNPHZLclPvJxuRH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pUNPHZLclPvJxuRH .icon-shape p,#mermaid-svg-pUNPHZLclPvJxuRH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-pUNPHZLclPvJxuRH .icon-shape .label rect,#mermaid-svg-pUNPHZLclPvJxuRH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pUNPHZLclPvJxuRH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-pUNPHZLclPvJxuRH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-pUNPHZLclPvJxuRH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Layer 0 - 密集邻接图(所有节点)
A
B
C
D
E
F
G
Layer 1 - 区域道路
A
B
D
F
G
Layer 2 - 高速公路
长距离边
长距离边
A
D
G

搜索过程

#mermaid-svg-XXHakTGLn9krfFy1{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-XXHakTGLn9krfFy1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XXHakTGLn9krfFy1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XXHakTGLn9krfFy1 .error-icon{fill:#552222;}#mermaid-svg-XXHakTGLn9krfFy1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XXHakTGLn9krfFy1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XXHakTGLn9krfFy1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XXHakTGLn9krfFy1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XXHakTGLn9krfFy1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XXHakTGLn9krfFy1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XXHakTGLn9krfFy1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XXHakTGLn9krfFy1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XXHakTGLn9krfFy1 .marker.cross{stroke:#333333;}#mermaid-svg-XXHakTGLn9krfFy1 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XXHakTGLn9krfFy1 p{margin:0;}#mermaid-svg-XXHakTGLn9krfFy1 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-XXHakTGLn9krfFy1 .cluster-label text{fill:#333;}#mermaid-svg-XXHakTGLn9krfFy1 .cluster-label span{color:#333;}#mermaid-svg-XXHakTGLn9krfFy1 .cluster-label span p{background-color:transparent;}#mermaid-svg-XXHakTGLn9krfFy1 .label text,#mermaid-svg-XXHakTGLn9krfFy1 span{fill:#333;color:#333;}#mermaid-svg-XXHakTGLn9krfFy1 .node rect,#mermaid-svg-XXHakTGLn9krfFy1 .node circle,#mermaid-svg-XXHakTGLn9krfFy1 .node ellipse,#mermaid-svg-XXHakTGLn9krfFy1 .node polygon,#mermaid-svg-XXHakTGLn9krfFy1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XXHakTGLn9krfFy1 .rough-node .label text,#mermaid-svg-XXHakTGLn9krfFy1 .node .label text,#mermaid-svg-XXHakTGLn9krfFy1 .image-shape .label,#mermaid-svg-XXHakTGLn9krfFy1 .icon-shape .label{text-anchor:middle;}#mermaid-svg-XXHakTGLn9krfFy1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XXHakTGLn9krfFy1 .rough-node .label,#mermaid-svg-XXHakTGLn9krfFy1 .node .label,#mermaid-svg-XXHakTGLn9krfFy1 .image-shape .label,#mermaid-svg-XXHakTGLn9krfFy1 .icon-shape .label{text-align:center;}#mermaid-svg-XXHakTGLn9krfFy1 .node.clickable{cursor:pointer;}#mermaid-svg-XXHakTGLn9krfFy1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XXHakTGLn9krfFy1 .arrowheadPath{fill:#333333;}#mermaid-svg-XXHakTGLn9krfFy1 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XXHakTGLn9krfFy1 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XXHakTGLn9krfFy1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XXHakTGLn9krfFy1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XXHakTGLn9krfFy1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XXHakTGLn9krfFy1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XXHakTGLn9krfFy1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XXHakTGLn9krfFy1 .cluster text{fill:#333;}#mermaid-svg-XXHakTGLn9krfFy1 .cluster span{color:#333;}#mermaid-svg-XXHakTGLn9krfFy1 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-XXHakTGLn9krfFy1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XXHakTGLn9krfFy1 rect.text{fill:none;stroke-width:0;}#mermaid-svg-XXHakTGLn9krfFy1 .icon-shape,#mermaid-svg-XXHakTGLn9krfFy1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XXHakTGLn9krfFy1 .icon-shape p,#mermaid-svg-XXHakTGLn9krfFy1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XXHakTGLn9krfFy1 .icon-shape .label rect,#mermaid-svg-XXHakTGLn9krfFy1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XXHakTGLn9krfFy1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XXHakTGLn9krfFy1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XXHakTGLn9krfFy1 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 查询向量
从最高层入口开始
贪心导航到最近节点
下降到下一层
继续贪心导航
下降到 Layer 0
在底层精细搜索

维护 ef 大小的候选集
从候选集取 TopK

参数详解

参数 阶段 作用 增大的影响
M 构建 每个节点的最大邻居数 图更密,召回更好,内存更高
efConstruction 构建 构建时的候选集大小 图质量更好,构建更慢
ef 搜索 搜索时的候选集大小 召回更高,延迟更大

参数经验值

场景 M efConstruction ef
低延迟优先 8-12 100 32-64
平衡 16 200 64-128
高召回优先 32-48 400 128-256

约束ef >= limit(TopK),否则候选集不够大。

内存估算

复制代码
HNSW 内存 ≈ 原始向量 + 图结构
         = N × dim × 4B + N × M × 2 × 8B

示例(100 万条,768 维,M=16):
= 1M × 768 × 4 + 1M × 16 × 2 × 8
= 2.87 GB + 0.24 GB
≈ 3.1 GB

在 Milvus 中使用

python 复制代码
index_params.add_index(
    field_name="embedding",
    index_type="HNSW",
    metric_type="COSINE",
    params={"M": 16, "efConstruction": 200},
)

# 搜索时
search_params = {
    "metric_type": "COSINE",
    "params": {"ef": 128},
}

PQ(乘积量化)

PQ 的核心思想:把高维向量切成多段,每段用码本近似表示,大幅压缩存储

编码过程

#mermaid-svg-T8pPf2gxrxjXQ9WK{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-T8pPf2gxrxjXQ9WK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-T8pPf2gxrxjXQ9WK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-T8pPf2gxrxjXQ9WK .error-icon{fill:#552222;}#mermaid-svg-T8pPf2gxrxjXQ9WK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-T8pPf2gxrxjXQ9WK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-T8pPf2gxrxjXQ9WK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-T8pPf2gxrxjXQ9WK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-T8pPf2gxrxjXQ9WK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-T8pPf2gxrxjXQ9WK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-T8pPf2gxrxjXQ9WK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-T8pPf2gxrxjXQ9WK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-T8pPf2gxrxjXQ9WK .marker.cross{stroke:#333333;}#mermaid-svg-T8pPf2gxrxjXQ9WK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-T8pPf2gxrxjXQ9WK p{margin:0;}#mermaid-svg-T8pPf2gxrxjXQ9WK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-T8pPf2gxrxjXQ9WK .cluster-label text{fill:#333;}#mermaid-svg-T8pPf2gxrxjXQ9WK .cluster-label span{color:#333;}#mermaid-svg-T8pPf2gxrxjXQ9WK .cluster-label span p{background-color:transparent;}#mermaid-svg-T8pPf2gxrxjXQ9WK .label text,#mermaid-svg-T8pPf2gxrxjXQ9WK span{fill:#333;color:#333;}#mermaid-svg-T8pPf2gxrxjXQ9WK .node rect,#mermaid-svg-T8pPf2gxrxjXQ9WK .node circle,#mermaid-svg-T8pPf2gxrxjXQ9WK .node ellipse,#mermaid-svg-T8pPf2gxrxjXQ9WK .node polygon,#mermaid-svg-T8pPf2gxrxjXQ9WK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-T8pPf2gxrxjXQ9WK .rough-node .label text,#mermaid-svg-T8pPf2gxrxjXQ9WK .node .label text,#mermaid-svg-T8pPf2gxrxjXQ9WK .image-shape .label,#mermaid-svg-T8pPf2gxrxjXQ9WK .icon-shape .label{text-anchor:middle;}#mermaid-svg-T8pPf2gxrxjXQ9WK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-T8pPf2gxrxjXQ9WK .rough-node .label,#mermaid-svg-T8pPf2gxrxjXQ9WK .node .label,#mermaid-svg-T8pPf2gxrxjXQ9WK .image-shape .label,#mermaid-svg-T8pPf2gxrxjXQ9WK .icon-shape .label{text-align:center;}#mermaid-svg-T8pPf2gxrxjXQ9WK .node.clickable{cursor:pointer;}#mermaid-svg-T8pPf2gxrxjXQ9WK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-T8pPf2gxrxjXQ9WK .arrowheadPath{fill:#333333;}#mermaid-svg-T8pPf2gxrxjXQ9WK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-T8pPf2gxrxjXQ9WK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-T8pPf2gxrxjXQ9WK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-T8pPf2gxrxjXQ9WK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-T8pPf2gxrxjXQ9WK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-T8pPf2gxrxjXQ9WK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-T8pPf2gxrxjXQ9WK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-T8pPf2gxrxjXQ9WK .cluster text{fill:#333;}#mermaid-svg-T8pPf2gxrxjXQ9WK .cluster span{color:#333;}#mermaid-svg-T8pPf2gxrxjXQ9WK 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-T8pPf2gxrxjXQ9WK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-T8pPf2gxrxjXQ9WK rect.text{fill:none;stroke-width:0;}#mermaid-svg-T8pPf2gxrxjXQ9WK .icon-shape,#mermaid-svg-T8pPf2gxrxjXQ9WK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-T8pPf2gxrxjXQ9WK .icon-shape p,#mermaid-svg-T8pPf2gxrxjXQ9WK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-T8pPf2gxrxjXQ9WK .icon-shape .label rect,#mermaid-svg-T8pPf2gxrxjXQ9WK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-T8pPf2gxrxjXQ9WK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-T8pPf2gxrxjXQ9WK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-T8pPf2gxrxjXQ9WK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 768 维向量
切成 m=96 段

每段 8 维
每段查码本

256 个聚类中心
每段用 1 字节编码
768 维 → 96 字节

压缩比 32:1

搜索过程

PQ 搜索不需要解码原始向量,而是用预计算的距离表快速估算近似距离:
#mermaid-svg-3ZXYYh0GTVhNzfZ7{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-3ZXYYh0GTVhNzfZ7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .error-icon{fill:#552222;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .marker.cross{stroke:#333333;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 p{margin:0;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .cluster-label text{fill:#333;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .cluster-label span{color:#333;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .cluster-label span p{background-color:transparent;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .label text,#mermaid-svg-3ZXYYh0GTVhNzfZ7 span{fill:#333;color:#333;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .node rect,#mermaid-svg-3ZXYYh0GTVhNzfZ7 .node circle,#mermaid-svg-3ZXYYh0GTVhNzfZ7 .node ellipse,#mermaid-svg-3ZXYYh0GTVhNzfZ7 .node polygon,#mermaid-svg-3ZXYYh0GTVhNzfZ7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .rough-node .label text,#mermaid-svg-3ZXYYh0GTVhNzfZ7 .node .label text,#mermaid-svg-3ZXYYh0GTVhNzfZ7 .image-shape .label,#mermaid-svg-3ZXYYh0GTVhNzfZ7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .rough-node .label,#mermaid-svg-3ZXYYh0GTVhNzfZ7 .node .label,#mermaid-svg-3ZXYYh0GTVhNzfZ7 .image-shape .label,#mermaid-svg-3ZXYYh0GTVhNzfZ7 .icon-shape .label{text-align:center;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .node.clickable{cursor:pointer;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .arrowheadPath{fill:#333333;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .cluster text{fill:#333;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .cluster span{color:#333;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 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-3ZXYYh0GTVhNzfZ7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .icon-shape,#mermaid-svg-3ZXYYh0GTVhNzfZ7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .icon-shape p,#mermaid-svg-3ZXYYh0GTVhNzfZ7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .icon-shape .label rect,#mermaid-svg-3ZXYYh0GTVhNzfZ7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-3ZXYYh0GTVhNzfZ7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 查询向量
切成 m 段
预计算:每段与 256 个中心的距离
对每条数据:查表累加 m 段距离
近似 TopK

参数详解

参数 作用 典型值
m 子空间数量 dim 的因子,如 768 维用 96 或 192
nbits 每段编码位数 通常 8(256 个中心)

压缩效果

原始大小 PQ 编码 (m=96, nbits=8) 压缩比
768 × 4B = 3072B 96 × 1B = 96B 32×
1536 × 4B = 6144B 192 × 1B = 192B 32×

代价

  • 召回率下降(量化误差)
  • 不适合小数据量(码本训练需要足够数据)
  • 通常与 IVF 组合使用(IVF_PQ)

在 Milvus 中使用

python 复制代码
index_params.add_index(
    field_name="embedding",
    index_type="IVF_PQ",
    metric_type="L2",
    params={"nlist": 1024, "m": 96, "nbits": 8},
)

DISKANN

DISKANN 把图索引存在磁盘上,只在内存中保留压缩的导航结构。适合超大规模、内存受限的场景。
#mermaid-svg-ou17n5j4wKFcXV5D{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-ou17n5j4wKFcXV5D .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ou17n5j4wKFcXV5D .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ou17n5j4wKFcXV5D .error-icon{fill:#552222;}#mermaid-svg-ou17n5j4wKFcXV5D .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ou17n5j4wKFcXV5D .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ou17n5j4wKFcXV5D .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ou17n5j4wKFcXV5D .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ou17n5j4wKFcXV5D .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ou17n5j4wKFcXV5D .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ou17n5j4wKFcXV5D .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ou17n5j4wKFcXV5D .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ou17n5j4wKFcXV5D .marker.cross{stroke:#333333;}#mermaid-svg-ou17n5j4wKFcXV5D svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ou17n5j4wKFcXV5D p{margin:0;}#mermaid-svg-ou17n5j4wKFcXV5D .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ou17n5j4wKFcXV5D .cluster-label text{fill:#333;}#mermaid-svg-ou17n5j4wKFcXV5D .cluster-label span{color:#333;}#mermaid-svg-ou17n5j4wKFcXV5D .cluster-label span p{background-color:transparent;}#mermaid-svg-ou17n5j4wKFcXV5D .label text,#mermaid-svg-ou17n5j4wKFcXV5D span{fill:#333;color:#333;}#mermaid-svg-ou17n5j4wKFcXV5D .node rect,#mermaid-svg-ou17n5j4wKFcXV5D .node circle,#mermaid-svg-ou17n5j4wKFcXV5D .node ellipse,#mermaid-svg-ou17n5j4wKFcXV5D .node polygon,#mermaid-svg-ou17n5j4wKFcXV5D .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ou17n5j4wKFcXV5D .rough-node .label text,#mermaid-svg-ou17n5j4wKFcXV5D .node .label text,#mermaid-svg-ou17n5j4wKFcXV5D .image-shape .label,#mermaid-svg-ou17n5j4wKFcXV5D .icon-shape .label{text-anchor:middle;}#mermaid-svg-ou17n5j4wKFcXV5D .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ou17n5j4wKFcXV5D .rough-node .label,#mermaid-svg-ou17n5j4wKFcXV5D .node .label,#mermaid-svg-ou17n5j4wKFcXV5D .image-shape .label,#mermaid-svg-ou17n5j4wKFcXV5D .icon-shape .label{text-align:center;}#mermaid-svg-ou17n5j4wKFcXV5D .node.clickable{cursor:pointer;}#mermaid-svg-ou17n5j4wKFcXV5D .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ou17n5j4wKFcXV5D .arrowheadPath{fill:#333333;}#mermaid-svg-ou17n5j4wKFcXV5D .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ou17n5j4wKFcXV5D .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ou17n5j4wKFcXV5D .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ou17n5j4wKFcXV5D .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ou17n5j4wKFcXV5D .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ou17n5j4wKFcXV5D .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ou17n5j4wKFcXV5D .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ou17n5j4wKFcXV5D .cluster text{fill:#333;}#mermaid-svg-ou17n5j4wKFcXV5D .cluster span{color:#333;}#mermaid-svg-ou17n5j4wKFcXV5D 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-ou17n5j4wKFcXV5D .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ou17n5j4wKFcXV5D rect.text{fill:none;stroke-width:0;}#mermaid-svg-ou17n5j4wKFcXV5D .icon-shape,#mermaid-svg-ou17n5j4wKFcXV5D .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ou17n5j4wKFcXV5D .icon-shape p,#mermaid-svg-ou17n5j4wKFcXV5D .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ou17n5j4wKFcXV5D .icon-shape .label rect,#mermaid-svg-ou17n5j4wKFcXV5D .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ou17n5j4wKFcXV5D .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ou17n5j4wKFcXV5D .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ou17n5j4wKFcXV5D :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 磁盘
内存
PQ 压缩向量

用于粗排
导航图入口
完整向量 + 图结构
查询
粗排候选集
精排 TopK

特性

维度 表现
内存 极低(仅 PQ 编码 + 导航结构)
延迟 中等(涉及磁盘 IO)
召回率 中高(PQ 粗排 + 原始向量精排)
适用规模 > 1 亿条

在 Milvus 中使用

python 复制代码
index_params.add_index(
    field_name="embedding",
    index_type="DISKANN",
    metric_type="COSINE",
)

# 搜索时
search_params = {
    "metric_type": "COSINE",
    "params": {"search_list": 100},  # 候选集大小
}

索引选择决策

#mermaid-svg-hrA3A42zPObEnhAQ{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-hrA3A42zPObEnhAQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-hrA3A42zPObEnhAQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-hrA3A42zPObEnhAQ .error-icon{fill:#552222;}#mermaid-svg-hrA3A42zPObEnhAQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hrA3A42zPObEnhAQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-hrA3A42zPObEnhAQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hrA3A42zPObEnhAQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hrA3A42zPObEnhAQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-hrA3A42zPObEnhAQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hrA3A42zPObEnhAQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hrA3A42zPObEnhAQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hrA3A42zPObEnhAQ .marker.cross{stroke:#333333;}#mermaid-svg-hrA3A42zPObEnhAQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hrA3A42zPObEnhAQ p{margin:0;}#mermaid-svg-hrA3A42zPObEnhAQ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-hrA3A42zPObEnhAQ .cluster-label text{fill:#333;}#mermaid-svg-hrA3A42zPObEnhAQ .cluster-label span{color:#333;}#mermaid-svg-hrA3A42zPObEnhAQ .cluster-label span p{background-color:transparent;}#mermaid-svg-hrA3A42zPObEnhAQ .label text,#mermaid-svg-hrA3A42zPObEnhAQ span{fill:#333;color:#333;}#mermaid-svg-hrA3A42zPObEnhAQ .node rect,#mermaid-svg-hrA3A42zPObEnhAQ .node circle,#mermaid-svg-hrA3A42zPObEnhAQ .node ellipse,#mermaid-svg-hrA3A42zPObEnhAQ .node polygon,#mermaid-svg-hrA3A42zPObEnhAQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hrA3A42zPObEnhAQ .rough-node .label text,#mermaid-svg-hrA3A42zPObEnhAQ .node .label text,#mermaid-svg-hrA3A42zPObEnhAQ .image-shape .label,#mermaid-svg-hrA3A42zPObEnhAQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-hrA3A42zPObEnhAQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-hrA3A42zPObEnhAQ .rough-node .label,#mermaid-svg-hrA3A42zPObEnhAQ .node .label,#mermaid-svg-hrA3A42zPObEnhAQ .image-shape .label,#mermaid-svg-hrA3A42zPObEnhAQ .icon-shape .label{text-align:center;}#mermaid-svg-hrA3A42zPObEnhAQ .node.clickable{cursor:pointer;}#mermaid-svg-hrA3A42zPObEnhAQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-hrA3A42zPObEnhAQ .arrowheadPath{fill:#333333;}#mermaid-svg-hrA3A42zPObEnhAQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-hrA3A42zPObEnhAQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-hrA3A42zPObEnhAQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hrA3A42zPObEnhAQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-hrA3A42zPObEnhAQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hrA3A42zPObEnhAQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-hrA3A42zPObEnhAQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-hrA3A42zPObEnhAQ .cluster text{fill:#333;}#mermaid-svg-hrA3A42zPObEnhAQ .cluster span{color:#333;}#mermaid-svg-hrA3A42zPObEnhAQ 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-hrA3A42zPObEnhAQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-hrA3A42zPObEnhAQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-hrA3A42zPObEnhAQ .icon-shape,#mermaid-svg-hrA3A42zPObEnhAQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hrA3A42zPObEnhAQ .icon-shape p,#mermaid-svg-hrA3A42zPObEnhAQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-hrA3A42zPObEnhAQ .icon-shape .label rect,#mermaid-svg-hrA3A42zPObEnhAQ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hrA3A42zPObEnhAQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-hrA3A42zPObEnhAQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-hrA3A42zPObEnhAQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} < 10 万
10 万 - 500 万
500 万 - 5000 万
> 5000 万




选择索引
数据规模
FLAT
内存充足?
内存充足?
DISKANN 或 IVF_PQ
HNSW
IVF_FLAT 或 IVF_SQ8
HNSW
IVF_PQ

综合对比

索引 内存 构建速度 搜索速度 召回率 适用规模
FLAT 无需构建 100% < 10 万
IVF_FLAT 10 万 - 1000 万
IVF_SQ8 较低 较高 10 万 - 1000 万
HNSW 很快 很高 10 万 - 5000 万
IVF_PQ > 1000 万
DISKANN 极低 中高 > 5000 万

选择原则

  1. 默认选 HNSW:大多数场景(< 2000 万条)HNSW 是最佳平衡
  2. 内存不够选 IVF_SQ8 或 IVF_PQ:用量化换内存
  3. 超大规模选 DISKANN:亿级数据的唯一选择
  4. 需要精确结果选 FLAT:评测基准或小数据量

索引构建与切换

查看当前索引

python 复制代码
info = client.describe_collection("articles")
for index in info.get("indexes", []):
    print(f"字段: {index['field_name']}, 类型: {index['index_type']}")

重建索引

Milvus 不支持原地修改索引参数。需要先删除再重建:

python 复制代码
# 释放 Collection
client.release_collection("articles")

# 删除旧索引
client.drop_index(collection_name="articles", index_name="embedding_idx")

# 创建新索引
index_params = MilvusClient.prepare_index_params()
index_params.add_index(
    field_name="embedding",
    index_name="embedding_idx",
    index_type="IVF_FLAT",
    metric_type="COSINE",
    params={"nlist": 2048},
)
client.create_index(collection_name="articles", index_params=index_params)

# 重新加载
client.load_collection("articles")

常见错误

现象 原因 修复
HNSW 内存爆掉 数据量大 + M 值高 降低 M,或换 IVF/DISKANN
IVF 召回率低 nprobe 太小 增大 nprobe,或增大 nlist
PQ 搜索结果差 数据量太少,码本训练不充分 数据 > 10 万条再用 PQ
索引构建超时 数据量大 + efConstruction 高 降低 efConstruction,或增加 IndexNode 资源
搜索延迟不稳定 ef/nprobe 设置过高 找到召回和延迟的平衡点
DISKANN 延迟高 磁盘 IO 慢 使用 SSD,增大内存缓存

面试题

  1. HNSW 为什么比 IVF 搜索更快但内存更高?

    HNSW 用图结构导航,搜索路径短(O(log N)),但每个节点需要存储 M 个邻居指针。IVF 只存聚类中心,但搜索时需要扫描整个倒排列表。

  2. IVF 的 nlist 设太大或太小分别有什么问题?

    太大:每个列表太短,边界效应严重(相近向量被分到不同簇),需要更大 nprobe 补偿。太小:每个列表太长,搜索退化为暴力扫描。

  3. PQ 为什么能压缩 32 倍但召回率只降几个点?

    PQ 利用了向量各维度之间的统计独立性假设。子空间内用 256 个中心近似,误差在多个子空间累加后仍然可控。但对于维度间强相关的数据,PQ 效果会变差。

  4. 为什么 ef 必须 >= limit(TopK)?

    ef 是搜索时维护的候选集大小。如果 ef < limit,候选集装不下 TopK 个结果,返回数量会不足。

  5. 什么场景下 FLAT 反而是最优选择?

    数据量 < 10 万、需要 100% 召回率、或作为评测基准。此时 FLAT 的延迟可接受(< 50ms),且无需调参、无构建开销。


练习题

  1. 索引对比实验:准备 10 万条 768 维随机向量,分别用 FLAT、IVF_FLAT(nlist=256)、HNSW(M=16) 建索引。对比构建时间、内存占用和搜索延迟(固定 TopK=10)。

  2. nprobe 调优:用 IVF_FLAT(nlist=1024) 索引 50 万条向量。nprobe 从 8、16、32、64、128、256 逐步增大,记录每个值的搜索延迟和召回率(以 FLAT 结果为基准)。画出 nprobe-recall 和 nprobe-latency 曲线。

  3. HNSW 参数实验:固定 50 万条数据,分别用 M=8/16/32、efConstruction=100/200/400 的组合建索引。记录构建时间和内存。搜索时用 ef=64/128/256,记录延迟和召回率。

  4. PQ 压缩效果:对比 IVF_FLAT 和 IVF_PQ 在 100 万条数据上的内存占用和召回率差异。


小结

向量索引是"用可控精度损失换取搜索加速"的工程工具。HNSW 是大多数场景的默认选择(高召回、低延迟、高内存),IVF 系列适合内存受限场景,PQ 和 DISKANN 面向超大规模。选择索引后,通过参数调优(ef、nprobe、M)在召回率和延迟之间找到业务可接受的平衡点。

相关推荐
qq_316837755 小时前
华为CCE 部署milvus向量数据库
milvus
救救孩子把6 小时前
10 Milvus-IVF原理与实战
milvus
金融支付架构实战指南1 天前
Milvus 向量检索服务 + SpringBoot 实战:电商商品语义检索与相似商品推荐
spring boot·后端·milvus·向量检索
程序员佳佳1 天前
四个月长期实测:自建 Milvus、FAISS、原生向量 API 和向量引擎中转方案,到底怎么选?
人工智能·windows·python·gpt·milvus·faiss
kishu_iOS&AI1 天前
LLM —— Milvmus向量数据库
数据库·人工智能·milvus
_张一凡2 天前
通往RAG之路(五):主流向量数据库全景解析与选型指南
pinecone·milvus·向量数据库·chroma·qdrant·rag系统搭建
王小王-1233 天前
从 Chroma 到 Milvus:一套 Agentic RAG 知识库的工程实践
milvus·chroma·rag·智能体·bm25·检索增强生成·agentic rag
啾啾Fun3 天前
【向量数据库】Milvus:为大规模、高性能而生的企业级向量数据库
数据库·milvus
救救孩子把4 天前
02 Milvus-Milvus整体架构
架构·milvus