什么是向量检索?

向量检索(Vector Search) 是将文本、图片、音频等非结构化数据转换为高维向量(Embedding),通过计算向量间的相似度来找到语义相近的内容,而非传统的关键词匹配。

传统搜索:  "苹果手机"  →  精确匹配 "苹果" "手机" 关键词
向量搜索:  "苹果手机"  →  语义理解 → 能匹配 "iPhone" "iOS设备" 等

ES 向量检索发展历程

版本

重要特性

7.0

引入 dense_vector 字段类型

7.3

支持 cosineSimilarity 脚本评分

8.0

原生 kNN 搜索 API 发布

8.4

kNN 融入主查询(支持混合检索)

8.8

引入 HNSW 索引,性能大幅提升

8.11

int8/int4 量化压缩,内存减少 75%

8.14+

BBQ(Binary Quantization) 极致压缩


核心概念

1. 🔢 Dense Vector(稠密向量)

PUT /articles
{
  "mappings": {
    "properties": {
      "title": { "type": "text" },
      "content": { "type": "text" },
      "embedding": {
        "type": "dense_vector",
        "dims": 1536,          // 向量维度(取决于模型)
        "index": true,         // 开启索引,支持 kNN
        "similarity": "cosine" // 相似度算法
      }
    }
  }
}

2. 📐 相似度算法

算法

适用场景

说明

cosine

文本语义搜索

余弦相似度,最常用

dot_product

归一化向量

点积,速度最快

l2_norm

图像搜索

欧式距离

max_inner_product

推荐系统

最大内积

3. 🏗️ HNSW 索引结构

ES 8.8+ 默认使用 HNSW(Hierarchical Navigable Small World)

优点:
  ✅ 近似最近邻(ANN),不是精确搜索
  ✅ 查询速度极快(毫秒级)
  ✅ 精度可调(accuracy vs speed 权衡)

参数:
  m: 每个节点的连接数(默认16,越大越精准但内存越多)
  ef_construction: 构建时搜索宽度(默认100)

核心 API 使用

📥 写入向量数据

from elasticsearch import Elasticsearch
from sentence_transformers import SentenceTransformer

es = Elasticsearch("http://localhost:9200")
model = SentenceTransformer("BAAI/bge-large-zh-v1.5")

doc = {
    "title": "FreeSWITCH 语音平台",
    "content": "FreeSWITCH 是一个开源的电话软交换平台...",
    "embedding": model.encode("FreeSWITCH 是一个开源的电话软交换平台").tolist()
}

es.index(index="articles", body=doc)

🔍 kNN 向量搜索

POST /articles/_search
{
  "knn": {
    "field": "embedding",
    "query_vector": [0.12, 0.45, ...],  // 查询文本的向量
    "k": 10,                             // 返回最相似的 10 条
    "num_candidates": 100                // 候选集大小,越大越精准
  },
  "_source": ["title", "content"]
}
# Python 实现
query_text = "语音识别方案有哪些?"
query_vector = model.encode(query_text).tolist()

result = es.search(
    index="articles",
    knn={
        "field": "embedding",
        "query_vector": query_vector,
        "k": 10,
        "num_candidates": 100
    }
)

🔀 混合检索(Hybrid Search)⭐ 推荐

向量检索 + 关键词检索 结合,效果最好

POST /articles/_search
{
  "query": {
    "match": {
      "content": "语音识别"    // BM25 关键词检索
    }
  },
  "knn": {
    "field": "embedding",
    "query_vector": [0.12, 0.45, ...],
    "k": 10,
    "num_candidates": 100
  },
  "rank": {
    "rrf": {                   // RRF 互惠排名融合
      "window_size": 50,
      "rank_constant": 20
    }
  }
}
混合检索原理(RRF 融合):

BM25 结果:   doc1(0.95) > doc3(0.82) > doc5(0.71) ...
kNN 结果:    doc3(0.98) > doc1(0.91) > doc7(0.85) ...
                ↓  RRF 融合
最终排名:    doc1 🥇  doc3 🥈  doc5 🥉 ...

向量模型选型

中文推荐模型

模型

维度

特点

适用场景

BAAI/bge-large-zh-v1.5

1024

中文最强之一

中文语义搜索

BAAI/bge-m3

1024

多语言,支持稀疏+稠密

多语言混合

text2vec-large-chinese

1024

中文优化

中文问答

OpenAI text-embedding-3-large

3072

效果顶尖

有 API 预算时

text-embedding-3-small

1536

性价比高

通用场景

# 使用 BGE 模型(推荐中文场景)
from sentence_transformers import SentenceTransformer

model = SentenceTransformer("BAAI/bge-large-zh-v1.5")

# BGE 模型查询时需加前缀
query = "为查询而写: 语音识别方案"
embedding = model.encode(query, normalize_embeddings=True)

性能优化技巧

1. 向量量化(节省内存)

"embedding": {
  "type": "dense_vector",
  "dims": 1536,
  "index": true,
  "similarity": "cosine",
  "index_options": {
    "type": "int8_hnsw"   // int8量化,内存减少75%,精度损失<1%
    // "type": "int4_hnsw" // int4量化,内存减少87.5%
    // "type": "bbq_hnsw"  // 二进制量化,内存减少96%
  }
}

2. 调整 HNSW 参数

"index_options": {
  "type": "hnsw",
  "m": 16,                // 增大提升精度(内存+)
  "ef_construction": 100  // 增大提升精度(构建慢)
}

// 查询时
"knn": {
  "num_candidates": 200   // 增大提升召回率(速度-)
}

3. 分片策略

向量数据量级建议:
< 100万条   → 1~2 个分片
100万~1000万 → 3~5 个分片
> 1000万    → 考虑分索引或向量数据库

完整 RAG 架构示例

结合大语言模型构建知识库问答

用户提问
    ↓
Embedding 模型(BGE/OpenAI)
    ↓ 问题向量化
ES 混合检索(kNN + BM25)
    ↓ 召回 Top-K 相关文档
Rerank 重排序(可选,BGE-Reranker)
    ↓ 精选 Top-3 上下文
LLM 大模型(GPT/通义/文心)
    ↓ 结合上下文生成回答
最终答案 ✅
def rag_query(question: str) -> str:
    # 1. 向量化问题
    query_vector = embed_model.encode(question).tolist()

    # 2. ES 混合检索
    results = es.search(
        index="knowledge_base",
        knn={"field": "embedding", "query_vector": query_vector, "k": 5, "num_candidates": 50},
        query={"match": {"content": question}},
        rank={"rrf": {}}
    )

    # 3. 拼接上下文
    context = "\n".join([hit["_source"]["content"] 
                         for hit in results["hits"]["hits"][:3]])

    # 4. 调用 LLM
    prompt = f"根据以下内容回答问题:\n{context}\n\n问题:{question}"
    return llm.chat(prompt)

ES vs 专业向量数据库

对比项

Elasticsearch

Milvus

Qdrant

Weaviate

向量检索性能

⭐⭐⭐

⭐⭐⭐⭐⭐

⭐⭐⭐⭐⭐

⭐⭐⭐⭐

混合检索

⭐⭐⭐⭐⭐

⭐⭐⭐

⭐⭐⭐⭐

⭐⭐⭐⭐

运维复杂度

中(已有经验)

全文检索

⭐⭐⭐⭐⭐

⭐⭐

⭐⭐⭐

适用场景

已有ES + 混合搜索

纯向量大规模

轻量向量搜索

AI原生应用


选型建议

场景

推荐方案

已有 ES,新增语义搜索

直接用 ES kNN,成本最低

纯向量搜索,亿级数据

Milvus / Qdrant

RAG 知识库问答

ES 混合检索 + BGE

中文语义搜索

ES + BAAI/bge-large-zh

快速原型

ES + OpenAI Embedding API


总结:ES 的向量检索最大优势是混合检索(BM25 + kNN + RRF),既有传统关键词的精确性,又有语义检索的召回能力,对于大多数 RAG 和语义搜索场景来说是性价比最高的方案,尤其适合团队已有 ES 运维经验的情况。