第 1 章 向量引擎基础
1.1 向量引擎概述
-
定义:ES 向量引擎是支持高维向量存储与相似度搜索的功能模块,基于
dense_vector字段实现语义检索。 -
核心价值:
- 语义理解:将文本、图像等转为向量,捕捉语义关联(如 “苹果” 与 “iPhone” 的向量相似性)。
- 混合搜索:结合关键词过滤与向量排序,提升搜索精准度。
-
典型应用:语义搜索、推荐系统、图像检索、异常检测。
1.2 核心概念
-
向量表示:
- 密集向量(Dense Vector) :固定维度的实数数组(如 768 维),由 BERT 等模型生成17。
- 相似度算法:余弦相似度、欧氏距离、点积(Dot Product)。
-
向量搜索 vs 传统搜索:
传统搜索 向量搜索 基于关键词匹配 基于语义相似度 依赖分词器与词典 依赖预训练模型(如 BERT) 无法理解语义关联 能捕捉语义相近内容
1.3 逻辑图:向量搜索全流程
graph TD
输入查询 --> 文本/图像-向量 --> ES向量引擎检索 --> 返回相似文档
第 2 章 向量引擎实现原理
2.1 向量字段类型
-
dense_vector字段配置:PUT my_index { "mappings": { "properties": { "text_vector": { "type": "dense_vector", "dims": 768, // 向量维度 "index": true, // 启用向量索引 "similarity": "cosine" // 相似度算法 } } } }-
参数说明:
-
dims:维度(≤2048),需与生成向量一致。该向量字段中每个向量的维度为 768,即每个向量由 768 个连续的数值(通常是浮点数)组成。举几个具体场景理解:
- 文本嵌入向量
当使用 BERT-base 等预训练模型生成文本嵌入时,输出的向量维度通常是 768。例如,一句 "今天天气很好" 经过模型处理后,会转化为一个包含 768 个浮点数的数组:
[0.123, -0.456, 0.789, ..., 0.321](共 768 个数值) - 图像特征向量
某些轻量级图像特征提取模型(如简化版 ResNet)可能输出 768 维向量。一张猫的图片经过处理后,会生成 768 个数值来描述其视觉特征(颜色、轮廓、纹理等)。 - 用户行为向量
在推荐系统中,用户的行为序列(如浏览、购买记录)可能被编码为 768 维向量,每个数值代表用户在某个潜在特征维度上的偏好强度。
维度是向量的核心属性,768 这个数值是许多主流模型(如 BERT-base、Sentence-BERT 等)的默认输出维度,平衡了表达能力和计算效率。在 Elasticsearch 中,
dims必须与实际写入的向量维度严格一致,否则会导致数据写入失败。 - 文本嵌入向量
-
similarity:支持cosine、dot_product、l2_norm等。1.
cosine(余弦相似度)-
原理:计算两个向量夹角的余弦值,取值范围为
[-1, 1],值越接近 1 表示方向越相似。
公式:cosθ = (A·B) / (||A|| × ||B||),其中A·B是向量点积,||A||和||B||是向量的 L2 范数(模长)。 -
特点:
- 只关注向量方向的相似性,不受向量模长(数值大小)影响。
- 适合文本嵌入、语义搜索等场景(语义相似性更依赖方向而非强度)。
2.
l2_norm(欧氏距离,L2 距离)-
原理:计算两个向量在 n 维空间中的直线距离,值越小表示越相似。
公式:L2(A,B) = √[(A₁-B₁)² + (A₂-B₂)² + ... + (Aₙ-Bₙ)²] -
特点:
- 受向量模长影响(模长大的向量会放大距离)。
- 适合图像特征、推荐系统等对数值大小敏感的场景(如像素强度、行为频次)。
3.
dot_product(点积)-
原理:计算两个向量的内积,值越大表示越相似(需注意向量模长的影响)。
公式:A·B = A₁B₁ + A₂B₂ + ... + AₙBₙ -
特点:
- 结果受向量模长影响(模长大的向量点积更大)。
- 若向量已归一化(模长为 1),则点积等价于余弦相似度。
- 适合需要保留向量强度信息的场景(如特征重要性加权)。
算法对比与选择建议
算法 核心关注 受模长影响 典型应用场景 cosine向量方向 否 文本语义搜索、情感分析 l2_norm空间距离 是 图像检索、推荐系统 dot_product向量重叠度 是 归一化向量场景、特征匹配 -
-
2.2 索引算法:HNSW
-
原理:分层图结构加速近似最近邻搜索(ANN),通过调整参数平衡速度与精度。
-
关键参数:
m:每个节点的最大连接数(默认 16),值越大索引质量越高,但内存消耗增加。ef_construction:索引构建时的候选集大小(默认 256),值越大索引越精确。ef_search:搜索时的候选集大小,值越大召回率越高,但速度变慢。
-
配置示例:
PUT my_index/_settings { "index.knn": true, "index.knn.algo_param.m": 32, "index.knn.algo_param.ef_construction": 512 }
2.3 查询方式
-
近似 kNN 搜索(推荐) :
GET /my_index/_search { "knn": { "field": "text_vector", "query_vector": [0.1, 0.2, ..., 0.7], // 目标向量 "k": 10, // 返回数量 "num_candidates": 100 // 候选集大小 } } -
精确暴力搜索:
GET /my_index/_search { "query": { "script_score": { "query": { "match_all": {} }, "script": { "source": "cosineSimilarity(params.queryVector, 'text_vector') + 1.0", "params": { "queryVector": [0.1, ..., 0.7] } } } } } -
参数说明:
-
"field": "text_vector"- 指定要进行相似性搜索的向量字段名,这里是
text_vector(需与映射中定义的向量字段名称一致)。 - 该字段必须是
dense_vector类型,且已配置索引("index": true)。
- 指定要进行相似性搜索的向量字段名,这里是
-
"query_vector": [0.1, 0.2, ..., 0.7]- 表示用于搜索的 "目标向量",即你要以此为基准,寻找与之相似的其他向量。
- 向量的维度必须与
text_vector字段定义的dims(如 768)完全一致,否则会报错。 - 实际使用中,这个向量通常是由模型生成的(如文本嵌入、图像特征向量)。
-
"k": 10- 指定最终返回与目标向量最相似的前 k 个结果(k 为正整数)。
- 例如
k=10表示返回相似度最高的 10 条数据,类似 "Top 10" 搜索结果。
-
"num_candidates": 100- 用于控制近似搜索的候选集大小,是提升搜索效率的关键参数。
- 原理:搜索时先从索引中筛选出
num_candidates个较相似的候选向量(如 100 个),再从候选集中精确计算并返回前 k 个最相似的结果。 - 取值影响:值越大,候选集越可能包含真正的相似向量(精度更高),但计算耗时更长;值越小,速度越
第 3 章 实战:构建语义搜索系统
3.1 准备工作
-
环境:
- ES 8.0+(支持 k-NN 搜索)。
- Python +
sentence-transformers库(生成文本向量)。
-
数据:
- 示例数据:1000 条商品描述文本。
3.2 步骤 1:Ruby生成向量并导入 ES
- 环境准备:
gem install elasticsearch
gem install numpy # 用于向量计算(需配合Ruby原生扩展)
- 创建向量索引:
require 'elasticsearch/client'
client = Elasticsearch::Client.new(hosts: 'http://localhost:9200')
# 创建包含向量字段的索引
client.indices.create(
index: 'vector_docs',
body: {
mappings: {
properties: {
text: { type: 'text' },
vector: {
type: 'dense_vector',
dims: 100 # 100维向量
}
}
}
}
)
- 插入向量数据:
# 模拟文本向量化并插入
def index_document(text)
vector = text_to_vector(text) # 假设已实现向量化函数
client.index(
index: 'vector_docs',
body: {
text: text,
vector: vector
}
)
end
# 插入示例数据
index_document("机器学习基础")
index_document("深度学习框架TensorFlow")
index_document("自然语言处理技术")
- 向量查询:
# 执行向量相似度查询
def vector_search(query_text, top_n: 5)
query_vector = text_to_vector(query_text)
client.search(
index: 'vector_docs',
body: {
query: {
script_score: {
query: { match_all: {} },
script: {
source: "cosineSimilarity(params.query_vector, 'vector') + 1.0",
params: { query_vector: query_vector }
}
}
},
size: top_n
}
)
end
# 执行查询
result = vector_search("深度学习")
result['hits']['hits'].each do |hit|
puts "得分: #{hit['_score']}, 文本: #{hit['_source']['text']}"
end
第 4 章 性能优化与最佳实践
4.1 性能调优
-
参数优化:
- 增大
num_candidates提高召回率,但会降低速度。 - 调整 HNSW 参数
m和ef_construction平衡索引质量与内存占用。
- 增大
-
量化技术:
- Int8 量化:减少内存占用(如 1024 维向量从 4KB→1KB),牺牲少量精度。
- 配置示例:
PUT my_index/_settings { "index.knn.quantization": "int8" }
4.2 内存管理
-
内存计算:
- 向量数据内存:
num_vectors * dims * 4(float 类型)。 - HNSW 索引内存:
num_vectors * 4 * m(默认 m=16)。 - 总内存需小于节点堆外内存(通过
GET _nodes/stats查询)。
- 向量数据内存:
4.3 混合检索策略
-
流程:
- 关键词过滤(如价格区间、分类)缩小范围。
- 向量排序(语义相似度)优化结果。
-
DSL 示例
GET /products/_search { "query": { "bool": { "filter": { "term": { "category": "laptop" } }, "should": [ { "knn": { "field": "text_vector", "query_vector": [0.1, ..., 0.7], "k": 10 } } ] } } }
第 5 章 对比分析与选型建议
5.1 ES 向量引擎 vs 专用向量数据库
| 维度 | ES 向量引擎 | 专用向量数据库(如 Milvus) |
|---|---|---|
| 核心优势 | 全栈搜索能力,易于集成 | 高性能向量搜索,支持亿级数据 |
| 适用场景 | 混合搜索(关键词 + 向量) | 纯向量搜索(如推荐系统) |
| 性能 | 中等,适合中小规模数据 | 高,适合大规模数据 |
| 成本 | 低(无需额外部署) | 高(需独立集群) |
5.2 选型建议
- 中小规模混合搜索:优先 ES 向量引擎。
- 大规模纯向量搜索:ES+Milvus 结合,ES 过滤数据,Milvus 优化排序。