Elasticsearch / OpenSearch 向量检索手册
Elasticsearch / OpenSearch 向量检索手册
适用版本:Elasticsearch 9.5.6(同期维护 9.4.9 / 8.19.24);OpenSearch 3.9.0(2.x 维护分支 2.19.7),核实于 2026-11 许可与形态:ES = Elastic License 2.0(默认)/ 源码可选 SSPLv1、AGPLv3,客户端 Apache-2.0;OpenSearch = Apache-2.0(官方 LICENSE 正文未直接核验);均为已有搜索集群上的向量字段 / 插件能力,分布式 一句话定位:在已有 ES / OpenSearch 索引里加一个向量字段,用同一套查询 DSL 同时做全文检索与 kNN 近邻,不新增一套数据库。 约定:
$普通用户、#root 或 sudo、<xxx>为占位符;标 ⚠️ 的是高危操作。 更新时间:2026-11(版本与 API 变化快,执行前请以官方文档复核)
目录
1. 它是什么、什么时候选它
1.1 定位与架构(按子产品)
Elasticsearch:向量是 dense_vector 字段类型,与倒排索引同处 Lucene 段内;knn query / retriever 在同一查询 DSL 内与全文检索组合,无独立进程、端口或存储,向量索引由 Lucene 段管理。index_options.type 决定 HNSW / 量化 / flat 等索引形态。
OpenSearch:向量能力由 k-NN 插件提供,索引级开关 settings.index.knn: true,字段类型 knn_vector;底层引擎可选 lucene / faiss(HNSW + IVF + PQ)/ nmslib(已弃用),IVF 需 Train API 训练模型。同样复用现有集群的分片、副本与查询 DSL。
| 分层 | 共同形态 | 运维含义 |
|---|---|---|
| 进程层 | 向量检索在搜索节点 data node 内执行 | 无额外进程,复用集群连接池与线程池 |
| 存储层 | 向量随文档存 Lucene 段,索引由段管理 | 随分片 / 副本复制,备份沿用集群快照 |
| 接口层 | REST + 查询 DSL | 复用现有客户端,无独立向量服务端口 |
| 部署层 | ES 内置字段类型 / OpenSearch 插件开关 | 升级 = 升集群或插件,不新增组件 |
1.2 横向对照表:定位差异(第 1 章)
| 维度 | Elasticsearch | OpenSearch |
|---|---|---|
| 向量字段类型 | dense_vector |
knn_vector |
| 能力来源 | 内核字段类型,开箱即用 | k-NN 插件 + 索引级开关 |
| 索引级开关 | 无需,index 默认 true |
必须 index.knn: true(建后不可改) |
| 维度上限 | dims ≤4096 |
dimension [1, 16000] |
| 底层引擎 | HNSW / 量化 / flat(由 index_options.type) |
lucene / faiss / nmslib(弃用) |
| 默认量化 | 9.1+ 按维度自动选择(见 6.7) | compression_level 1x~32x |
| 过滤语义 | knn query 内 filter = pre-filter;bool.filter = post-filter |
ANN 的 filter = 检索后过滤 |
| 许可 | Elastic License 2.0 等 | Apache-2.0(正文未核验) |
| 最新稳定 | 9.5.6 | 3.9.0(2.x 维护 2.19.7) |
1.3 适合 / 不适合(按子产品)
ES 适合:已有 ES 集群、需 BM25 + 稠密混合检索且要 RRF;已有完善的分片 / 副本 / 快照体系;数据量在搜索集群常规量级;需要 retriever.rrf、ES|QL 等查询语言能力。
ES 不适合:向量规模远超倒排数据、QPS 极高;需要 GPU / 专用分布式向量引擎;许可不接受 Elastic License 2.0 约束。
OpenSearch 适合:已在 OpenSearch / 兼容分支上、希望 Apache-2.0 生态;需要 faiss 的 IVF/PQ 或磁盘模式;维度可到 16000。
OpenSearch 不适合:无法接受 index.knn: true 建后不可改(需 reindex);依赖已弃用的 nmslib;需要开箱即用的 pre-filter(其 ANN filter 是检索后过滤)。
1.4 规模、链路位置与「何时该换」
| 项 | 经验区间(非官方承诺,须实测) |
|---|---|
| 条数 | 与搜索集群同量级;向量与倒排同段,规模受分片与堆内存约束 |
| 维度 | ES dims ≤4096;OpenSearch dimension ≤16000;常见 768 / 1024 / 1536 |
| QPS | 依赖分片数、num_candidates / k、堆内存,须压测 |
| 过滤比例 | 低命中率过滤对两者都是难点(见 6.5) |
链路位置:离线「文档 → Embedding → 写入文档的一个向量字段(与正文、标量字段同文档)」;在线「query → Embedding → knn query(可叠加全文与 filter)→ 取回 _source → 重排 → LLM / 展示」。向量检索只是召回层的一个子句,最大价值是全文与向量在同一 DSL 内融合。
该换专用向量库的信号:向量规模 / QPS 远超搜索集群承载;低命中率过滤导致召回持续不达标;需要十亿级分布式向量优化或 GPU;向量检索要独立扩容而不想拖累搜索集群;需要内核级多向量 / 复杂重排。
2. 版本、许可与官方入口
2.1 版本状态表
| 产品 | 版本 | 时间 | 状态 | 备注 |
|---|---|---|---|---|
| ES | 9.5.6 | 2026-11-02 | 最新 | 同期维护 9.4.9、8.19.24 |
| ES | 9.2 | 官方未标注日期 | 已发布 | ES|QL 引入 KNN()、FORK / FUSE(tech preview) |
| ES | 9.1 | 官方未标注日期 | 已发布 | 默认量化策略变更(见 6.7)、RRF 多字段 query |
| OpenSearch | 3.9.0 | 2026-09-29 | Latest | knn_vector 动态映射(默认关闭) |
| OpenSearch | 2.19.7 | 官方未标注日期 | 2.x 维护分支 | — |
2.2 许可与官方入口(按子产品)
- ES:Elastic License 2.0(默认),源码可选 SSPLv1 / AGPLv3;客户端为 Apache-2.0。Serverless 与部分量化默认策略受许可档位影响(见 6.7)。许可变更风险以 https://www.elastic.co/pricing/faq/licensing 为准。
- OpenSearch:Apache-2.0(官方 LICENSE 正文未直接核验,以官方仓库为准)。
2.3 版本识别命令
# 两者通用做法:查集群信息响应里的 version.number(端点与端口以实际部署 / 官方文档为准)
$ curl -s "http://<host>:<port>/" | grep -o '"number"[^,]*'
2.4 近两年重要变更与弃用提醒
ES:9.1 起 float 向量按维度自动量化(<384 维 int8_hnsw、≥384 维 bbq_hnsw);9.1+ RRF 支持多字段 query;9.2+ 子检索器 weight;9.2 ES|QL 引入 KNN() / FORK / FUSE(tech preview,GA 状态未核实);Serverless / 9.4+ 许可允许时默认 bbq_disk。
OpenSearch:nmslib 引擎已弃用,应选 lucene / faiss;3.9 提供 knn_vector 动态映射,需开 knn.dynamic_mapping.enabled(默认关闭,只建字段不启用 ANN)。
版本差异:改
dense_vector的index_options.type不会重索引已有向量,已写入的段保持原索引形态;要让新策略作用于存量数据必须 reindex。 避坑:OpenSearch 的settings.index.knn: true在建索引后不可改,只能新建索引并 reindex 数据。
3. 安装与启动
3.1 说明与前置条件
本类产品通常已有集群,「安装」实为「在已有索引上启用向量能力」。官方资料未提供两者官方安装命令、镜像 tag 与端口,部署安装请以官方文档为准,勿臆测。
- ES:
dense_vector为内核字段类型,无需额外插件;需确认版本 ≥8.x 且dense_vector可用。 - OpenSearch:需 k-NN 插件可用;索引创建时就必须带
settings.index.knn: true,事后无法补。 - 通用前置:JDK / 堆内存 / 分片规划沿用现有搜索集群基线(通用运维见根目录手册)。
3.2 ES:创建带 dense_vector 的索引
ES_HOST="http://<host>:<port>" # 替换为实际集群地址
curl -s -X PUT "$ES_HOST/knn-demo" -H 'Content-Type: application/json' -d '{
"mappings": {
"properties": {
"content": { "type": "text" },
"category": { "type": "keyword" },
"vec": {
"type": "dense_vector",
"dims": 3,
"index": true,
"similarity": "cosine",
"index_options": { "type": "hnsw", "m": 16, "ef_construction": 100 }
}
}
}
}'
示例用 3 维,实际常见 768 / 1024 / 1536;
dims≤4096。以上参数均取自官方 dense-vector 映射文档。
3.3 OpenSearch:创建带 knn_vector 的索引
OS_HOST="http://<host>:<port>" # 替换为实际集群地址
curl -s -X PUT "$OS_HOST/knn-demo" -H 'Content-Type: application/json' -d '{
"settings": { "index.knn": true },
"mappings": {
"properties": {
"content": { "type": "text" },
"category": { "type": "keyword" },
"vec": { "type": "knn_vector", "dimension": 3 }
}
}
}'
示例用 3 维;
dimension上限 16000。引擎(lucene / faiss,勿用已弃用 nmslib)、space_type、data_type、mode、compression_level的具体映射结构官方资料未给出逐字写法,按官方文档配置。
3.4 目录与端口表
| 项 | ES | OpenSearch | 备注 |
|---|---|---|---|
| HTTP 端口 | 通用默认 9200 | 通用默认 9200 | 官方资料未核实,以实际配置为准 |
| 向量字段 | dense_vector |
knn_vector |
无独立端口 |
| 数据 / 索引 | Lucene 段(分片目录) | Lucene 段(分片目录) | 纳入集群快照 |
| 日志 | 集群日志目录 | 集群日志目录 | 无独立日志 |
3.5 健康检查与连通性验证
判定「向量能力就绪」的可靠方式:写入一条带向量的文档,随后执行 knn 检索能返回该文档。ES 用 5.1 的 knn query;OpenSearch 的 knn 查询体官方资料未提供逐字参数,按官方文档构造后验证。仅能建索引、不能 knn 检索,说明 ANN 未真正启用(OpenSearch 尤其要检查 index.knn: true 与动态映射开关)。
3.6 生产最小配置建议
认证 / TLS / RBAC / 网络暴露面沿用搜索集群基线(通用运维见根目录手册);堆内存与分片数需把向量索引纳入容量评估;索引级设置(尤其 OpenSearch 的 index.knn)建前定稿。
⚠️ 危险:对已有大索引直接改
dense_vector映射参数或补index.knn不会作用于存量数据,误以为已生效会带来召回与容量双重事故。
4. 核心概念与数据模型
4.1 术语对照(按子产品)
| 通用术语 | Elasticsearch | OpenSearch |
|---|---|---|
| 向量字段 | dense_vector |
knn_vector |
| 维度 | dims(≤4096) |
dimension([1,16000]) |
| 相似度 / 空间 | similarity |
space_type |
| 元素类型 | element_type |
data_type |
| 索引形态 | index_options.type |
引擎 + mode / compression_level |
| TopK 近邻 | knn query |
k-NN 查询 |
| 混合融合 | retriever.rrf |
官方资料未提供逐字条目 |
| 文档 / 索引 | _doc / index |
_doc / index |
4.2 横向对照表:字段 / 索引 / 过滤差异(第 4 章,重点)
| 维度 | ES dense_vector |
OpenSearch knn_vector |
|---|---|---|
| 字段类型名 | dense_vector |
knn_vector |
| 维度参数 / 上限 | dims,≤4096 |
dimension,[1, 16000] |
| 是否要索引开关 | index 默认 true |
索引级 settings.index.knn: true(建后不可改) |
| 相似度 / 空间 | l2_norm / dot_product / cosine(默认)/ max_inner_product |
l1 / l2 / linf / cosinesimil / innerproduct / hamming / hammingbit |
| 元素类型 | float / bfloat16 / byte / bit |
binary / byte / float / half_float |
| 索引类型 | hnsw / int8_hnsw / int4_hnsw / bbq_hnsw / flat / int8_flat / int4_flat / bbq_flat / bbq_disk |
lucene / faiss(HNSW + IVF + PQ)/ nmslib(已弃用) |
| 建索引参数 | m=16、ef_construction=100 |
mode(in_memory / on_disk)、compression_level(1x~32x) |
| 量化入口 | index_options.type |
compression_level + 引擎 |
| 过滤行为 | knn query 内 filter = pre-filter;bool.filter = post-filter |
ANN 的 filter = 检索后过滤 |
| 动态映射 | 官方资料未提供 | 3.9 需 knn.dynamic_mapping.enabled(默认关闭,只建字段不启用 ANN) |
| IVF 训练 | 官方资料未提供 | faiss IVF 需 Train API 训练模型 |
避坑:这张表是本篇最容易被旧教程误导的地方——ES 与 OpenSearch 的字段名、索引开关、过滤语义都不通用,把 ES 的
dense_vector写法照搬到 OpenSearch(或反过来)会直接失败。
4.3 数据模型、距离与方向
两者都是「index → 文档 → 字段(正文 text + 标量 keyword + 向量字段)」,向量与倒排字段同文档,无独立 collection / load 步骤。
- ES:
similarity默认cosine;l2_norm越小越相似,dot_product/cosine/max_inner_product按分数越大越相似(查询侧以_score体现)。 - OpenSearch:
space_type决定距离语义,如l2/l1/linf越小越相似,cosinesimil/innerproduct越大越相似,hamming/hammingbit用于二值。
4.4 索引参数表(按子产品)
| 产品 | 参数 | 默认值 | 作用 |
|---|---|---|---|
| ES | m |
16 | HNSW 每层连接数 |
| ES | ef_construction |
100 | 建索引候选集 |
| ES | k |
— | 返回条数,必须 ≤ num_candidates |
| ES | num_candidates |
1.5 × k,≤10000 | 每分片候选数,召回 / 延迟主旋钮 |
| ES | knn.filter |
— | pre-filter,在 ANN 之前裁剪候选 |
| ES | similarity |
— | 结果最低相似度阈值 |
| ES | query_vector_builder |
— | 用模型在查询时生成向量(替代 query_vector) |
| OpenSearch | dimension |
— | [1,16000],建字段时定 |
| OpenSearch | mode |
— | in_memory / on_disk |
| OpenSearch | compression_level |
— | 1x~32x 压缩 |
| OpenSearch | space_type |
— | 距离空间 |
| OpenSearch | data_type |
— | binary / byte / float / half_float |
4.5 生命周期与一致性
写入文档后需经过索引 refresh 才可被检索(搜索集群通用行为);向量索引随 Lucene 段构建与合并,无「load 集合」步骤。一致性沿用各自集群的刷新 / 副本模型(近实时,非强一致事务),与 pgvector 的事务型语义不同。
5. 快速上手:完整 CRUD 示例
示例统一用 3 维向量便于阅读;实际常见 768 / 1024 / 1536 维。以下 REST 路径为通用形态示意,端点与端口以实际部署 / 官方文档为准。
5.1 Elasticsearch:完整 REST / cURL CRUD
ES_HOST="http://<host>:<port>" # 替换为实际集群地址
IDX="knn-demo"
# 1) 建索引(若 3.2 已建可跳过)
curl -s -X PUT "$ES_HOST/$IDX" -H 'Content-Type: application/json' -d '{
"mappings": { "properties": {
"content": { "type": "text" },
"category": { "type": "keyword" },
"vec": { "type": "dense_vector", "dims": 3, "index": true,
"similarity": "cosine",
"index_options": { "type": "hnsw", "m": 16, "ef_construction": 100 } }
} }
}'
# 2) 插入文档
curl -s -X POST "$ES_HOST/$IDX/_doc/1" -H 'Content-Type: application/json' \
-d '{"content":"向量检索入门","category":"tech","vec":[1,2,3]}'
curl -s -X POST "$ES_HOST/$IDX/_doc/2" -H 'Content-Type: application/json' \
-d '{"content":"关系型数据库运维","category":"tech","vec":[4,5,6]}'
curl -s -X POST "$ES_HOST/$IDX/_doc/3" -H 'Content-Type: application/json' \
-d '{"content":"咖啡拉花教程","category":"life","vec":[7,1,2]}'
curl -s -X POST "$ES_HOST/$IDX/_refresh"
# 3) knn 相似度检索
curl -s -X POST "$ES_HOST/$IDX/_search" -H 'Content-Type: application/json' -d '{
"knn": { "field": "vec", "query_vector": [3,1,2], "k": 3, "num_candidates": 100 },
"_source": ["content", "category"]
}'
# 4) 带标量过滤的检索:pre-filter 必须放在 knn 对象的 filter 里
curl -s -X POST "$ES_HOST/$IDX/_search" -H 'Content-Type: application/json' -d '{
"knn": { "field": "vec", "query_vector": [3,1,2], "k": 3,
"num_candidates": 100,
"filter": { "term": { "category": "tech" } } },
"_source": ["content", "category"]
}'
# 5) 更新 6) 删除 7) 清理
curl -s -X POST "$ES_HOST/$IDX/_doc/1" -H 'Content-Type: application/json' \
-d '{"content":"向量检索入门(修订)","category":"tech","vec":[1,2,4]}'
curl -s -X DELETE "$ES_HOST/$IDX/_doc/3"
curl -s -X DELETE "$ES_HOST/$IDX"
filter内的term为 ES 标准查询子句(通用 DSL,具体写法以官方文档为准);关键点不是子句写法,而是filter必须位于knn对象内部。
5.2 输出怎么读
| 字段 | 含义 |
|---|---|
hits.hits[]._id |
文档 id,用于回表取原文 |
hits.hits[]._score |
相似度得分(默认 cosine 下越大越相似),不是距离 |
hits.hits[]._source |
正文与标量字段,验证过滤是否生效 |
hits.total |
命中总数,用来发现「过滤后结果变少」 |
5.3 OpenSearch:可运行的建索引与写入
OS_HOST="http://<host>:<port>" # 替换为实际集群地址
IDX="knn-demo"
curl -s -X PUT "$OS_HOST/$IDX" -H 'Content-Type: application/json' -d '{
"settings": { "index.knn": true },
"mappings": { "properties": {
"content": { "type": "text" },
"category": { "type": "keyword" },
"vec": { "type": "knn_vector", "dimension": 3 }
} }
}'
curl -s -X POST "$OS_HOST/$IDX/_doc/1" -H 'Content-Type: application/json' \
-d '{"content":"向量检索入门","category":"tech","vec":[1,2,3]}'
curl -s -X POST "$OS_HOST/$IDX/_doc/2" -H 'Content-Type: application/json' \
-d '{"content":"关系型数据库运维","category":"tech","vec":[4,5,6]}'
curl -s -X POST "$OS_HOST/$IDX/_doc/3" -H 'Content-Type: application/json' \
-d '{"content":"咖啡拉花教程","category":"life","vec":[7,1,2]}'
curl -s -X DELETE "$OS_HOST/$IDX/_doc/3" # 删除
curl -s -X DELETE "$OS_HOST/$IDX" # 清理
避坑:OpenSearch 的 knn 查询体逐字参数名官方资料未核实,故此处不臆造查询 DSL;请按 https://docs.opensearch.org/3.6/search-plugins/knn/approximate-knn 构造 knn 查询后再做「写入一条 → knn 检索返回」的就绪验证。可以确认的行为是:ANN 索引的 filter 是检索后过滤(4.2 表),低命中率过滤会明显少结果。
5.4 旧教程会怎么写
避坑:ES 旧教程常把过滤写成
bool.filter/post_filter,并当成「pre-filter」。这是 post-filter:ANN 先取 TopK 再过滤,可能返回少于k条。正确写法是把filter放进knnquery 对象内部(5.1 第 4 步)。 避坑:OpenSearch 旧教程用nmslib引擎、或建索引时漏掉index.knn: true事后想补——前者已弃用(改 lucene / faiss),后者建后不可改,只能新建索引 + reindex。
6. 索引与检索进阶
6.1 索引参数调优(按子产品)
| 产品 | 参数 | 默认值 | 影响 | 建议(经验值,实测为准) |
|---|---|---|---|---|
| ES | num_candidates |
1.5 × k,≤10000 | 每分片候选↑ → 召回↑、延迟↑ | 从 10×k 内逐步压测 |
| ES | k |
— | 返回条数,须 ≤ num_candidates |
按业务 TopK 定 |
| ES | m / ef_construction |
16 / 100 | 图质量与体积 | 建索引期参数,改需 reindex |
| ES | similarity |
— | 最低分阈值 | 用于截断低质结果 |
| OpenSearch | compression_level |
— | 1x~32x,压缩↑ 召回↓ | 按内存预算选 |
| OpenSearch | mode |
— | in_memory / on_disk | 大容量用 on_disk |
6.2 横向对照表:索引 / 量化 / 过滤 / 混合(第 6 章)
| 维度 | Elasticsearch | OpenSearch |
|---|---|---|
| ANN 索引族 | index_options.type 九种(hnsw / int8_hnsw / int4_hnsw / bbq_hnsw / flat / int8_flat / int4_flat / bbq_flat / bbq_disk) |
lucene / faiss(HNSW + IVF + PQ)/ nmslib(弃用) |
| 默认量化 | 9.1+:<384 维 int8_hnsw、≥384 维 bbq_hnsw;Serverless / 9.4+ 许可允许时 bbq_disk |
compression_level 手动 1x~32x |
| 改索引类型的效果 | 不会重索引已有向量,须 reindex | 引擎在建索引时选定 |
| 过滤语义 | knn filter = pre-filter;bool.filter = post-filter |
filter = 检索后过滤 |
| 混合检索 | retriever.rrf(retrievers≥2、rank_constant=60、rank_window_size=10、filter) |
官方资料未提供逐字条目 |
| RRF 限制 | 不支持 scroll / sort / rescore | 官方资料未提供 |
| 稀疏 / 多向量 | 官方资料未提供逐字条目 | faiss IVF 需 Train API |
6.3 recall 与延迟取舍
num_candidates(ES)与候选 / 压缩档位(OpenSearch)是主要旋钮:候选越大召回越高、延迟与 CPU 越高。方法(经验):用 flat / 精确检索跑 ground truth,再对同一批 query 算 recall@k,逐步加候选到达标。
6.4 标量过滤:pre-filter 还是 post-filter(重点)
| 产品 | 写法 | 行为 | 后果 |
|---|---|---|---|
| ES | knn 对象内 filter |
pre-filter,先裁剪候选再做 ANN | 结果完整、性能更好 |
| ES | bool.filter / post_filter |
post-filter,ANN 取 TopK 后再过滤 | 可能返回少于 k 条 |
| OpenSearch | ANN 查询的 filter | 检索后过滤 | 低命中率时明显少结果 |
避坑:「过滤结果变少」不要先怀疑数据没写进去,先看过滤子句放在哪一层。ES 一律用 knn query 的
filter;OpenSearch 需接受检索后过滤的语义,必要时改用引擎侧过滤能力或加大候选量(以官方文档为准)。
6.5 混合检索:ES retriever.rrf 参数与限制
retriever.rrf 用于把多个检索器(BM25 全文 + knn 稠密等)融合:
| 参数 | 默认值 | 说明 |
|---|---|---|
retrievers |
必须 ≥2 | 子检索器数组,具体类型以官方文档为准 |
rank_constant |
60 | RRF 公式的秩常数 |
rank_window_size |
10 | 每个子检索器参与融合的窗口 |
filter |
— | 作用于检索器的过滤 |
版本演进:9.1+ 支持多字段 query;9.2+ 子检索器支持 weight。限制:不支持 scroll、sort、rescore。
子检索器的逐字类型名官方资料未核实,故此处只给参数与限制、不给臆造的完整 JSON;
retrievers内具体写法以官方 RRF retriever 文档为准。
6.6 量化与压缩(重点)
ES 9.1+ 默认量化策略:Stack 9.1 起,float 向量 <384 维默认 int8_hnsw、≥384 维默认 bbq_hnsw;Serverless / 9.4+ 在许可允许时默认 bbq_disk。这意味着即使你没显式写 index_options.type,索引形态也已由维度决定。可用 element_type(float / bfloat16 / byte / bit)与 index_options.type(hnsw / int8_hnsw / int4_hnsw / bbq_hnsw / flat / int8_flat / int4_flat / bbq_flat / bbq_disk)显式覆盖。
避坑:改
index_options.type不会重索引已有向量。已写入的 Lucene 段保持旧索引形态,只有新写入 / 新段才用新策略;要让存量向量生效必须 reindex。
OpenSearch:compression_level 1x~32x 配合 faiss PQ;data_type(binary / byte / float / half_float)与 mode(in_memory / on_disk)控制精度与内存。
6.7 容量估算(经验公式,非官方承诺)
向量原始体积 ≈ 4 × dim 字节/向量(float32);dim=768、100 万条 ≈ 3.07 GB(未计副本与段开销)
含副本总量 ≈ 原始体积 × (1 + 副本数)
HNSW / 量化索引额外开销随 m、量化档位与段合并波动,须按集群实测
ES num_candidates 与 OpenSearch 候选量主要影响查询期 CPU / 堆内存,不影响存储
系数为经验区间,非官方承诺;用集群监控实测后做容量规划。
7. 生产部署与运维
7.1 高可用、备份与监控(按子产品)
- ES:向量索引随分片 / 副本复制;快照(snapshot)备份含向量段,恢复后无需单独重建索引;监控沿用集群指标,重点看查询延迟、
num_candidates相关 CPU、堆内存与段合并。 - OpenSearch:同样随分片 / 副本复制与快照备份;需额外监控 k-NN 插件的图 / 缓存内存、
index.knn是否生效、faiss IVF 模型是否已 Train。
| 指标 | 关注点 | 告警阈值(经验值) |
|---|---|---|
| 向量查询 P99 延迟 | 候选量是否过大 | 相对基线翻倍即排查 |
| 堆内存 / 段合并 | 向量索引占用 | 超水位即扩容 |
| 过滤后命中数 | 是否 post-filter 截断 | 明显少于 k 即排查过滤位置 |
| 副本延迟 / 分片健康 | 向量段复制 | 沿用集群基线 |
7.2 升级、迁移与安全
- 升级:ES 跨 9.x 升级前核对默认量化策略变化(9.1+);改
index_options.type后要 reindex 存量。OpenSearch 升级时确认nmslib已弃用,迁移到 lucene / faiss;index.knn开关只能在新建索引时决定。 - 容量与扩缩容:按 6.7 估算并预留副本与段合并空间;扩分片需重建索引(reindex),属计划内变更。
- 安全基线:认证、TLS、RBAC、网络暴露面沿用集群基线;向量字段同样受字段级 / 文档级安全控制(通用运维见根目录手册)。
- 日志:集群日志目录,k-NN 插件无独立日志文件。
⚠️ 危险:对生产索引执行 reindex / 删除重建会改变索引名与别名指向,务必先切别名、保留旧索引回滚能力。
8. 高频故障与排障
| 症状 | 可能原因 | 定位命令 | 处置 |
|---|---|---|---|
[ES] dense_vector 映射报错 / dims 不符 |
dims 超 4096 或写入向量维度不匹配 |
GET /<index>/_mapping |
对齐 dims 与写入维度 |
[ES] 过滤后结果少于 k |
用了 bool.filter / post_filter(post-filter) |
检查查询体过滤子句位置 | 改用 knn query 内的 filter |
[ES] 改 index_options.type 后召回没变 |
新策略不重索引已有向量 | GET /<index>/_mapping + 段信息 |
reindex 存量数据 |
[ES] knn 报错 k > num_candidates |
k 超过候选数 |
检查查询体 k / num_candidates |
保证 k ≤ num_candidates(≤10000) |
| [ES] 查询慢 / CPU 高 | num_candidates 过大 |
集群慢日志 / 监控 | 下调候选量、加副本分摊 |
| [OS] knn 查询不返回 / ANN 未启用 | 建索引时漏 index.knn: true 或动态映射默认关闭 |
GET /<index>/_settings |
新建带 index.knn: true 的索引并 reindex |
[OS] 提示 nmslib 相关告警 |
引擎已弃用 | GET /<index>/_mapping |
改用 lucene / faiss |
| [OS] 过滤后结果明显变少 | ANN filter 是检索后过滤 | 对比无过滤 knn 结果 | 加大候选量或调整过滤策略(以官方文档为准) |
[OS] dimension 超限 |
超过 16000 | GET /<index>/_mapping |
降维或改用更小维度 |
| [通用] 连不上 / 写入失败 | 集群不可达、分片未分配、磁盘满 | 集群健康 / 分配接口(以官方文档为准) | 恢复节点、清理磁盘、检查分片 |
| [通用] 版本升级后 knn 报错 | 查询 DSL / 默认量化策略版本差异 | 查 version.number |
按新版本文档调整查询体与索引策略 |
| [通用] OOM / 堆内存溢出 | 向量索引 + 候选量叠加 | 集群监控 / 日志 | 加堆内存、降候选、用量化或 on_disk |
9. 常见坑与避坑清单
- 现象:ES 过滤后结果变少。原因:
bool.filter是 post-filter。怎么做:pre-filter 必须用 knn query 的filter。 - 现象:ES 改了
index_options.type却没效果。原因:不会重索引已有向量。怎么做:reindex 存量数据。 - 现象:ES 没写
index_options.type,索引形态却不是预期。原因:9.1+ 按维度默认量化(<384int8_hnsw、≥384bbq_hnsw)。怎么做:显式写index_options.type并核对维度阈值。 - 现象:ES
knn报k > num_candidates。原因:k必须 ≤num_candidates(≤10000,默认 1.5×k)。怎么做:调大num_candidates或减小k。 - 现象:ES RRF 查询加
sort/scroll报错。原因:retriever.rrf不支持 scroll / sort / rescore。怎么做:改走普通查询或调整融合结构。 - 现象:ES 9.2 ES|QL 的
KNN()/FORK/FUSE当成 GA 写进方案。原因:tech preview,GA 版本未核实。怎么做:标注「以官方文档为准」,勿写成稳定能力。 - 现象:OpenSearch 建索引时漏
index.knn: true,事后想补。原因:建后不可改。怎么做:新建索引 + reindex。 - 现象:OpenSearch 用了
nmslib。原因:引擎已弃用。怎么做:选 lucene / faiss。 - 现象:OpenSearch 过滤后结果明显变少。原因:ANN filter 是检索后过滤。怎么做:加大候选量并接受语义差异,勿按 pre-filter 预期验收。
- 现象:OpenSearch 动态映射建了
knn_vector字段却不做 ANN。原因:knn.dynamic_mapping.enabled默认关闭,只建字段不启用 ANN。怎么做:显式开启并核对索引设置。 - 现象:把 ES 的
dense_vector写法照搬到 OpenSearch(或反之)。原因:字段名、维度参数、索引开关、过滤语义都不通用。怎么做:按 4.2 对照表逐项区分。 - 现象:reindex / 删索引重建后应用查不到数据。原因:别名未切换、索引名变化。怎么做:⚠️ 先切别名并保留旧索引回滚,这是可能导致线上事故的操作。
10. 速查表(横向对照)
| 操作 | Elasticsearch | OpenSearch | 说明 |
|---|---|---|---|
| 字段类型 | "type": "dense_vector" |
"type": "knn_vector" |
名称不通用 |
| 维度参数 | "dims": 3(≤4096) |
"dimension": 3(≤16000) |
示例 3 维 |
| 相似度 / 空间 | "similarity": "cosine" |
space_type(l2 / cosinesimil / …) |
默认 cosine(ES) |
| 元素类型 | "element_type": "float" |
data_type(float / byte / …) |
量化入口 |
| 索引形态 | "index_options": {"type":"hnsw","m":16,"ef_construction":100} |
引擎 lucene / faiss + mode / compression_level |
勿用 nmslib |
| 索引开关 | index 默认 true |
settings.index.knn: true |
⚠️ OS 建后不可改 |
| 建索引 | PUT /<index> |
PUT /<index> |
建前定稿设置 |
| 写文档 | POST /<index>/_doc/1 |
POST /<index>/_doc/1 |
向量放字段里 |
| 刷新 | POST /<index>/_refresh |
集群通用 refresh | 写入后可检索 |
| knn 检索 | {"knn":{"field":"vec","query_vector":[3,1,2],"k":3,"num_candidates":100}} |
查询体以官方文档为准 | 官方资料未给 OS 逐字参数 |
| pre-filter | knn 对象内 "filter" |
无(filter 为检索后过滤) | ES 必用此写法 |
| 候选量 | num_candidates(默认 1.5×k,≤10000) |
引擎侧候选 / compression_level |
召回 / 延迟旋钮 |
| 查询向量生成 | query_vector_builder |
官方资料未提供 | ES 可查询时生成 |
| 相似度阈值 | knn similarity |
官方资料未提供 | 截断低质结果 |
| 显式量化类型 | int8_hnsw / bbq_hnsw / bbq_disk 等九种 |
compression_level 1x~32x |
9.1+ 有默认策略 |
| 混合检索 | retriever.rrf(rank_constant 60、rank_window_size 10) |
官方资料未提供 | 不支持 scroll / sort / rescore |
| ES|QL | 9.2 KNN() / FORK / FUSE(tech preview) |
— | GA 状态未核实 |
| IVF 训练 | 官方资料未提供 | faiss IVF 需 Train API | 建模前置 |
| 更新 / 删除 | POST /<index>/_doc/1、DELETE /<index>/_doc/1 |
同左(通用 REST) | — |
| 清索引 | DELETE /<index> |
DELETE /<index> |
⚠️ 高危,先切别名 |
| 端口 / 路径 | 值 | 备注 |
|---|---|---|
| HTTP 端口 | 通用默认 9200(两者) | 官方资料未核实,以实际配置为准 |
| 向量字段 | dense_vector / knn_vector |
无独立向量服务端口 |
| 数据 / 索引 | Lucene 段(分片目录) | 纳入集群快照 |
| 日志 | 集群日志目录 | 无独立日志 |
11. 参考与延伸
官方链接清单
| 资源 | URL |
|---|---|
| ES 文档入口 | https://www.elastic.co/docs |
| ES dense_vector 映射 | https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/dense-vector |
| ES knn query | https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-knn-query |
| ES RRF retriever | https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrievers/rrf-retriever |
| ES 许可 FAQ | https://www.elastic.co/pricing/faq/licensing |
| ES Releases | https://github.com/elastic/elasticsearch/releases |
| OpenSearch 文档入口 | https://opensearch.org/docs |
| OpenSearch knn_vector 字段 | https://opensearch.org/docs/latest/field-types/supported-field-types/knn-vector/ |
| OpenSearch approximate-knn | https://docs.opensearch.org/3.6/search-plugins/knn/approximate-knn |
| OpenSearch Releases | https://github.com/opensearch-project/OpenSearch/releases |
与同册其他产品的关系:已有 ES / OpenSearch → 本篇;已有 PG → pgvector.md;已有 Redis → Redis-Vector-Search.md;已有 ClickHouse → ClickHouse.md;已有国产关系库 → 国产数据库向量能力.md;需分布式专用向量库 → 01-专用向量数据库 分册。
进阶阅读:ES dense_vector 的 index_options 与量化档位、RRF retriever 限制;OpenSearch k-NN 插件的引擎差异、faiss IVF Train API、3.9 动态映射。
本篇「未核实 / 以官方为准」事项:
- ES 9.2 ES|QL
KNN()/FORK/FUSE为 tech preview,GA 版本未核实,正文不得写成稳定能力。 - OpenSearch Apache-2.0 官方 LICENSE 正文未直接核验,以官方仓库为准。
- OpenSearch knn 查询 DSL 的逐字参数名未核实,故 5.3 / 6.5 未给臆造查询体,按官方文档构造。
- ES RRF 子检索器的逐字类型名未核实;
retrievers内具体写法以官方文档为准。 - ES 9.1 / 9.2 / 9.4+ 的具体发布日期未核实(官方资料仅给 9.5.6 日期)。
- 两者官网 / 镜像仓库 / SDK / 控制台 URL、安装命令、镜像 tag、HTTP 端口均官方资料未提供,勿臆测。
- 4.3 中相似度 / 距离方向的逐值口径、6.7 容量公式、各告警阈值均为经验性表述,非官方承诺,须实测。
- ES 9.4+ / Serverless 默认
bbq_disk的「许可允许」具体条件未核实,以官方许可文档为准。