← blog AI Agent · 2026-04-09

vector-db-retrieval-algorithms

深入解析主流向量数据库检索算法,包括HNSW、IVF、PQ、LSH等,涵盖算法原理、参数调优、选型决策及代码实战

8 min read

向量检索是现代 AI 应用的核心技术之一,广泛应用于语义搜索、推荐系统、图像检索等场景。本文将深入解析主流向量数据库采用的检索算法,并提供实用的选型和配置指南。

一、常用检索算法分类

1.1 HNSW (Hierarchical Navigable Small World)

HNSW 是一种基于多层图结构的近似最近邻搜索算法,被视为当前最流行的向量索引算法。

核心特点:

  • 多层图结构,自顶向下构建稀疏连接
  • 查询速度:O(log n),适合实时检索场景
  • 召回率:95-99%,精度表现优异
  • 内存占用较高,以空间换时间

工作原理: HNSW 构建一个多层图,上层节点连接较远,下层节点连接较近。查询时从最上层开始,通过贪心搜索快速定位,逐步向下层细化,最终找到最近邻。

1.2 IVF (Inverted File Index)

IVF 采用倒排索引思想,先将向量空间聚类划分,查询时只需搜索部分聚类中心。

核心特点:

  • 先聚类后搜索,搜索范围可控
  • 支持增量索引,无需全量重建
  • 召回率取决于探查簇数量
  • 可与 PQ 结合进一步压缩

1.3 PQ (Product Quantization)

Product Quantization 将高维向量分割成多个子空间,分别进行量化编码。

核心特点:

  • 高压缩比:10-50x 内存压缩
  • 支持亿级向量规模
  • 查询速度受分段数影响
  • 常与 IVF 结合使用(IVF-PQ)

1.4 LSH (Locality-Sensitive Hashing)

LSH 通过哈希函数将相似向量映射到相同桶中。

核心特点:

  • 适合稀疏向量检索
  • 天然支持去重任务
  • 需要较多哈希表达到高精度
  • 查询召回率相对较低

1.5 HNSW + IVF 混合

结合两者优点,在 HNSW 图结构上叠加 IVF 索引层,进一步提升大规模数据下的检索效率。


二、核心参数详解

2.1 HNSW 参数

参数含义推荐值说明
M每节点最大邻居数16-64注意:指每个节点最多连接的节点数,而非每层节点数
efConstruction构建时搜索广度100-400值越大构建越慢,但索引质量越高
efSearch查询时搜索广度50-500值越大召回率越高,但查询延迟上升

参数调优建议:

  • 数据量小、精度优先:M=32-64,efConstruction=200-400
  • 数据量大、追求速度:M=16-32,efConstruction=100-200
  • 查询时 efSearch 可动态调整,无需重建索引

2.2 IVF 参数

参数含义推荐值说明
nlist聚类中心数~4×√nn 为向量总数,中心数约为 4 倍平方根
nprobe搜索探查簇数10-100越多召回率越高,但延迟增加

2.3 PQ 参数

参数含义推荐值说明
m分段数32-128分段越多精度越高,但编码长度增加
nbits每段编码位数8通常为 8,即 256 个码字

2.4 LSH 参数

参数含义推荐值说明
nbits哈希位数维度 2-4 倍维度为向量维度
ntables哈希表数量50-200越多召回率越高,内存占用越大

三、算法选型决策树

根据不同业务场景选择合适的算法:

graph TD
    A["数据量 < 100万,精度优先"] --> B["推荐 HNSW"]
    C["数据量 100万-1000万,均衡考虑"] --> D["推荐 HNSW 或 IVF+PQ"]
    E["数据量 > 1000万,内存受限"] --> F["推荐 IVF + PQ"]
    G["稀疏向量 / 去重任务"] --> H["推荐 LSH"]
    I["需要增量更新 + 大规模"] --> J["推荐 IVF(可叠加 PQ)"]

四、主流产品算法对比

产品主要算法特点
PineconeHNSW + 优化托管服务,开箱即用
MilvusHNSW、IVF、GPU加速开源灵活,支持混合索引
WeaviateHNSW默认 HNSW,支持矢量化和混合搜索
FaissIVF、PQ、HNSW、LSH 全支持Facebook 出品,算法最全面
QdrantHNSW + 滤波支持带过滤条件的向量检索
ChromaHNSW(基于 Faiss)轻量级,嵌入管理专精

五、代码示例:Faiss 实战

Faiss 是 Facebook 出品的向量检索库,提供了所有主流算法的实现。

5.1 HNSW 索引

import faiss

d = 128  # 向量维度
M = 32   # 每节点最大邻居数

# 创建 HNSW 索引
index = faiss.IndexHNSWFlat(d, M)

# 设置参数
index.hnsw.efConstruction = 200  # 构建时搜索广度
index.hnsw.efSearch = 100         # 查询时搜索广度

# 添加向量
index.add(vectors)

# 查询
D, I = index.search(query_vector, k=10)
# D: 距离数组, I: 最近邻索引数组

5.2 IVF 索引

d = 128
nlist = 100  # 聚类中心数

# 使用内积作为相似度度量
quantizer = faiss.IndexFlatIP(d)

# 创建 IVF 索引
index = faiss.IndexIVFFlat(quantizer, d, nlist)

# 必须先训练再添加向量
index.train(vectors)
index.add(vectors)

# 设置探查数量
index.nprobe = 20

# 查询
D, I = index.search(query_vector, k=10)

5.3 IVF-PQ 混合索引

d = 128
nlist = 100  # 聚类数
m = 64       # PQ 分段数
nbits = 8    # 每段编码位数

quantizer = faiss.IndexFlatIP(d)

# 创建 IVF-PQ 索引
index = faiss.IndexIVFPQ(quantizer, d, nlist, m, nbits)

index.train(vectors)
index.add(vectors)

D, I = index.search(query_vector, k=10)

六、配置示例:主流数据库

6.1 Milvus 配置

index:
  type: HNSW
  params:
    M: 32
    efConstruction: 200
search:
  params:
    ef: 100

6.2 Qdrant 配置

{
  "hnsw_config": {
    "m": 32,
    "ef_construct": 200
  },
  "query_params": {
    "hnsw_ef": 128
  }
}

6.3 Weaviate 配置

{
  "vectorIndexType": "hnsw",
  "vectorIndexConfig": {
    "ef": 128,
    "efConstruction": 200,
    "maxConnections": 32
  }
}

七、RAG 中的稠密检索 vs 稀疏检索

graph TD
    Q["Query"] --> R["Retrieval"]
    R --> S["Sparse Retrieval"]
    R --> D["Dense Retrieval"]
    S --> B["BM25 / TF-IDF<br/>(词项匹配)"]
    D --> E["Embedding Model<br/>(语义匹配)"]

核心区别

维度稀疏检索 (Sparse)稠密检索 (Dense)
表示方式高维稀疏向量(词项出现与否)低维稠密向量(语义embedding)
匹配方式词项精确匹配 / 统计权重余弦相似度 / 向量距离
代表算法BM25、TF-IDFSentence-BERT、ColBERT
同义词处理❌ 无法处理✅ 语义理解
多语言支持依赖分词器✅ 跨语言
计算成本低中高
可解释性高(词项可追溯)低(向量不可解释)
冷启动✅ 无需训练需要预训练模型

稀疏检索详解

  # BM25 算法核心思想
  def bm25_score(query: str, document: str, avgdl: float, k1=1.5, b=0.75) -> float:
      """
      BM25 = Σ IDF(qi) × (tf(qi,d) × (k1+1)) / (tf(qi,d) + k1 × (1-b + b × |d|/avgdl))

      词项出现次数越多分数越高,但有衰减(饱和)
      文档越长惩罚越大
      """
      score = 0.0
      for qi in query.split():
          tf = document.count(qi)  # 词项频率
          idf = log((N - n(qi) + 0.5) / (n(qi) + 0.5))  # 逆文档频率
          numerator = tf * (k1 + 1)
          denominator = tf + k1 * (1 - b + b * len(document) / avgdl)
          score += idf * numerator / denominator
      return score

稀疏检索示例:

  Query: "Python 异步编程"
  Document: "Python asyncio 是异步编程框架"

BM25 匹配:

  • “Python” ✓ 匹配
  • “异步” ✓ 匹配
  • “编程” ✓ 匹配 Score: 高(三个词都命中)

但无法理解 “asyncio” = “异步编程” 的语义关系


稠密检索详解

稠密检索核心思想

def dense_retrieve(query_embedding, document_embeddings, top_k=5):
    """
    1. Query → Embedding Model → 向量 q
    2. Document → Embedding Model → 向量 d1, d2, ...
    3. 计算余弦相似度: cos(q, di)
    4. 返回 top-k 最相似的文档
    """
    similarities = []
    for doc_id, doc_emb in document_embeddings.items():
        sim = cosine_similarity(query_embedding, doc_emb)
        similarities.append((doc_id, sim))

    # 返回最相似的 top-k
    return sorted(similarities, key=lambda x: x[1], reverse=True)[:top_k]

稠密检索示例:

  Query: "Python 异步编程"
  → Embedding: [0.12, 0.45, 0.78, ...]  (768维向量)

  Document 1: "Python asyncio 是异步编程框架"
  → Embedding: [0.11, 0.47, 0.79, ...]  → similarity: 0.94 ✓

  Document 2: "Java 多线程并发处理"
  → Embedding: [0.65, 0.12, 0.08, ...]  → similarity: 0.23

即使词项完全不匹配,也能通过语义理解返回正确结果

混合检索(Hybrid Retrieval)

实际应用中通常结合两者优势:

  class HybridRetriever:
      def __init__(self, sparse_weight=0.3, dense_weight=0.7):
          self.sparse_weight = sparse_weight
          self.dense_weight = dense_weight
          self.sparse_retriever = BM25Retriever()
          self.dense_retriever = DenseRetriever()

      def retrieve(self, query: str, top_k=10) -> list[Document]:
          # 稀疏检索
          sparse_results = self.sparse_retriever.retrieve(query, top_k * 2)

          # 稠密检索
          dense_results = self.dense_retriever.retrieve(query, top_k * 2)

          # RRF (Reciprocal Rank Fusion) 融合
          fused_scores = {}
          for rank, doc in enumerate(sparse_results):
              fused_scores[doc.id] = fused_scores.get(doc.id, 0) + self.sparse_weight / (60 +
   rank)

          for rank, doc in enumerate(dense_results):
              fused_scores[doc.id] = fused_scores.get(doc.id, 0) + self.dense_weight / (60 +
  rank)

          # 返回融合后 top-k
          sorted_docs = sorted(fused_scores.items(), key=lambda x: x[1], reverse=True)
          return [doc for doc_id, _ in sorted_docs[:top_k]]

在 AI-Interview 项目中的检索方式

RAG 检索流程:

  graph TD
  用户问题 --> S1["1. Sparse: BM25 初步召回(关键词匹配)<br/>快速召回 100 个候选"]
  S1 --> S2["2. Dense: Embedding 精排(语义相似度)<br/>从 100 个中选出 top-5"]
  S2 --> S3["3. Rerank: 交叉编码器重排<br/>最终 top-3 输出"]
  S3 --> C["相关文档 context"]
  C --> L["LLM 生成回答"]

何时使用哪种检索

场景推荐方式原因
关键词明确稀疏检索“Python async await” 精确词项匹配
同义词查询稠密检索“心脏” = “心肌” 语义理解
多语言场景稠密检索跨语言 embedding
企业内部术语混合检索兼顾专有名词 + 语义
实时性要求高稀疏检索计算更快

八、总结

向量检索算法的选择需要综合考虑以下因素:

  1. 数据规模:决定采用单一算法还是混合方案
  2. 精度要求:HNSW 精度最高,LSH 适合快速过滤
  3. 内存限制:PQ 可大幅压缩内存占用
  4. 查询延迟:实时系统需要 O(log n) 级别的响应
  5. 更新频率:IVF 支持增量更新,HNSW 需要重建

对于大多数场景,HNSW 是首选方案;若数据量超过千万级或内存受限,可考虑 IVF+PQ 组合。具体参数设置建议从推荐值开始,通过实际测试调整到最优配置。

Sources

No external sources for this entry.

Related