跳到主要内容

Elasticsearch 速查表:80+ 条 Query DSL / Mapping / 分析器 / 聚合 / 复制 带真实生产坑

Elasticsearch 速查表,80+ 条 Query DSL/mapping/analyzer/聚合/复制,真实例子和坑。

  • 本地处理
  • 分类 开发运维
  • 适合 格式化、校验、压缩或检查和代码相关的文本。
172
索引管理 (19)
PUT /<index>

创建索引。不带 body 时给默认 1 主 1 副 + 动态 mapping,玩玩可以,生产几乎从不合适。

常见坑: < 50GB 索引默认 1 shard 够用;"1GB 日志开 100 shard" 这种超分会拖垮 cluster state 和恢复时间。按真实数据量算 shard,别按"万一长大了"。

例子
PUT /products
PUT /logs-2026.05 {"settings":{"number_of_shards":3,"number_of_replicas":1}}
DELETE /<index>

删除索引,磁盘立刻释放。不可撤销,没有软删除也没有回收站。配合 elasticsearch.yml 里 action.destructive_requires_name 拒绝通配符删除。

常见坑: 默认配置下 DELETE /* 瞬间把全部索引清空。务必开 action.destructive_requires_name: true 强制写明索引名。

例子
DELETE /products
DELETE /logs-2025.*
GET /<index>

查索引的全貌,mapping、settings、aliases 一次返回。加 ?include_defaults=true 看每个没显式设置的项实际取什么值。

例子
GET /products
GET /products?include_defaults=true
POST /<index>/_close · _open

关索引释放 heap(mapping 保留,shard 下线),要用再打开。需要关索引才能改的设置(分析器、similarity)必须 close → update → open 一套走完才生效。

常见坑: 关闭的索引占磁盘但不能查不能写。关错生产索引 = 直接事故。写明索引名,不要用 pattern。

例子
POST /products/_close
POST /products/_open
POST /_aliases

原子地在多个索引上加 / 删 alias。零停机 reindex 的标准动作:旧索引继续写,新索引建好后一步原子切 alias。

例子
POST /_aliases {"actions":[{"remove":{"index":"products_v1","alias":"products"}},{"add":{"index":"products_v2","alias":"products"}}]}
POST /_aliases {"actions":[{"add":{"index":"logs-2026.05","alias":"logs-current","is_write_index":true}}]}
PUT /_index_template/<name>

Composable index template(7.8+)。匹配命名 pattern 的新索引自动套上 mapping + settings,标准化每日日志索引、按时间 rollover、租户索引的正路。

常见坑: Template 只对"保存之后才创建"的索引生效。已存在的索引仍是旧 mapping,想追溯应用得 reindex。

例子
PUT /_index_template/logs-template {"index_patterns":["logs-*"],"template":{"settings":{"number_of_shards":1,"number_of_replicas":1},"mappings":{"properties":{"@timestamp":{"type":"date"},"message":{"type":"text"}}}}}
POST /<index>/_rollover

当 size / age / doc 数到阈值时,把 alias 滚到新索引。配合 ILM 策略,日 / 周索引大小可控,老索引自动迁到 warm/cold tier。

例子
POST /logs-current/_rollover {"conditions":{"max_age":"7d","max_size":"50gb","max_docs":100000000}}
POST /_reindex

把全部 doc 从一个索引复制到另一个,可选改字段、按 query 过滤。改字段类型 / 给老数据加新分析器,只有这一条路。

常见坑: 默认 reindex 同步阻塞。> 10w 文档加 ?wait_for_completion=false 拿 task id,再用 GET /_tasks/<id> 轮询。slices=auto 调并行。

例子
POST /_reindex {"source":{"index":"products_v1"},"dest":{"index":"products_v2"}}
POST /_reindex?wait_for_completion=false&slices=auto {"source":{"index":"logs-2025.*"},"dest":{"index":"logs-archive"}}
POST /<index>/_forcemerge

把 segment 合到 N 个(一般 max_num_segments=1)减少 shard 内 segment 数、释放已删除文档空间、加速只读索引上的搜索。

常见坑: 正在写入的索引绝不要 force-merge。会产生巨大的 merge IO,且下次 refresh 又会生成新 segment。只对停止写入的索引执行。

例子
POST /logs-2025.12/_forcemerge?max_num_segments=1
POST /<index>/_refresh

手动刷新索引,让刚写入的文档立刻能被搜到。默认每 1s 自动 refresh;高吞吐写入场景把 refresh_interval 调到 30s,按需手动 _refresh。

例子
POST /products/_refresh
PUT /products/_settings {"index":{"refresh_interval":"30s"}}
POST /<index>/_flush

把 translog flush 掉、Lucene segment commit 到磁盘。日常自动 flush,手动 flush 主要在 snapshot 或关停前用。

例子
POST /products/_flush
POST /_flush
PUT /<index>/_settings

在线改索引的动态设置,refresh_interval、number_of_replicas、max_result_window、blocks 都行。静态设置(number_of_shards、analysis 段)改不了,得关索引或 reindex。

常见坑: number_of_shards 创建时定死,之后永远改不了,要么前期算好,要么用 _split / _shrink 改。在线只有 number_of_replicas 能随便调。

例子
PUT /products/_settings {"index":{"number_of_replicas":2,"refresh_interval":"30s"}}
PUT /products/_settings {"index":{"max_result_window":50000}}
POST /<index>/_clone

把索引克隆成同 mapping、同 shard 数的新索引,segment 走硬链接,几乎瞬时且几乎不占额外磁盘。前提是源索引先设只读(index.blocks.write)。

例子
PUT /products/_settings {"settings":{"index.blocks.write":true}}
POST /products/_clone/products_copy
POST /<index>/_shrink

把索引收缩到更少的主 shard(目标数必须能整除源 shard 数)。常用于 rollover 后把超分的旧只读索引合并,省掉 cluster-state 开销。

常见坑: _shrink 前索引必须只读,且所有主 shard 要先集中到同一节点,先设 index.routing.allocation.require._name。漏了这步收缩就会卡住。

例子
PUT /logs-old/_settings {"settings":{"index.blocks.write":true,"index.routing.allocation.require._name":"node-1"}}
POST /logs-old/_shrink/logs-old-shrunk {"settings":{"index.number_of_shards":1,"index.blocks.write":null}}
POST /<index>/_split

不 reindex 把索引拆成更多主 shard。源索引要只读,目标 shard 数必须是源的整数倍。索引长大超过原 shard 数时的补救路。

例子
PUT /events/_settings {"settings":{"index.blocks.write":true}}
POST /events/_split/events_split {"settings":{"index.number_of_shards":6}}
GET /<index>/_stats

单索引运行统计,文档数、存储体积、index/search/merge/refresh/flush 速率、segment 数、query cache 命中率。某个索引变慢时先看它。

例子
GET /products/_stats
GET /products/_stats/search,indexing,merge
GET /<index>/_segments

列出每个 shard 内的 Lucene segment,数量、体积、文档数、已删除文档数。segment 太多或删除文档占比高,就是该对只读索引做 force-merge 的信号。

例子
GET /products/_segments
GET /logs-2025.12/_segments?verbose=false
PUT /_component_template/<name>

composable index template 的可复用积木,把 mapping 或 settings 定义一次,再用 composed_of 在多个 index template 里引用。让 log/metric/trace 模板共享字段定义不重复。

例子
PUT /_component_template/base-settings {"template":{"settings":{"number_of_shards":1,"number_of_replicas":1}}}
PUT /_index_template/logs {"index_patterns":["logs-*"],"composed_of":["base-settings"]}
PUT /<data-stream> (data stream)

data stream 是时序后备索引之上的"只追加"抽象,靠 index template + ILM 自动 rollover。它是"自己管每日索引 + alias"的现代替代,你只往一个名字写,rollover 由 ES 接管。

常见坑: data stream 只接受 create(追加)操作,不能通过 stream 名按 id 改或删单条文档,得直接定位到具体的后备索引(.ds-<name>-<date>-NNNN)。

例子
PUT /_index_template/metrics {"index_patterns":["metrics-*"],"data_stream":{},"template":{"mappings":{"properties":{"@timestamp":{"type":"date"}}}}}
PUT /_data_stream/metrics-app
文档 (17)
PUT /<index>/_doc/<id>

按 id 写文档(新建或整体替换)。只想"不存在才写"加 op_type=create,已存在就 409。

例子
PUT /products/_doc/1 {"name":"Headphones","price":99,"in_stock":true}
PUT /products/_doc/1?op_type=create {"name":"Headphones"}
POST /<index>/_doc

不指定 id 写文档,ES 自动生成 base64 id。比 PUT/_doc/<id> 略快,省了"是不是更新"的判断。

例子
POST /products/_doc {"name":"Mouse","price":25}
GET /<index>/_doc/<id>

按 id 取单个文档,返回 _source 加元数据。加 _source_includes / _source_excludes 只挑要的字段,大文档便宜很多。

例子
GET /products/_doc/1
GET /products/_doc/1?_source_includes=name,price
POST /<index>/_update/<id>

部分更新,在一次原子 get-modify-index 里把传入字段合到现有 _source。简单合并用 doc,需要条件逻辑用 script。

常见坑: ES 没有真正的原地更新;每次"更新"都是重写整个文档加把老的标记为 deleted。重更新场景会让 segment 膨胀,reindex 或走 rollover 索引。

例子
POST /products/_update/1 {"doc":{"price":89}}
POST /products/_update/1 {"script":{"source":"ctx._source.views += params.n","params":{"n":1}}}
POST /<index>/_update_by_query

服务端一遍扫描更新所有匹配 query 的文档,不用每条来回。配 script 可以不写客户端就完成回填或字段迁移。

例子
POST /products/_update_by_query {"script":{"source":"ctx._source.active = true"},"query":{"term":{"in_stock":true}}}
DELETE /<index>/_doc/<id>

按 id 删单个文档。磁盘要等 Lucene segment 合并后才回收,大量删除后磁盘并不会立刻下降。

例子
DELETE /products/_doc/1
POST /<index>/_delete_by_query

删除所有匹配 query 的文档。比 DROP TABLE 安全,索引和 mapping 留着,只删数据,而且可以先用 search 预览。

常见坑: 只是标记 deleted,磁盘要等 segment 合并才回收。想"清空索引"用 DELETE /<index> + 重建,比 _delete_by_query 快得多。

例子
POST /logs/_delete_by_query {"query":{"range":{"@timestamp":{"lt":"now-30d"}}}}
POST /_bulk

一次请求里批量 index / update / delete,想吃满 ES 写吞吐只有这条路。NDJSON body:每个 op 两行,一行 action,一行 source。

常见坑: 甜区每次 bulk 5-15MB。< 1MB 来回太多;> 100MB 容易超时和 413。大 bulk 把 request timeout 调到 30s+。

例子
POST /_bulk
{"index":{"_index":"products","_id":"1"}}
{"name":"A"}
{"index":{"_index":"products","_id":"2"}}
{"name":"B"}
GET /_mget

一次拿多个文档(跨索引也行)。比发 N 个 GET /_doc 快很多。

例子
GET /_mget {"docs":[{"_index":"products","_id":"1"},{"_index":"products","_id":"2"}]}
GET /<index>/_count

查匹配 query 的文档数,比 search.size=0 加 total 便宜,不算分、不读 source。

例子
GET /products/_count
GET /products/_count {"query":{"term":{"in_stock":true}}}
GET /<index>/_source/<id>

只取文档的 _source,跳过元数据外壳(_index、_id、_version)。只要原始 JSON 时比 GET /_doc/<id> 略轻。

例子
GET /products/_source/1
GET /products/_source/1?_source_includes=name,price
HEAD /<index>/_doc/<id>

存在性检查,文档在就返回 200,不在就 404,不传 body。决定该 create 还是 update 前,问"这个 id 已经入库了吗"最省的方式。

例子
HEAD /products/_doc/1
PUT /<index>/_doc/<id>?if_seq_no=&if_primary_term=

乐观并发控制,只有当文档仍是你上次读到的 seq_no + primary_term 时才写。被别人抢先改过就返回 409,而不是悄悄覆盖丢更新。

常见坑: ES 没有行锁。不带 if_seq_no / if_primary_term,两个并发的读改写客户端会互相覆盖且无声。做 compare-and-set 更新一定要带这两个。

例子
PUT /products/_doc/1?if_seq_no=12&if_primary_term=2 {"name":"Headphones","stock":5}
POST /<index>/_update/<id> (upsert)

一次原子调用完成更新或插入,id 存在就跑 script/doc,不存在就写 upsert 体。"计数器自增,不存在就从 0 建"的标准写法。

例子
POST /counters/_update/page-1 {"script":{"source":"ctx._source.hits += params.n","params":{"n":1}},"upsert":{"hits":1}}
POST /products/_update/1 {"doc":{"price":89},"doc_as_upsert":true}
POST /<index>/_doc?routing=<value>

自定义 routing,用你的 routing 值(默认是 _id 的 hash)把文档钉到某个 shard。把相关文档(同一租户的全部)放同一 shard,带同 routing 的查询就只打一个 shard。

常见坑: 自定义 routing 若某个值占了大部分数据会造成热 shard。而且 GET/DELETE/update 必须带相同 routing,否则 ES 去错 shard 找,报 404。

例子
POST /orders/_doc?routing=tenant-42 {"tenant":"tenant-42","total":99}
GET /orders/_search?routing=tenant-42 {"query":{"match_all":{}}}
GET /<index>/_explain/<id>

逐项解释某条文档为什么(不)匹配某个 query,以及它的 BM25 分是怎么算出来的。调"这条为什么排在这"相关性问题的对口工具。

例子
GET /products/_explain/1 {"query":{"match":{"description":"wireless"}}}
POST /<index>/_termvectors/<id>

返回文档的 term vector,逐字段列出 term 及词频、位置、偏移、payload。用于调试分词、做"more like this"、或检查实际入库了什么。

例子
POST /products/_termvectors/1 {"fields":["description"],"term_statistics":true}
Mapping (18)
PUT /<index>/_mapping

给已存在的索引 mapping 加新字段或子字段。加新字段可以,改字段类型不行,改类型必须 reindex 到新索引。

常见坑: 字段一旦 mapping 成 keyword,就不能原地改成 text,必须建新索引 + reindex。

例子
PUT /products/_mapping {"properties":{"tags":{"type":"keyword"},"description":{"type":"text","analyzer":"english"}}}
GET /<index>/_mapping

看索引当前 mapping,每个字段的类型、分析器、子字段。写 query 前必看,免得对错字段类型查。

例子
GET /products/_mapping
GET /products/_mapping/field/name
type: text vs keyword

text = 分词后做全文搜索(match); keyword = 原样存为一个 token,用于过滤 / 排序 / 聚合。大多数字符串字段两个都要,用 multi-field。

常见坑: text 字段默认不能聚合 / 排序(fielddata 关)。字符串字段都按 text + keyword 子字段写:{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}}。

例子
{"properties":{"name":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}}}}
type: date

日期字段。接受 ISO 8601、毫秒时间戳、或 format 里声明的任意格式。内部存毫秒 long,range 查询飞快。

例子
{"properties":{"@timestamp":{"type":"date","format":"strict_date_optional_time||epoch_millis"}}}
type: nested

nested 对象,保留对象数组里子字段的"绑定关系"。需要"数组中某一个元素同时满足 A 和 B"的查询时必用。

常见坑: 普通 object 数组会扁平化,{"tags":[{"k":"x","v":1},{"k":"y","v":2}]} 变成 {tags.k:[x,y], tags.v:[1,2]},bool "k=x AND v=2" 会误中。同一对象内 AND 重要时必须用 nested。

例子
{"properties":{"variants":{"type":"nested","properties":{"sku":{"type":"keyword"},"price":{"type":"double"}}}}}
type: geo_point

地理点字段,支持 lat/lon 对象、[lon,lat] 数组、"lat,lon" 字符串、geohash。开启 geo_distance、geo_bounding_box、geo_polygon 查询和 geo_distance 排序。

例子
{"properties":{"location":{"type":"geo_point"}}}
POST /stores/_doc {"location":{"lat":40.71,"lon":-74.0}}
dynamic: true · false · strict

控制写入未知字段时的行为。true = 自动建(默认,危险); false = 忽略未知字段; strict = 直接拒绝整条文档报错。

常见坑: 用户控制的输入用默认 dynamic:true 会导致"mapping 爆炸",上百万自动建的字段把 cluster state 撑爆。用户传 JSON 一律 dynamic:strict。

例子
{"mappings":{"dynamic":"strict","properties":{"name":{"type":"text"}}}}
multi-field (fields)

一个源字段索引出多个子字段,不同分析器 / 类型,name 全文搜、name.keyword 精确匹配、name.autocomplete 做自动补全。

例子
{"properties":{"name":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256},"english":{"type":"text","analyzer":"english"}}}}}
index: false

存但不建索引,省磁盘和内存,字段变成搜不到。适合只在 _source 返回的字段(展示用标签、原始 HTML、blob 等)。

例子
{"properties":{"raw_html":{"type":"text","index":false}}}
numeric types (long, integer, double, scaled_float)

挑能装下的最小数值类型,整数用 byte/short/integer/long,实数用 float/double/half_float。scaled_float 把浮点按因子存成 long(价格 × 100),固定精度的金额比 double 更小更快。

常见坑: order_id、电话号这种标识符别只因为长得像数字就映射成数值类型,你根本不会对它做范围运算,用 keyword 索引和聚合都高效得多。

例子
{"properties":{"price":{"type":"scaled_float","scaling_factor":100}}}
{"properties":{"order_id":{"type":"keyword"}}}
type: ip

ip 字段,存 IPv4 和 IPv6,并能直接做 CIDR 范围查询("10.0.0.0/8 网段全部")。比把 IP 存成 keyword 字符串强得多,后者没法做子网匹配。

例子
{"properties":{"client_ip":{"type":"ip"}}}
{"query":{"term":{"client_ip":"10.0.0.0/8"}}}
type: boolean

boolean 字段,接受 true/false 以及字符串 "true"/"false"。索引成单个 term,对它做 term/filter 查询极便宜且可缓存。

例子
{"properties":{"in_stock":{"type":"boolean"}}}
{"query":{"term":{"in_stock":true}}}
type: object vs flattened

普通 object 把每个子 key 各映射成一个字段(已知结构好用,无限 key 灾难)。flattened 把整个 JSON 对象索引成"一个字段"里的 keyword 叶子,正好用于会撑爆 mapping 的任意元数据/标签。

常见坑: flattened 字段只能精确匹配,没有全文分词、没有逐叶子类型、不能数值范围。它是用来"驯服"无限 key 的,不是拿来当 text 搜的。

例子
{"properties":{"labels":{"type":"flattened"}}}
{"query":{"term":{"labels.env":"prod"}}}
type: completion (suggester)

completion suggester 专用类型,底层是内存里的 FST,为带权重的快速前缀补全优化。要带排序的补全候选时,搜索框用它而不是 edge_ngram。

例子
{"properties":{"suggest":{"type":"completion"}}}
POST /products/_search {"suggest":{"s":{"prefix":"head","completion":{"field":"suggest","size":5}}}}
type: dense_vector (kNN)

存浮点向量做语义 / kNN 检索(8.0+)。设 index:true 加 HNSW similarity(cosine、dot_product、l2_norm)就能做近似最近邻,是 ES 里向量 / embedding 检索的底座。

常见坑: dot_product similarity 要求单位长度(归一化)向量,喂未归一化的向量会悄悄扭曲相关性。入库前归一化 embedding,或改用 cosine。

例子
{"properties":{"embedding":{"type":"dense_vector","dims":768,"index":true,"similarity":"cosine"}}}
type: alias

field alias,一个虚拟名,查询和聚合时指向真实字段,不复制数据。让你在查询层给字段改名("ts" → "@timestamp")而无需 reindex。

常见坑: alias 只对读路径(查询、聚合、排序)有效,不能往 alias 字段写入,也不能指向 object 或另一个 alias。

例子
{"properties":{"@timestamp":{"type":"date"},"ts":{"type":"alias","path":"@timestamp"}}}
copy_to

入库时把多个源字段合并到一个可搜字段,不用 multi_match 就能跨 first_name + last_name 搜 "John Smith"。合并字段可搜但不出现在 _source 里。

例子
{"properties":{"first_name":{"type":"text","copy_to":"full_name"},"last_name":{"type":"text","copy_to":"full_name"},"full_name":{"type":"text"}}}
runtime field

runtime field,字段值由 Painless 脚本在"查询时"算,不落盘(schema-on-read)。给老数据加或修字段而无需 reindex,代价是每次查询多花一点 CPU 而不是磁盘。

常见坑: runtime field 每次查询对每条命中文档现算,过滤少量结果便宜,对上百万条排序/聚合就贵。某个热 runtime field 形态稳定后,把它提升为索引字段。

例子
PUT /logs/_mapping {"runtime":{"status_class":{"type":"keyword","script":{"source":"emit(doc['status'].value >= 500 ? '5xx' : 'ok')"}}}}
Query DSL (31)
match

全文搜索,用字段分析器分析 query 串,任一 token 命中即可,按 BM25 打分。搜 text 字段的默认选择。

例子
GET /products/_search {"query":{"match":{"description":"wireless headphones"}}}
GET /_search {"query":{"match":{"description":{"query":"wireless headphones","operator":"and","minimum_should_match":"75%"}}}}
match_phrase

短语查询,token 必须按顺序连着出现(或允许 slop 个间隔)。做"完整短语"搜索;slop=2 允许中间夹几个词。

例子
{"query":{"match_phrase":{"description":"wireless noise cancelling"}}}
{"query":{"match_phrase":{"description":{"query":"wireless headphones","slop":2}}}}
multi_match

同一个 query 串同时打多个字段,可加权。type=best_fields 取打分最高字段;cross_fields 当成一个大字段。

例子
{"query":{"multi_match":{"query":"wireless","fields":["name^3","description"],"type":"best_fields"}}}
term

精确值查询,不分词。用于 keyword / 数值 / 布尔 / 日期 字段。对 text 字段用 term 搜 "Apple" 会全空,因为 text 入库时变成了小写。

常见坑: term 对 text 字段几乎永远 0 命中,text 入库时小写化 + 分词,"Apple" 变成 "apple"。要么查 name.keyword,要么改用 match。

例子
{"query":{"term":{"status":"active"}}}
{"query":{"term":{"name.keyword":"Apple"}}}
terms

字段值等于列表中任意一个就命中,ES 版的 SQL IN。默认上限 65536 个 term,真要更多就调 index.max_terms_count。

例子
{"query":{"terms":{"status":["active","pending","review"]}}}
range

数值 / 日期 / IP 范围查询。日期支持 date math,now-1d, now/d(向下取整到天), now+5m 等。包含 gte/lte,不含 gt/lt。

例子
{"query":{"range":{"price":{"gte":10,"lte":100}}}}
{"query":{"range":{"@timestamp":{"gte":"now-7d/d","lt":"now/d"}}}}
bool (must / should / must_not / filter)

布尔组合。must = AND(打分), should = OR(打分,影响分数), must_not = NOT(不打分), filter = AND(不打分,可缓存,最快)。不需要打分一律用 filter。

常见坑: 把等值 / 范围条件放 must 而不是 filter,既浪费打分 CPU 又错过 filter 缓存。"是不是真"的条件全挪到 filter,"打分排序"的才放 must。

例子
{"query":{"bool":{"must":[{"match":{"description":"wireless"}}],"filter":[{"term":{"in_stock":true}},{"range":{"price":{"lte":200}}}],"must_not":[{"term":{"discontinued":true}}]}}}
wildcard

通配符匹配,* 任意多字符,? 单字符。跑在 keyword 上(text 上有坑)。前导通配符("*foo")会全索引扫,大索引上很慢。

常见坑: 前导通配符("*foo*")是最慢的 query,用不上倒排索引。要 "contains" 搜索,改用 wildcard 字段(7.9+)或 ngram 分析器。

例子
{"query":{"wildcard":{"sku.keyword":{"value":"SKU-*-RED"}}}}
regexp

keyword 字段上的正则匹配。用 Lucene 风格的 regex(不是完整 PCRE)。整个 term 锚定,不用写 ^$。

常见坑: 长 term 上 regex 可能指数级慢;用 max_determinized_states 封顶。高基数字段上 ngram 分析器比 regex 快。

例子
{"query":{"regexp":{"sku.keyword":{"value":"[A-Z]{3}-[0-9]{4}","max_determinized_states":10000}}}}
prefix

前缀匹配,找以指定字符串开头的 term。在 keyword 字段上便宜(倒排索引有序)。做"输入即搜"用这个,别用 wildcard。

例子
{"query":{"prefix":{"name.keyword":{"value":"Apple"}}}}
fuzzy

Levenshtein 距离模糊匹配,容错拼写。AUTO 按 term 长度选 0/1/2 次编辑。长 term 上慢,用 prefix_length 和 max_expansions 封顶。

例子
{"query":{"fuzzy":{"name":{"value":"helo","fuzziness":"AUTO","prefix_length":1}}}}
exists

匹配字段存在(非 null、非空)的文档。ES 里最接近 SQL IS NOT NULL 的写法。放 must_not 里即 IS NULL。

例子
{"query":{"exists":{"field":"email"}}}
{"query":{"bool":{"must_not":[{"exists":{"field":"email"}}]}}}
ids

在一次 query 里按 id 拉一小批文档。比 _mget 灵活(同一 query 接口,可打分、可高亮)。

例子
{"query":{"ids":{"values":["1","2","42"]}}}
nested query

nested 字段内的查询,"所有条件落在同一个 nested 对象上"必用。inner_hits 返回究竟是哪个 nested 元素命中。

例子
{"query":{"nested":{"path":"variants","query":{"bool":{"must":[{"term":{"variants.color":"red"}},{"range":{"variants.price":{"lte":50}}}]}},"inner_hits":{}}}}
geo_distance

匹配离某点 D 距离内的文档。配 sort:_geo_distance 实现"最近优先"。默认距离单位米,支持 km、mi。

例子
{"query":{"geo_distance":{"distance":"5km","location":{"lat":40.71,"lon":-74.0}}}}
function_score

自定义打分,按时间衰减、热度、地理距离、随机、脚本来改 BM25 分。score_mode 和 boost_mode 控制怎么混。

例子
{"query":{"function_score":{"query":{"match":{"description":"wireless"}},"functions":[{"gauss":{"@timestamp":{"origin":"now","scale":"30d"}}}],"boost_mode":"multiply"}}}
highlight

每条命中返回带 <em>...</em> 标记的片段(可配置)。三种 highlighter:unified(默认,均衡), plain(慢但准), fvh(快,需要 term_vector=with_positions_offsets)。

例子
{"query":{"match":{"description":"wireless"}},"highlight":{"fields":{"description":{"fragment_size":150,"number_of_fragments":3}}}}
search_after (deep pagination)

稳定深度分页,把上一页最后一条的 sort 值作为下一页的 search_after。翻 10000 之外的页用这个,别用 from + size。

常见坑: from + size 深翻页默认到 index.max_result_window=10000 就报错,而且即使没到,每个 coordinator 也要从每个 shard 拉 from+size 条。用 search_after 或 PIT。

例子
{"size":20,"sort":[{"@timestamp":"desc"},{"_id":"asc"}],"search_after":["2026-05-26T10:00:00Z","abc123"]}
scroll · point_in_time

scroll = 离线导出用的老快照接口。PIT(point-in-time, 7.10+)= 现代替代品,配 search_after 实现可恢复 + 快照一致的分页。

例子
POST /products/_pit?keep_alive=5m
GET /_search {"pit":{"id":"<pit-id>","keep_alive":"5m"},"size":100,"sort":[{"_shard_doc":"asc"}]}
match_all · match_none

match_all 返回所有文档,分数恒为 1,是默认 query,也是"给我全部"(分页)的正路。match_none 什么都不返回,在模板化 query 里当占位符好用。

例子
{"query":{"match_all":{}}}
{"query":{"match_none":{}}}
terms_set

terms_set,当命中的 term 数达到下限就匹配,下限来自字段或脚本,"至少列出 N 个技能就算匹配"。表达"5 选 3"这类需求的 DSL 写法。

例子
{"query":{"terms_set":{"skills":{"terms":["es","sql","python"],"minimum_should_match_field":"required_matches"}}}}
constant_score

constant_score 包住一个 filter,让所有命中拿同一固定分(boost),完全跳过 BM25。想要 filter 缓存的速度,又需要某个 should 子句贡献一个平的加分时用它。

例子
{"query":{"constant_score":{"filter":{"term":{"in_stock":true}},"boost":1.2}}}
dis_max

dis_max,跑多个 query,取打分最高的那个作为结果分(再加 tie_breaker × 其余)。避免同一 term 命中多个字段时文档被重复加分。

例子
{"query":{"dis_max":{"queries":[{"match":{"title":"wireless"}},{"match":{"body":"wireless"}}],"tie_breaker":0.3}}}
query_string · simple_query_string

把 Lucene 语法串("wireless AND (headphones OR earbuds) -wired")解析成 query。query_string 强但语法错会抛异常;simple_query_string 永不报错,适合直接接终端用户输入。

常见坑: query_string 绝不要直接暴露给不可信用户,畸形或恶意 query(深通配、巨大布尔树)会报错或拖垮集群。公开搜索框用 simple_query_string。

例子
{"query":{"simple_query_string":{"query":"wireless +headphones -wired","fields":["name^2","description"]}}}
more_like_this (MLT)

more_like_this,基于共有的显著 term,找与给定文本或种子文档相似的文档。不用 embedding 就能做经典的"相关文章" / "类似商品"。

例子
{"query":{"more_like_this":{"fields":["title","body"],"like":[{"_index":"articles","_id":"42"}],"min_term_freq":1,"max_query_terms":12}}}
knn search (vector)

knn 检索,在 dense_vector 字段上用 HNSW 做近似最近邻(8.x 顶层 knn)。返回离查询向量最近的 k 个,是语义 / RAG 检索的召回那一半。配 filter 限定候选集。

例子
POST /docs/_search {"knn":{"field":"embedding","query_vector":[0.12,0.83],"k":10,"num_candidates":100,"filter":{"term":{"lang":"zh"}}}}
distance_feature

distance_feature,按 date 或 geo_point 字段离某 origin 的远近加分,随距离衰减,在 bool 里便宜地把更新 / 更近的结果往上提。比 function_score 做常见的"时效 / 就近"加分更快。

例子
{"query":{"bool":{"must":{"match":{"description":"coffee"}},"should":{"distance_feature":{"field":"@timestamp","origin":"now","pivot":"7d"}}}}}
sort (multi-field, missing, mode)

按一个或多个字段排序,各自 asc/desc,用 missing:_first/_last 处理空值,用 mode(min/max/avg/sum/median)把数组字段折叠成一个值。按字段排序会关掉算分,除非显式加 track_scores。

例子
{"sort":[{"price":{"order":"asc","missing":"_last"}},{"_score":"desc"}]}
{"sort":[{"ratings":{"order":"desc","mode":"avg"}}]}
_source filtering · stored_fields

控制每条命中返回什么,_source:false 完全不返回 body,_source:{includes,excludes} 挑字段,fields:[...] 返回格式化后的值(适合 runtime field 和日期)。给宽文档瘦身。

例子
{"_source":{"includes":["name","price"]},"query":{"match_all":{}}}
{"_source":false,"fields":["name","@timestamp"],"query":{"match_all":{}}}
GET /_search/template

用运行时参数跑一个存好的 Mustache 搜索模板,query 结构留在服务端,客户端只传值。比用字符串拼 query JSON 更干净也更安全。

例子
POST /_scripts/find_by_status {"script":{"lang":"mustache","source":{"query":{"term":{"status":"{{s}}"}}}}}
GET /products/_search/template {"id":"find_by_status","params":{"s":"active"}}
GET /_search?profile=true

profile 一个 query,拿到逐 shard、逐组件的耗时拆解(哪个子查询、rewrite、collector)。排除 mapping 错误后,定位"这个搜索为什么慢"的权威工具。

例子
GET /products/_search {"profile":true,"query":{"bool":{"must":[{"match":{"description":"wireless"}}]}}}
聚合 (22)
terms agg

按字段值分组,等价 SQL GROUP BY。按 doc 数返回 top N 桶(默认 size=10)。最常用的聚合,所有 facet、"销量榜"报表都走它。

常见坑: terms agg 默认 size=10 在高基数字段上会漏长尾,而且是近似的,看 doc_count_error_upper_bound。要"所有桶"分页用 composite agg。

例子
{"size":0,"aggs":{"by_status":{"terms":{"field":"status","size":20}}}}
avg · sum · min · max · stats

数值字段上的单值聚合。stats 一次返回五个(count, min, max, avg, sum)通常都比分开跑划算。

例子
{"size":0,"aggs":{"price_stats":{"stats":{"field":"price"}}}}
{"size":0,"aggs":{"avg_price":{"avg":{"field":"price"}}}}
cardinality

HyperLogLog++ 估算 distinct count,内存恒定,与基数无关。precision_threshold(默认 3000,最大 40000)调精度 / 内存权衡。

常见坑: cardinality 是近似值,典型误差 1-6%。需要精确且 < 10w 用 terms agg 数桶。计费、合规数字绝不用它。

例子
{"size":0,"aggs":{"unique_users":{"cardinality":{"field":"user_id","precision_threshold":40000}}}}
date_histogram

按日期间隔分桶。calendar_interval(1d, 1M, 1y,处理夏令时和月长不一)或 fixed_interval(30s, 1h, 7d)。所有时序看板的骨架。

例子
{"size":0,"aggs":{"daily":{"date_histogram":{"field":"@timestamp","calendar_interval":"1d","time_zone":"Asia/Shanghai"}}}}
histogram

数值直方图,按定宽间隔在数值字段上分桶。用于价格区间、延迟分布等。

例子
{"size":0,"aggs":{"price_dist":{"histogram":{"field":"price","interval":50,"min_doc_count":1}}}}
range

在数值 / 日期字段上自定义区间桶,自己定阈值。固定宽度 histogram 不符合业务桶(如 $0-49, $50-199, $200+)时用这个。

例子
{"size":0,"aggs":{"price_tier":{"range":{"field":"price","ranges":[{"to":50},{"from":50,"to":200},{"from":200}]}}}}
percentiles · percentile_ranks

基于 t-digest 或 HDR 的近似分位数。percentiles 给 p50/p95/p99;percentile_ranks 给"小于 X 的占多少 %"。延迟 SLO 看板的骨架。

例子
{"size":0,"aggs":{"latency_p":{"percentiles":{"field":"latency_ms","percents":[50,95,99]}}}}
composite agg (paginate all buckets)

通过 after_key 按稳定顺序遍历"所有"分组桶,想"列出全部唯一组合"且不一次性塞内存,只有这个安全。

例子
{"size":0,"aggs":{"all_combos":{"composite":{"size":1000,"sources":[{"status":{"terms":{"field":"status"}}},{"day":{"date_histogram":{"field":"@timestamp","calendar_interval":"1d"}}}]}}}}
sub-aggregations (nested aggs)

聚合可以嵌套,每个桶下面再挂 metric 或 bucket 子聚合。"按状态再按天的平均价"两层就能表达。

例子
{"size":0,"aggs":{"by_status":{"terms":{"field":"status"},"aggs":{"by_day":{"date_histogram":{"field":"@timestamp","calendar_interval":"1d"},"aggs":{"avg_price":{"avg":{"field":"price"}}}}}}}}
filter agg

把子聚合限定在一个子集上,一次性 WHERE,不影响外层 query。比为每个子集重跑 query 便宜。

例子
{"size":0,"aggs":{"in_stock_avg":{"filter":{"term":{"in_stock":true}},"aggs":{"avg_price":{"avg":{"field":"price"}}}}}}
top_hits agg

每个桶内返回 top N 真实文档,按分数或自定义 sort。用于"每类展示 3 条示例"或"每用户最新事件"模式。

例子
{"size":0,"aggs":{"per_cat":{"terms":{"field":"category"},"aggs":{"sample":{"top_hits":{"size":3,"sort":[{"@timestamp":"desc"}]}}}}}}
significant_terms

找在子集中相对全集"显著超量"的 term,自动浮现"这组与众不同在哪",不用手动调权。

例子
{"size":0,"query":{"term":{"status":"fraud"}},"aggs":{"why_fraud":{"significant_terms":{"field":"ip_country"}}}}
value_count

value_count,统计某字段有值的文档数,相当于 SQL 的 COUNT(field)。与 _count 不同,它跳过字段缺失的文档,所以可能和桶的 doc_count 不一致。

例子
{"size":0,"aggs":{"with_email":{"value_count":{"field":"email"}}}}
extended_stats

比 stats 多了方差、标准差、平方和、标准差边界,正是离群检测和统计异常阈值需要的指标。

例子
{"size":0,"aggs":{"lat":{"extended_stats":{"field":"latency_ms","sigma":3}}}}
date_range

把日期分到命名的显式区间(支持 now-1M/M 这类 date math 边界),"本月 vs 上月 vs 更早"。只需要少量有意义的桶时,比 date_histogram 干净。

例子
{"size":0,"aggs":{"buckets":{"date_range":{"field":"@timestamp","ranges":[{"key":"last_7d","from":"now-7d/d"},{"key":"older","to":"now-7d/d"}]}}}}
nested agg

nested 聚合,进入一个 nested 字段,让子聚合按"每个 nested 对象"而非"每个父文档"成桶。variants 是 nested 类型时,正确算"所有 variant 的均价"必用。配 reverse_nested 再爬回父层。

例子
{"size":0,"aggs":{"variants":{"nested":{"path":"variants"},"aggs":{"avg_price":{"avg":{"field":"variants.price"}}}}}}
filters agg (multi-bucket)

filters 聚合,定义多个命名 filter,一遍扫描每个 filter 出一个桶,"error vs warn vs info"一次性数出来,不用发三个 query。是单数 filter 聚合的复数版。

例子
{"size":0,"aggs":{"levels":{"filters":{"filters":{"errors":{"term":{"level":"error"}},"warnings":{"term":{"level":"warn"}}}}}}}
global agg

global 聚合,把子聚合从外层 query 里挣脱出来,让它看到"所有文档"而不只是命中的,在一个请求里同时算"全部均价"和"搜索结果均价"。

例子
{"query":{"match":{"name":"wireless"}},"aggs":{"all":{"global":{},"aggs":{"avg_price":{"avg":{"field":"price"}}}}}}
bucket_script (pipeline)

bucket_script 是管道聚合,从同级的其它聚合结果再算一个值,比如每桶的转化率 = 销量 ÷ 访问。让你在 ES 里就算出比率和差值,而不用客户端后处理。

例子
{"size":0,"aggs":{"by_day":{"date_histogram":{"field":"@timestamp","calendar_interval":"1d"},"aggs":{"sales":{"sum":{"field":"sale"}},"visits":{"sum":{"field":"visit"}},"cvr":{"bucket_script":{"buckets_path":{"s":"sales","v":"visits"},"script":"params.v > 0 ? params.s / params.v : 0"}}}}}}
derivative · cumulative_sum (pipeline)

作用在有序直方图上的管道聚合,derivative 给相邻桶的变化量("每日增量"),cumulative_sum 给累计("累计注册数")。两者都需要一个父 date_histogram 或 histogram。

例子
{"size":0,"aggs":{"daily":{"date_histogram":{"field":"@timestamp","calendar_interval":"1d"},"aggs":{"signups":{"sum":{"field":"new_users"}},"growth":{"derivative":{"buckets_path":"signups"}},"total":{"cumulative_sum":{"buckets_path":"signups"}}}}}}
moving_fn (pipeline)

moving_fn,在直方图桶的滑动窗口上跑窗口函数(移动平均、min、max、stdDev、线性加权),在 query 里就把抖动的时序抹平,或算 7 日滚动均值。

例子
{"size":0,"aggs":{"daily":{"date_histogram":{"field":"@timestamp","calendar_interval":"1d"},"aggs":{"v":{"sum":{"field":"sale"}},"ma7":{"moving_fn":{"buckets_path":"v","window":7,"script":"MovingFunctions.unweightedAvg(values)"}}}}}}
geohash_grid · geotile_grid

把 geo_point 文档按指定精度分到网格单元,是热力图和地图聚合标记的后端。geotile_grid 对齐标准网络地图瓦片(z/x/y),单元和地图瓦片严丝合缝。

例子
{"size":0,"aggs":{"heat":{"geohash_grid":{"field":"location","precision":5}}}}
{"size":0,"aggs":{"tiles":{"geotile_grid":{"field":"location","precision":10}}}}
分析器 (17)
standard analyzer

默认 text 分析器,Unicode 词边界(UAX #29)+ 小写。多数西文够用。中日韩不行,中文用 ik、日文 kuromoji、韩文 nori。

例子
POST /_analyze {"analyzer":"standard","text":"Quick brown FOX 2026!"}
POST /_analyze

测试某分析器怎么把字符串切成 token,"match 查不到东西" 时最有用的调试工具。开工单前先跑一遍。

例子
POST /_analyze {"analyzer":"english","text":"Running quickly through the parks"}
POST /products/_analyze {"field":"name","text":"Wireless Headphones"}
language analyzers (english, french, ...)

内置语言分析器,按 locale 做词干提取、停用词、小写。english 把 "running" 变 "run"、"parks" 变 "park"。面向用户的文本搜索按语言选。

例子
{"properties":{"description":{"type":"text","analyzer":"english"}}}
custom analyzer

把 char_filter + tokenizer + token_filter 组合成自己的分析器。自动补全、search-as-you-type、方言处理、任何非默认分词需求都按这个走。

例子
PUT /demo {"settings":{"analysis":{"analyzer":{"my_a":{"type":"custom","tokenizer":"standard","filter":["lowercase","asciifolding","stop"]}}}}}
edge_ngram (autocomplete)

入库时为每个 token 生成前缀,"wireless" 入库为 ["wi","wir","wire",...,"wireless"]。简单 match 就能做自动补全,不用前导通配符。

常见坑: edge_ngram 只放在 index analyzer 上。search_analyzer 必须是 standard / lowercase,否则搜索 token 也会被切成前缀,命中爆炸。

例子
{"settings":{"analysis":{"filter":{"edge":{"type":"edge_ngram","min_gram":2,"max_gram":15}},"analyzer":{"ac_idx":{"tokenizer":"standard","filter":["lowercase","edge"]},"ac_search":{"tokenizer":"standard","filter":["lowercase"]}}}}}
ngram

为每个 token 生成 min_gram..max_gram 长度的全部子串,不用通配符就能做"contains"搜索。耗磁盘和入库时间,只用在短字段上。

例子
{"settings":{"analysis":{"filter":{"ng":{"type":"ngram","min_gram":3,"max_gram":4}},"analyzer":{"ng_a":{"tokenizer":"standard","filter":["lowercase","ng"]}}}}}
synonym filter

入库或搜索时映射同义词,"tv" ⇄ "television"、"laptop" ⇄ "notebook"。搜索时同义词不占额外磁盘;入库时同义词查询便宜但改词得 reindex。

例子
{"settings":{"analysis":{"filter":{"syn":{"type":"synonym","synonyms":["tv,television","laptop,notebook"]}},"analyzer":{"syn_a":{"tokenizer":"standard","filter":["lowercase","syn"]}}}}}
stop filter

入库或搜索时移除常见停用词(the / a / is)。省索引体积、提相关性,但会让含停用词的短语查询失效("to be or not to be")。

例子
{"settings":{"analysis":{"analyzer":{"my_a":{"tokenizer":"standard","filter":["lowercase","english_stop"]}},"filter":{"english_stop":{"type":"stop","stopwords":"_english_"}}}}}
asciifolding filter

把非 ASCII 字符转 ASCII 等价物,"café" → "cafe"、"naïve" → "naive"。用户敲不带音标的也能搜到带音标的。

例子
{"settings":{"analysis":{"analyzer":{"folding":{"tokenizer":"standard","filter":["lowercase","asciifolding"]}}}}}
CJK analyzers (ik, kuromoji, nori)

standard 把 CJK 文本当一个大 token,中日韩搜索完全没法用。装对应插件:中文 ik、日文 kuromoji、韩文 nori。

常见坑: 托管服务(AWS OpenSearch、Elastic Cloud)上线前先确认分析器插件是不是预装的,装自定义插件可能要换 tier。

例子
PUT /zh_demo {"settings":{"analysis":{"analyzer":{"ik_a":{"type":"custom","tokenizer":"ik_smart"}}}}}
keyword analyzer

keyword 分析器,把整段输入原样当成一个 token,不切词、不小写。用在 text 字段上,当你确实要精确、不分词的匹配但又想保留 text 行为(比如高亮)时。

例子
POST /_analyze {"analyzer":"keyword","text":"Wireless Headphones X1"}
whitespace · pattern · simple analyzers

内置轻量分析器,whitespace 只按空格切(保留大小写和标点),pattern 按你给的正则切,simple 按非字母切并小写。处理日志 token、编码、类 CSV 字段很顺手。

例子
POST /_analyze {"analyzer":"whitespace","text":"ERROR 500 /api/v1"}
PUT /demo {"settings":{"analysis":{"analyzer":{"by_comma":{"type":"pattern","pattern":","}}}}}
search_as_you_type field

search_as_you_type 字段类型,自动帮你建好 edge-ngram 子字段(._index_prefix、._2gram、._3gram),一个 multi_match 就能做边打边搜,不用手搭 edge_ngram 分析器。

例子
{"properties":{"q":{"type":"search_as_you_type"}}}
{"query":{"multi_match":{"query":"head","type":"bool_prefix","fields":["q","q._2gram","q._3gram"]}}}
char_filter (mapping, html_strip, pattern_replace)

char_filter 在分词"之前"预处理原文,html_strip 去标签,mapping 替换字符("&" → "and"),pattern_replace 跑正则替换。它在 tokenizer 之前跑,能修掉会被分词器搞乱的输入。

例子
PUT /demo {"settings":{"analysis":{"analyzer":{"clean":{"tokenizer":"standard","char_filter":["html_strip"]}}}}}
normalizer (keyword case-insensitive)

normalizer 是只含 token filter 的管道,给 keyword 字段用,没有 tokenizer,只做 lowercase/asciifolding,让 "USA" 和 "usa" 当成同一个 term 精确匹配。想要大小写无关的精确匹配又不想换 text,用它。

例子
PUT /demo {"settings":{"analysis":{"normalizer":{"lc":{"type":"custom","filter":["lowercase","asciifolding"]}}},"mappings":{"properties":{"country":{"type":"keyword","normalizer":"lc"}}}}}
analyzer vs search_analyzer

一个字段可以入库用一种分析器、搜索用另一种。经典搭配:入库 edge_ngram、搜索 standard,这样 "wir" 入库切成前缀,而查询词 "wir" 保持单个 token。

常见坑: 只设 "analyzer" 会同时用于入库和搜索。配了 edge_ngram 入库分析器却忘了设 search_analyzer,是"自动补全命中爆炸"的头号原因。

例子
{"properties":{"name":{"type":"text","analyzer":"ac_idx","search_analyzer":"standard"}}}
stemmer · kstem · porter

stemmer 类 token filter 把词归约到词根,"running"/"ran" → "run"。按激进程度选算法:kstem(轻,保留真实词)、porter/porter2(经典)、或语言专用 stemmer。过度归约会伤精确度。

例子
{"settings":{"analysis":{"filter":{"en_stem":{"type":"stemmer","language":"light_english"}},"analyzer":{"a":{"tokenizer":"standard","filter":["lowercase","en_stem"]}}}}}
集群与 _cat (18)
GET /_cluster/health

集群健康摘要,状态(绿 / 黄 / 红)、节点数、shard 数、未分配 shard。绿 = 主 + 副本全分配,黄 = 主 OK 但副本有未分配,红 = 主有未分配(可能丢数据)。

例子
GET /_cluster/health
GET /_cluster/health?level=indices&wait_for_status=green&timeout=30s
GET /_cluster/stats

集群级统计,总文档数、存储体积、JVM heap、OS 负载、写入 / 搜索速率。下钻到节点 / 索引前的"全局快照"。

例子
GET /_cluster/stats
GET /_cluster/settings

查集群级动态 + 持久设置。persistent 重启后保留;transient 重启就丢,几乎总是用 persistent。

例子
GET /_cluster/settings?include_defaults=true
PUT /_cluster/settings {"persistent":{"cluster.routing.allocation.disk.watermark.low":"85%"}}
GET /_cluster/allocation/explain

解释某 shard 为什么分 / 没分到某节点,排查"黄集群一直黄""shard 卡在 INITIALIZING"的第一工具。逐节点返回真实原因。

例子
GET /_cluster/allocation/explain {"index":"products","shard":0,"primary":true}
GET /_cat/health

_cat 系列 API,人类友好的文本表,终端和脚本都好读。/_cat/health 是"一眼看集群行不行"的命令。

例子
GET /_cat/health?v
GET /_cat/health?h=status,node.total,shards
GET /_cat/nodes

列每个节点,IP、角色(m=master, d=data, i=ingest)、heap %、CPU、负载。?v 加表头, ?h=name,role,heap.percent,ram.percent 输出更紧凑。

例子
GET /_cat/nodes?v
GET /_cat/nodes?h=name,role,heap.percent,ram.percent,cpu&v
GET /_cat/indices

每索引摘要,健康、状态、主 / 副本数、文档数、存储体积。?s=store.size:desc 快速找最大的索引。

例子
GET /_cat/indices?v
GET /_cat/indices?v&s=store.size:desc&bytes=gb
GET /_cat/shards

列出所有 shard 的状态(STARTED, INITIALIZING, RELOCATING, UNASSIGNED)、所在节点、体积。?h=index,shard,prirep,state,unassigned.reason 排查未分配 shard。

例子
GET /_cat/shards?v
GET /_cat/shards?h=index,shard,prirep,state,unassigned.reason&v
GET /_cat/aliases · /_cat/templates · /_cat/recovery

其它 _cat 助手:aliases 列 alias→index 映射, templates 按 pattern 列模板, recovery 看 shard 恢复进度(rolling 重启时常用)。

例子
GET /_cat/aliases?v
GET /_cat/templates?v
GET /_cat/recovery?v&active_only=true
GET /_nodes/stats

节点级详细统计,JVM、OS、process、fs、indices、thread_pool。用 /_nodes/stats/thread_pool 钻 search / write 线程池饱和。

例子
GET /_nodes/stats/jvm,thread_pool
GET /_nodes/<node>/stats/indices/search
GET /_tasks

列长任务(reindex, update_by_query, force-merge, snapshot)及进度。用 POST /_tasks/<id>/_cancel 取消,失控操作的开关。

例子
GET /_tasks?actions=*reindex&detailed=true
POST /_tasks/<task-id>/_cancel
GET /_nodes/hot_threads

采样各节点上最烫(最吃 CPU)的线程,直接给出此刻在吃 CPU 的栈。某个节点 CPU 顶到 100%、要知道是哪个操作干的时候,第一时间看它。

例子
GET /_nodes/hot_threads?threads=3&interval=500ms
GET /_cat/thread_pool

各节点线程池统计,write、search 等池的 active、queue、rejected 数。write/search 池 queue 在涨或 rejected 非零,是集群过载最清楚的信号。

例子
GET /_cat/thread_pool/write,search?v&h=node_name,name,active,queue,rejected
POST /_cluster/reroute?retry_failed=true

让集群重新尝试分配那些撞到最大重试次数(默认 5)的 shard,在你修好根因(腾盘、重启节点)之后,给 UNASSIGNED shard 的手动一推。

常见坑: reroute?retry_failed 只有在根因消失后才有用,磁盘还满 / 节点还挂着就跑它,只是再次烧掉重试额度。先看 allocation/explain。

例子
POST /_cluster/reroute?retry_failed=true
GET /_cat/segments · /_cat/fielddata

更多 _cat 诊断,segments 看逐 shard 的 Lucene segment 数 / 体积(数高→考虑对只读索引 force-merge),fielddata 看每个字段占的 fielddata heap(揪出撑爆 heap 的字段)。

例子
GET /_cat/segments/products?v
GET /_cat/fielddata?v&s=size:desc
GET /_cat/count · /_cat/master · /_cat/allocation

速查一行命令,count 给某索引 pattern 的总文档数,master 显示当选的 master 节点,allocation 显示每节点的磁盘用量 / 可用和 shard 数(快速发现倾斜的节点)。

例子
GET /_cat/count/logs-*?v
GET /_cat/master?v
GET /_cat/allocation?v
cluster.routing.allocation.enable

临时控制 shard 分配,rolling 重启前设成 "none",免得集群白白去重平衡一个你马上要拉回来的节点的 shard。重启完再设回 "all"。

常见坑: 维护后忘了设回 "all",新 shard / 副本会一直 UNASSIGNED,集群黄 / 红再怎么等也不好。禁用和重新启用必须成对出现。

例子
PUT /_cluster/settings {"persistent":{"cluster.routing.allocation.enable":"none"}}
PUT /_cluster/settings {"persistent":{"cluster.routing.allocation.enable":"all"}}
GET /_cluster/pending_tasks

列出还在等 master 处理的 cluster-state 更新任务,mapping 更新、建索引、改设置。pending 队列很长说明 master 成了瓶颈(常因 shard 太多或 mapping 频繁变动)。

例子
GET /_cluster/pending_tasks
复制与快照 (14)
number_of_replicas

每主 shard 的副本数。生产最低 1(挂一台不丢数据), 2+ 提可用 / 读吞吐。只有一次性测试索引才设 0。

常见坑: replicas=0 单点故障就丢数据。很多"测试"索引悄悄变成"半生产",所有 index template 默认 replicas=1。

例子
PUT /products/_settings {"index":{"number_of_replicas":2}}
PUT /_index_template/default {"index_patterns":["*"],"template":{"settings":{"number_of_replicas":1}}}
PUT /_snapshot/<repo>

注册快照仓库,S3、GCS、Azure、NFS、HDFS、共享文件系统。能拍 / 恢复快照前必须先注册。ES 唯一内建的灾备路径。

例子
PUT /_snapshot/s3_backups {"type":"s3","settings":{"bucket":"my-es-backups","region":"us-east-1"}}
PUT /_snapshot/<repo>/<snap>

拍快照。增量,同仓库里只上传相对上次快照新增的 segment。生产集群可在线跑。

例子
PUT /_snapshot/s3_backups/2026-05-26?wait_for_completion=false {"indices":"products,logs-*","include_global_state":false}
POST /_snapshot/<repo>/<snap>/_restore

恢复快照,可在恢复时改名,先和当前数据对比,再切 alias。"完蛋了"回滚的标准做法。

常见坑: 恢复时拒绝覆盖"已存在的开启状态"索引。要么先 close 要么用 rename_pattern + rename_replacement 恢复到旁路名字。

例子
POST /_snapshot/s3_backups/2026-05-26/_restore {"indices":"products","rename_pattern":"(.+)","rename_replacement":"restored_$1"}
GET /_snapshot/<repo>/_all

列仓库里全部快照及状态、起 / 止时间、shard 数、失败数。任何备份审计 / 脚本里"找最近一个好快照"都靠它。

例子
GET /_snapshot/s3_backups/_all
SLM (snapshot lifecycle management)

内建周期性快照 + 保留期调度器。比自己写 cron 强,保留期按策略来(保 30 天 daily + 12 个 monthly 等),ES 自己强制。

例子
PUT /_slm/policy/daily {"schedule":"0 30 1 * * ?","name":"<daily-{now/d}>","repository":"s3_backups","config":{"indices":["*"]},"retention":{"expire_after":"30d","min_count":7,"max_count":50}}
cross-cluster replication (CCR)

把索引从 leader 集群持续复制到多个 follower 集群,跨区灾备、读扩展、地理就近。需 Platinum / Enterprise 许可证。

例子
PUT /products-replica/_ccr/follow?wait_for_active_shards=1 {"remote_cluster":"leader_cluster","leader_index":"products"}
ILM (index lifecycle management)

按年龄 / 体积 / 文档数自动让索引走 hot → warm → cold → frozen → delete 各阶段。配 rollover 做任意体量的时序日志。

例子
PUT /_ilm/policy/logs_policy {"policy":{"phases":{"hot":{"actions":{"rollover":{"max_age":"7d","max_size":"50gb"}}},"warm":{"min_age":"30d","actions":{"forcemerge":{"max_num_segments":1}}},"delete":{"min_age":"90d","actions":{"delete":{}}}}}}
DELETE /_snapshot/<repo>/<snap>

删一个快照。因为快照是增量的,ES 只释放不被仓库里其它快照引用的 segment,删旧快照实际腾出的空间可能远小于它的名义体积。

例子
DELETE /_snapshot/s3_backups/2026-04-01
GET /_snapshot/<repo>/<snap>/_status

正在跑或已完成快照的逐 shard 实时进度,已完成字节 vs 总字节、文件数、状态。盯一个大快照用它,而不是只给粗状态的 _all。

例子
GET /_snapshot/s3_backups/2026-05-26/_status
POST /_snapshot/<repo>/_verify · _cleanup

verify 检查每个节点能否读写仓库(在备份悄悄失败前抓出凭证或网络问题)。cleanup 清掉被中断的快照删除留在仓库里的孤儿数据。

例子
POST /_snapshot/s3_backups/_verify
POST /_snapshot/s3_backups/_cleanup
searchable snapshots

searchable snapshot,把快照直接挂成可搜索的索引而不用完整恢复,数据留在对象存储(S3),按需拉取。它支撑 ILM 的 cold/frozen tier,大幅降低很少查询的旧数据的存储成本。需企业许可证。

例子
POST /_snapshot/s3_backups/2026-01/_mount?wait_for_completion=true {"index":"logs-2026.01","renamed_index":"logs-2026.01-cold"}
wait_for_active_shards (write consistency)

wait_for_active_shards,写入时要求目标 shard 有 N 个副本处于 active 才接受。默认 1(只要主),当"单副本确认"对你的数据不够可靠时设 "all" 或一个 quorum。

常见坑: 设得比可用副本数还高,写入会阻塞到超时再失败,replicas=2 的索引别轻易设 "all",除非你能保证所有副本都在线。

例子
PUT /orders/_doc/1?wait_for_active_shards=2 {"total":99}
allocation awareness (rack / zone)

告诉 ES 每个节点在哪个机架 / 可用区,它会把主 + 副本分散到不同区,这样一个区挂掉绝不会同时带走一个 shard 的两份。多 AZ 生产集群必配。

例子
# elasticsearch.yml
node.attr.zone: zone-a
cluster.routing.allocation.awareness.attributes: zone
PUT /_cluster/settings {"persistent":{"cluster.routing.allocation.awareness.attributes":"zone"}}
常见坑 (16)
Heap > 32GB hits compressed-oops cliff

JVM 压缩对象指针在约 32GB heap 以上失效,指针变 2 倍、GC 压力骤增、吞吐下降。哪怕 256GB 机器,heap 也卡在 30-31GB,要多就一机多节点。

例子
# jvm.options (good)
-Xms30g
-Xmx30g
# jvm.options (bad)
-Xms64g
-Xmx64g  # crossed the cliff
Mapping explosion from dynamic:true

默认 dynamic:true 遇到用户 JSON,每个独特 key 自动建字段。坏客户端 = 上百万字段、GB 级 cluster state、full GC、集群无响应。生产 ES 挂掉头号原因。

常见坑: 用户输入一律 dynamic:strict。用 index.mapping.total_fields.limit(默认 1000)封顶,接近上限就拒写。每周 GET /_cluster/state/metadata 审一遍字段数。

例子
PUT /events_strict {"mappings":{"dynamic":"strict","properties":{"@timestamp":{"type":"date"},"event":{"type":"keyword"}}}}
Deep paging with from + size

每次 from + size 都要让每个 shard 返回 from+size 条再合并。from=10000 + size=10 + 5 shard = 每 shard 50050 条 = 爆 heap。默认上限 index.max_result_window=10000。

常见坑: 永远不要靠调大 max_result_window 来"修"深翻页,改 search_after 或 point_in_time + search_after,无论翻到第几页都 O(size)。

例子
# wrong — will blow up
GET /products/_search {"from":100000,"size":10}
# right — sort + search_after
GET /products/_search {"size":10,"sort":[{"_id":"asc"}],"search_after":["abc123"]}
Refresh interval at default 1s

默认 1s refresh 适合低写场景,高写 / 日志场景会狂吃 CPU,每次 refresh 都生成新 segment,后面要合并。日志索引把 refresh_interval 调到 30s。

例子
PUT /logs-2026.05/_settings {"index":{"refresh_interval":"30s"}}
PUT /products/_settings {"index":{"refresh_interval":"-1"}}  # disable; manual _refresh only
Disk watermark blocks writes

磁盘 85% 满,ES 停止给该节点分新 shard。90% 主动迁。95%(flood_stage)把该节点上的所有索引锁成只读。赶紧腾盘或手动解只读。

常见坑: 解锁:PUT /<index>/_settings {"index.blocks.read_only_allow_delete":null},但必须先腾盘,否则下次 watermark 检查又锁。

例子
PUT /_cluster/settings {"persistent":{"cluster.routing.allocation.disk.watermark.low":"85%","cluster.routing.allocation.disk.watermark.high":"90%","cluster.routing.allocation.disk.watermark.flood_stage":"95%"}}
PUT /*/_settings {"index.blocks.read_only_allow_delete":null}
Searching wrong field type

text 字段用 term 查全空(text 入库小写 + 分词)。keyword 字段用 match 查不到非精确匹配(keyword 不分词)。写 query 前先 GET /<index>/_mapping 看清楚类型。

例子
# wrong — term on text
{"query":{"term":{"name":"Apple"}}}  # 0 hits
# right — term on keyword sub-field
{"query":{"term":{"name.keyword":"Apple"}}}
Bulk size too small / too big

bulk 请求甜区 5-15MB。更小 = 网络来回主导。更大 = HTTP 413 / OOM / 协调节点崩。算清楚 payload,定一个落在甜区的批量条数。

例子
# python elasticsearch helpers
from elasticsearch.helpers import bulk
bulk(client, actions, chunk_size=2000, max_chunk_bytes=10*1024*1024)
Split brain (pre-7.x) / quorum loss (7.x+)

7.x 之前:discovery.zen.minimum_master_nodes 配错会分裂出两个 "master"。7.x+ 用投票配置(自管)更安全,但仍然需要 ≥ 3 个 master-eligible 节点保 quorum。

常见坑: 两个 master-eligible 节点是最差的配置,任意一个挂就丢 quorum。生产要么 1(仅测试), 3, 5, 7,奇数且 ≥ 3。

例子
# 3 master-eligible nodes, no voting-only nodes
node.roles: [ master, data, ingest ]
fielddata: true on text bloats heap

为了"让 text 可排序" 开 fielddata:true,会把每个 term + 每个 doc-id 装进 heap。一招让节点 OOM。正路是加个 keyword 子字段,聚合 / 排序走它。

例子
# wrong
{"properties":{"name":{"type":"text","fielddata":true}}}
# right
{"properties":{"name":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}}}}
Too many shards per node

不管 shard 多小,它都背着固定的 heap 和 cluster-state 开销。成千上万个小 shard 会撑大 master、拖慢恢复、耗尽 heap。经验法则:shard 控制在 10-50GB,每 GB heap 远低于约 20 个 shard。

常见坑: 超分通常来自"每客户每天一个索引"加默认 shard 数。改用 data stream + 按体积 rollover 来合并,旧只读索引用 _shrink。

例子
GET /_cat/allocation?v&h=node,shards,disk.indices
# consolidate: rollover by 50gb instead of 1 index/day
POST /logs/_rollover {"conditions":{"max_size":"50gb"}}
Aggregating on a high-cardinality keyword

terms 聚合跑在上百万个不同 keyword 值上,会在 heap 里建一个巨大的桶表,而且默认 size 下还只是近似。它是仅次于"text 开 fielddata"的第二大 OOM 来源。

常见坑: 要"列出所有唯一值"用 composite 聚合(分页、内存有界),不要用 size:1000000 的 terms 聚合。只要 distinct COUNT,改用 cardinality(HLL)。

例子
# wrong — builds a giant bucket map
{"aggs":{"u":{"terms":{"field":"user_id","size":1000000}}}}
# right — paginate with composite
{"aggs":{"u":{"composite":{"size":1000,"sources":[{"uid":{"terms":{"field":"user_id"}}}]}}}}
Wildcard / regexp / leading-wildcard on big fields

wildcard:"*foo*" 和不锚定的 regexp 用不上有序倒排索引,会扫该字段的每个 term。在高基数字段上,这会把 5ms 的查询变成几秒、给集群施压的全扫。

常见坑: "contains"搜索用 wildcard 字段类型(7.9+)或入库时的 ngram 分析器;"starts with"用 prefix 或 completion suggester。真正的 wildcard 查询只留给小的、低基数字段。

例子
# slow on large fields
{"query":{"wildcard":{"msg.keyword":"*timeout*"}}}
# better — index with ngram and use match
Scripts in hot query paths

script_score、script query、runtime field 里的 Painless 对每条命中、每次查询都现算,灵活但规模上 CPU 很重。一个在上百万命中里访问 doc-values 的脚本会吃掉你的延迟。

常见坑: 只要输入在写入时就已知,就在入库时把值预算进一个真实字段。脚本只留给真正动态、按请求变化的逻辑,而且先把候选集过滤小。

例子
# expensive
{"query":{"script_score":{"query":{"match_all":{}},"script":{"source":"Math.log(2 + doc['votes'].value)"}}}}
# cheaper — precompute log_votes at index time, sort on it
now in a filter kills the request cache

range filter 用裸 now,值每毫秒都变,shard 请求缓存永远命不中。改成 now/d(或 now/h)向下取整,值在当天 / 当小时内稳定,缓存才生效。

常见坑: 可缓存 filter 里的 date math 一律取整:用 now-7d/d 而不是 now-7d。差别就是时间窗看板的整个 shard 请求缓存能用还是作废。

例子
# cache-busting
{"filter":{"range":{"@timestamp":{"gte":"now-7d"}}}}
# cache-friendly
{"filter":{"range":{"@timestamp":{"gte":"now-7d/d"}}}}
Index-time vs search-time analyzer mismatch

字段用一种分析器入库,你却按另一种去查,token 对不上,match 返回空。常发生在"改了 mapping 里的分析器但没 reindex 老数据"之后。

常见坑: 改分析器只影响"改之后"入库的文档。对同一段文本用两种分析器各跑一次 POST /<index>/_analyze 确认 token 一致,不一致就 reindex 老数据。

例子
POST /products/_analyze {"field":"name","text":"Wireless"}
Returning huge _source per hit

为 1000 条命中每条都拉 50KB 的 _source,会传 50MB 你可能根本不要的数据。只渲染标题和价格就只取它们,大结果集上的网络和 JSON 解析开销是实打实的。

常见坑: 用 _source includes/excludes,或 fields + _source:false,只返回 UI 要展示的。纯聚合请求设 size:0,完全不返回命中。

例子
{"size":20,"_source":["title","price"],"query":{"match_all":{}}}
{"size":0,"aggs":{"by_cat":{"terms":{"field":"category"}}}}

这个工具能做什么

可搜索的 Elasticsearch 速查表,覆盖后端、SRE、搜索平台 同学日常真在 Kibana Dev Tools 里敲的 80+ 条命令。九大 分类:索引管理(PUT / DELETE、alias 做零停机 reindex、 composable index template、时序日志的 _rollover、 _reindex 配 slices=auto、_forcemerge、refresh / flush)、 文档(_doc 配 op_type=create、_update 与 _update_by_query、_bulk 甜区、_mget、_count)、mapping (text 配 keyword multi-field、date、nested 与扁平 object 的取舍、geo_point、dynamic:strict 防 mapping 爆炸)、Query DSL(match、match_phrase 配 slop、 multi_match 的 best_fields / cross_fields、term 与 terms、range 配 date math、bool 的 must/should/must_not/filter、wildcard / regexp / prefix / fuzzy、exists、nested 配 inner_hits、geo_distance、 function_score 配 gauss 衰减、highlight、深翻页用 search_after、scroll 与 point_in_time)、聚合(terms + composite 全枚举、avg / sum / stats、cardinality HyperLogLog++、date_histogram 带 time_zone、histogram、 range、percentiles、子聚合、filter agg、每桶 top_hits、 significant_terms)、分析器(standard、语言分析器、自 定义 char_filter + tokenizer + token_filter、自动补全用 edge_ngram、ngram、synonym、stop、asciifolding、中日韩 插件 ik / kuromoji / nori)、集群运维(_cluster/health、 allocation explain、常用 _cat 系列加正确字段、_tasks 配 _cancel)、复制与灾备(number_of_replicas 默认值、 snapshot 仓库、_snapshot 创建 / 恢复带 rename、SLM、 CCR、ILM hot/warm/cold/frozen/delete),以及生产环境的 坑(heap > 32GB 压缩指针失效、dynamic:true 引发 mapping 爆炸、from + size 深翻页、高写场景默认 1s refresh、磁盘 95% flood_stage 锁只读、错字段类型查询、bulk 大小甜区、 split-brain、fielddata:true 让节点 OOM)。每条都附中英 说明、1-3 条可直接粘到 Kibana Dev Tools 跑的真实 JSON / REST 例子、一行"常见坑"。搜索框跨命令 / 说明 / 例子 / 坑一起搜,分类胶囊缩范围。完全在浏览器里跑,不连任何 Elasticsearch,不上传。配合 Redis、PostgreSQL、MongoDB、 Docker 速查覆盖整条数据栈。

工具细节

输入
文本
页面会根据工具类型展示文本框、数值控件、文件选择或结构化输入。
输出
即时结果 + 复制 + 预览
结果区优先给出可操作结果,支持项会显示复制、下载或可视化预览。
隐私
浏览器本地处理
主工具逻辑未发现外部 API 调用,输入通常留在当前标签页内处理。
保存 / 分享
免账号使用
打开页面即可使用;刷新后是否保留结果取决于具体工具。
性能预算
首屏 JS ≤ 32 KB
没有声明 WASM 依赖,适合快速打开和移动端使用。
适用场景
开发运维 · 程序员
分类和职业标签用于推荐相关工具、组织内链,并帮助用户快速判断是否适合当前任务。

怎么用

  1. 1. 输入

    把内容粘贴或拖入工具面板。

  2. 2. 处理

    点击按钮,在浏览器内本地处理,文件不上传。

  3. 3. 复制 / 下载

    一键复制结果或下载到本地。

Elasticsearch 速查表 适合怎么用

适合穿插在写代码、查问题、做 Review、上线前的小任务里。

适合开发场景

  • 格式化、校验、压缩或检查和代码相关的文本。
  • 把片段整理好再放进文档、工单、提交或交接材料。
  • 不切换工具,快速检查一个小 payload。

开发检查项

  • 压缩、混淆这类不可逆处理,先对副本操作。
  • 除非确认工具本地处理,不要粘贴密钥和敏感片段。
  • 转换后的代码上线前,仍要跑自己的测试或 lint。

下一步可以接着做

这些入口会把当前任务接到更完整的工具链里。

  1. 1 JSON 格式化与校验 浏览器内即时格式化、校验、压缩 JSON,数据不离开本地。 打开
  2. 2 Redis 速查表 Redis 速查表,80+ 命令覆盖字符串/哈希/列表/集合/有序集合/发布订阅/Streams/脚本,带真实例子和坑。 打开
  3. 3 PostgreSQL 速查表 PostgreSQL 速查表,80+ 命令和函数,psql、JSONB、CTE、窗口函数、索引、分区、高级扩展。 打开

真实使用场景

  • 生产 4000 万文档商品索引上 term 过滤零命中

    预发好用的 "status:active" 过滤到了生产一条都查不到,因为 这个字段被映射成 text 不是 keyword,入库时小写加分词了。你 筛出 term 查询那几条加"term 查不到"那条坑,确认正确写法是 term 走 status.keyword,再在 Dev Tools 里 POST /_analyze 看值到底被分成了什么。十分钟定位,不用整个下午瞎猜。

  • 6 分片 80GB 索引零停机切到新 mapping

    市场部要 name 能全文搜,但它建成了 keyword,类型不能原地 改。你拉出零停机 reindex 那条,建 products_v2,用 slices=auto 加 wait_for_completion=false 跑 _reindex,轮询 _tasks,最后 一个 payload 里 remove 加 add 原子切 alias。80GB 切换全程 应用还在通过 products alias 正常读写,业务无感。

  • 12 节点日志集群一个节点到 96% 磁盘后变红

    那个节点上每个索引都被锁只读,写入直接卡住。你抓出磁盘 watermark flood_stage 那条,确认 95% 触发只读锁,用集群运维 区的 _cat/allocation 和 allocation/explain 定位热节点,腾盘, 再清掉 read_only_allow_delete 阻塞。速查直接给你那条 PUT _settings,凌晨两点不用现翻 YAML 配置。

  • 做每个类别 top10 卖家的看板面板

    你要先按类别分组,再出每组销量最高的卖家带各自营收,还得在 3000 万订单上做到亚秒级。你筛到聚合区,复制 terms 套 top_hits 再加一个 sum 子聚合的写法,粘进 Dev Tools,照那条 terms 聚合 精度的坑调 size 和 shard_size。面板直接打在线上 ES,不用每晚 导一份到单独的分析库。

常见踩坑

  • 在 text 字段上跑 term 结果零命中。字符串建成 text 加 keyword 子字段,term 走 field.keyword,要全文就用 match。

  • 用 from + size 翻过 10000 深翻页,每个 shard 都返回 from+size 条直接爆 heap。改用带 sort 的 search_after,或用 point_in_time 拿稳定游标。

  • 高写日志场景把 refresh_interval 留在默认 1s,大半 CPU 都耗在做小 segment。调到 30s,只在必须读到刚写的数据时再手动 _refresh。

隐私说明

这份速查是单个静态页。搜索完全在你浏览器里对内存中的条目数组 做过滤,所以你输入的内容不发去任何地方,不连任何 Elasticsearch, 索引名、查询、字段值都不出这个标签页。URL 里也不写任何内容, 分享链接不带查询文本。堡垒机后面、气隙网络、走代理的内网都能 放心用,特别适合装不了 Kibana 的环境。

常见问题

类似工具组合

做你这行的人, 还会一起用这些。

Made by Toolora · 100% client-side · Updated 2026-06-13