向量数据库工程实践:从HNSW索引到混合检索架构

为什么需要向量数据库

随着大模型时代的到来,文本、图像、音频等数据被编码为高维向量(Embedding),传统数据库无法高效处理"语义相似度搜索"。向量数据库应运而生,专门优化了最近邻搜索(ANN)场景,达到亚秒级的十亿级向量检索。

向量索引算法全景

ANN算法的核心思想是:放弃精确解的保证,换取搜索效率的指数级提升。

算法原理构建时间搜索时间内存占用召回率
Flat Brute-force暴力扫描所有向量O(1)O(Nd)O(Nd)1.0
IVF(倒排文件)先聚类再倒排检索O(NK)O(√N·d)O(Nd)0.9~0.99
HNSW(层级图)多层跳跃图搜索O(NlogN)O(logN·d)O(Nd·M)0.95~0.999
DiskANNVamana图+磁盘页O(NlogN)O(logN·d·IO)O(N·d/压缩率)0.9~0.97

HNSW索引详解

HNSW(Hierarchical Navigable Small World)是当前工程上最成功的ANN索引,被Milvus、Qdrant、pgvector、Elasticsearch等广泛采用。

层级结构:

  • 第0层包含所有节点
  • 上层节点按指数衰减概率分布
  • 高层用于快速"跳远",低层用于精细搜索
# HNSW搜索伪代码
import heapq

def hnsw_search(graph, query, top_k, ef_search):
    # 从最高层的入口点开始
    entry_point = graph.top_level_entry
    current_level = graph.max_level

    # 逐层贪心搜索,直到第0层
    while current_level > 0:
        entry_point = greedy_search_layer(query, entry_point, current_level, ef=1)
        current_level -= 1

    # 在第0层做beam search
    candidates = beam_search_layer(query, entry_point, current_level, ef=ef_search)
    return heapq.nlargest(top_k, candidates, key=lambda x: x.distance)

def greedy_search_layer(query, entry, level, ef):
    visited = {entry}
    candidates = [DistanceNode(query.distance(entry), entry)]
    best = candidates[0]

    while candidates:
        current = heapq.heappop(candidates)
        if current.distance > best.distance:
            break
        for neighbor in graph.neighbors(current.node, level):
            if neighbor not in visited:
                visited.add(neighbor)
                dist = query.distance(neighbor)
                if dist < best xss=removed>

关键参数:

  • M:每个节点的最大连接数(通常16~64),影响图连通性
  • ef_construction:构建时的beam width,越大图质量越高但构建越慢
  • ef_search:搜索时的beam width,与召回率正相关,与延迟负相关

PostgreSQL + pgvector的工程实践

对于已有PostgreSQL基础设施的团队,pgvector是最低成本的向量搜索方案。

-- 启用扩展
CREATE EXTENSION vector;

-- 创建向量表
CREATE TABLE documents (
    id BIGSERIAL PRIMARY KEY,
    content TEXT,
    embedding vector(1536)  -- OpenAI ada-002 维度
);

-- 创建HNSW索引(构建参数可调)
CREATE INDEX ON documents
USING hnsw (embedding vector_l2_ops)
WITH (m = 16, ef_construction = 200);

-- 语义搜索查询(L2距离)
SELECT id, content, embedding <-> '[0.1, 0.2, ...]' AS distance
FROM documents
ORDER BY distance ASC
LIMIT 10;

-- 混合检索:向量相似度 + BM25全文搜索的RRF融合
WITH vec_search AS (
    SELECT id, embedding <-> $1 AS vec_score
    FROM documents ORDER BY vec_score LIMIT 20
),
text_search AS (
    SELECT id, ts_rank(to_tsvector(content), $2) AS text_score
    FROM documents
    WHERE to_tsvector(content) @@ $2 ORDER BY text_score DESC LIMIT 20
),
rrf AS (
    SELECT id,
           1.0 / (60 + ROW_NUMBER() OVER (PARTITION BY id ORDER BY vec_score)) +
           1.0 / (60 + ROW_NUMBER() OVER (PARTITION BY id ORDER BY text_score)) AS rrf_score
    FROM vec_search FULL OUTER JOIN text_search USING (id)
)
SELECT d.id, d.content, r.rrf_score
FROM rrf r JOIN documents d ON r.id = d.id
ORDER BY r.rrf_score DESC LIMIT 10;

生产环境优化策略

1. 量化压缩

乘积量化(Product Quantization)将原始向量压缩到1/8~1/16大小,以轻微精度损失换取内存和IO节省。Milvus的IVF_PQ索引就是典型应用。

2. 分区与分片

按租户ID或数据类别对向量做分区(Partition),搜索时只扫描相关分区。Milvus的Partition Key机制能自动路由查询。

3. 存算分离

Milvus 2.4+引入的Streaming Node架构将存储与计算解耦:日志存于对象存储(S3),计算层只负责向量检索,存储成本下降80%。

4. 混合检索

单纯的向量搜索无法处理精确匹配条件(如"价格=100元")。生产系统通常采用向量+标量过滤的混合方案:先通过B+Tree索引过滤metadata,再对候选集做ANN搜索。

典型应用场景

  • RAG(检索增强生成):将文档按chunk编码存入向量库,用户问题也做Embedding,召回top-k个最相关chunk作为LLM上下文
  • 图像搜索:CLIP/ViT编码后存入向量库,以图搜图或跨模态检索
  • 推荐系统:用户行为序列的Embedding表示,基于相似用户或物品做推荐
  • 异常检测:将时序数据窗口编码为向量,检测与历史模式的偏离程度

向量数据库的发展仍在快速推进,DiskANN等磁盘索引方案让十亿级检索无需全量加载内存,而向量+标量的混合查询、多模态联合检索等能力正在成熟。对于生产环境,选择pgvector(已有PG生态)、Milvus(独立部署)还是Pinecone(全托管),取决于数据规模与运维成本的权衡。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部