Elasticsearch 向量迁 Easysearch:别只改字段名
最近好几拨朋友问同一件事:ES 上的向量检索,迁到 Easysearch 能不能直接用?
Easysearch 向量搜索 vs Elasticsearch:别再问"兼容不兼容"了,先看这篇
我的短答案是:向量数据能迁,API 和索引算法不能照搬。

稠密浮点向量换个字段类型就能灌进去;int8_hnsw
、pre-filter kNN、加权稀疏向量,这三样在 Easysearch 里没有一一对应的原样平替。能力有对应实现,但字段名、索引模型、过滤语义、稀疏语义都不等价。
下面按 Easysearch 2.3.1 实测口径,把该改什么、别踩什么一次说清楚。
1、先泼一盆冷水:不是改个字段名就完事
很多人看到官方迁移指南里写着:
dense_vector
→knn_dense_float_vector
,数据保留
就以为「改 mapping 名,查询原样拷过去」。
跑起来你会发现:查询 DSL 变了,近似索引算法变了,带过滤条件时 TopK 还可能对不上。
2.3.1 这边,对 Easysearch 自有的稠密浮点向量和布尔稀疏向量,exact
、LSH、sparse_indexed
查询都能工作。这句话的重点在「自有」——不是 ES 的 dense_vector
/ sparse_vector
API 兼容层。

官方迁移指南「字段类型兼容性」章节写得很直白,向量这块必须装 knn 插件,目标索引先建好新 mapping,再灌数。

2、字段怎么换:dense_vector 对上的是 knn_dense_float_vector
对照关系先记死:
dense_vector | knn_dense_float_vector | |
knn_vector | knn_dense_float_vector | |
sparse_vector | knn_sparse_bool_vector |
稠密向量的数据长这样,两边都能认:
[0.12, -0.03, 0.88, 0.45]
ES 侧常见写法(示意):
PUT products
{
"mappings": {
"properties": {
"embedding": {
"type": "dense_vector",
"dims": 768,
"index": true,
"similarity": "cosine",
"index_options": {
"type": "int8_hnsw" // ← ES 默认量化近似索引,Easysearch 没有
}
}
}
}
}

Easysearch 侧要改成:
PUT products
{
"mappings": {
"properties": {
"embedding": {
"type": "knn_dense_float_vector", // ← 这里!字段类型换名
"knn": {
"dims": 768,
"model": "lsh", // ← 近似用 LSH,不是 HNSW
"similarity": "cosine",
"L": 99,
"k": 1
}
}
}
}
}

几点实操提醒:
必须安装 knn
插件,否则向量查询起不来。数组格式兼容,Gateway Bulk 灌数时向量值一般不用二次编码。 Easysearch 还不支持 int8_hnsw
。内存占用和召回曲线别拿 ES 量化 HNSW 的经验直接套。小数据、要对齐过滤结果时,mapping 可以只写 dims
,查询用model: exact
。
字段类型细节见官方文档:向量字段类型(K-NN)


3、查询怎么改:从 knn 换成 knn_nearest_neighbors
ES 8 常见写法:
POST products/_search
{
"knn": {
"field": "embedding",
"query_vector": [0.12, -0.03, 0.88],
"k": 10,
"num_candidates": 100,
"filter": {
"term": { "category": "tech" } // ← ES 的 pre-filter
}
}
}
Easysearch 统一走 knn_nearest_neighbors
:
POST products/_search
{
"size": 10,
"query": {
"knn_nearest_neighbors": {
"field": "embedding",
"vec": {
"values": [0.12, -0.03, 0.88] // ← 这里!查询向量放 values
},
"model": "lsh",
"similarity": "cosine",
"candidates": 100 // ← 类似 num_candidates,建议 size 的 5~10 倍
}
}
}

精确搜索把 model
改成 exact
,不用配 candidates
:
"model": "exact",
"similarity": "cosine"
客户端、查询模板、网关改写规则都要动。别指望「只换集群地址」。
查询参数完整说明:k-NN 查询 API
4、最容易踩的坑:过滤语义不是一回事
这是向量迁移里最容易「看起来能跑、结果对不上」的地方。
ES 的 knn filter
是 pre-filter:先在满足条件的文档集合里找最近邻,尽量保证返回满 k 条「既相似又过筛」的结果。
Easysearch 文档里,向量查询可以塞进 bool
,和 filter
组合:
POST products/_search
{
"size": 10,
"query": {
"bool": {
"must": [
{
"knn_nearest_neighbors": {
"field": "embedding",
"vec": { "values": [0.12, -0.03, 0.88] },
"model": "lsh",
"similarity": "cosine",
"candidates": 100
}
}
],
"filter": [
{ "term": { "category": "tech" } }
]
}
}
}

大白话讲差别:
pre-filter:先缩小候选池,再在池子里找邻居。 post-filter:先找一堆邻居,再扔掉不符合条件的。过滤很严时,最终可能凑不满 k 条,排序也可能和 ES 不一致。
实测口径(2.3.1):LSH + bool filter 不等效于 ES pre-filter kNN。
替代思路:
model: exact,再叠 bool filter; | |
candidates调大,做召回重叠率,业务侧接受差异 | |
别把「能组合 filter」理解成「和 ES pre-filter 一样」。验收时一定要单独测「带过滤的 TopK」。
5、稀疏向量:名字像,语义差很远
这是第二个容易想当然的点。
ES 的 sparse_vector
(配合 ELSER / sparse_vector
query)是 加权稀疏:token → weight,分数跟权重有关。
Easysearch 的 knn_sparse_bool_vector
是 布尔稀疏:
每个维度只有 true/false,内部只存为 true 的下标,相似度是 Jaccard / Hamming。
写入形态大概长这样:
{
"features": [[0, 3, 5, 12, 88], 1000]
}
意思是:总维度 1000,其中下标 0、3、5、12、88 为 true。
查询示例:
// 1. 创建索引 — model 用 lsh(或 exact)PUT /products_0712{"mappings": {"properties": {"features": {"type": "knn_sparse_bool_vector","knn": {"dims": 1000,"model": "lsh","similarity": "jaccard","L": 99,"k": 1}}}}}// 2. 写入文档(格式不变)POST /products_0712/_doc/1{"features": [[0, 3, 5, 12, 88], 1000]}// 3. 查询 — 此时可以用 lsh 加速POST /products_0712/_search{"query": {"knn_nearest_neighbors": {"field": "features","vec": [[0, 5, 12, 100, 456], 1000],"model": "lsh","similarity": "jaccard","candidates": 50}}}
结论写死:

正确的做法是先创建索引,定义 knn_sparse_bool_vector
字段时,model
必须使用lsh
或exact
,绝不能写成sparse_indexed
;然后写入文档,稀疏向量格式始终是 [[true的下标], 总维度]
;最后查询时, model
也要和映射保持一致(这里用lsh
),vec
直接传数组,不需要values
包装。
6、一张迁移决策表 + 验收清单
6.1 迁不迁,先看你依赖什么
knn_dense_float_vector,改查询 DSL | |
int8_hnsw省内存 | |
sparse_vector/ ELSER | |
ES 7.0–7.11 快照窗口相对顺;7.12+ / 8.x 快照格式与 Easysearch 2.x 不兼容,走 INFINI Gateway 更稳。
6.2 上线前至少做这五步验收
文档量一致(含向量字段非空文档数)。 无过滤 TopK 重叠率:同一批 query,看 ES vs Easysearch 的命中重叠。 带过滤 TopK 对拍:这是坑点,单独测,别和「无过滤」混在一起报喜。 延迟与内存:LSH 的 L
/k
/candidates
要重新调,别抄 ES 的num_candidates
。核心业务链路压测:推荐、语义搜索、RAG 召回,用真实流量回放。
小索引先跑通 mapping 和查询,再全量迁。这句话在向量场景比普通文本索引更重要——mapping 建错,整库重灌。
7、向量迁的是数据,不是 API
回到开头那句话:
稠密向量:数据兼容,字段和查询要改。
近似索引:HNSW/int8 换成 LSH/exact,重新调参。
过滤:LSH 不等效 pre-filter,exact 更接近但仍要对拍。
稀疏:布尔稀疏 ≠ 加权稀疏。
Easysearch 2.3.1 上,自有稠密浮点和布尔稀疏的 exact / LSH / sparse_indexed 都能干活。迁移不是「功能有没有」,而是「语义等不等价」。把等价边界画清楚,迁移才不会在上线那天翻车。
你现在的 ES 向量栈是 HNSW、int8 量化,还是 ELSER 稀疏?欢迎留言。
LangChain + Easysearch + MiMo 大模型——从零构建企业级 RAG 向量检索系统
Easysearch 向量搜索 vs Elasticsearch:别再问"兼容不兼容"了,先看这篇




