关于 elasticsearch-esql
此技能通过 elastic CLI 引导 Elasticsearch 用户发现索引结构、编写 ES|QL 查询并执行。它会根据部署版本选择功能,并要求先检查字段名称,避免猜测。
主要功能
- 01验证连接并识别集群版本
- 02发现索引和字段映射
- 03按查询意图选择功能
- 04生成简洁的 ES|QL 查询
- 05通过 elastic CLI 执行查询
适用场景
- 01探索 Elasticsearch 数据字段
- 02汇总日志或指标
- 03使用 ES|QL 搜索文档
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ elastic/ agent-skills --skill elasticsearch-esql安装后在 Claude Code 中输入/elasticsearch-esql确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/dsl-to-esql-migration.mdesql-reference.mdesql-search-strategy.mdesql-search.mdesql-version-history.mdgeneration-tips.mdpromql-command.mdquery-approximation.mdquery-patterns.mdtime-series-queries.md详细介绍
Elasticsearch ES|QL
对 Elasticsearch 执行 ES|QL 查询:发现架构,为任务选择合适的 ES|QL 功能,生成最简单且正确的查询,然后运行。
环境配置
此技能通过 elastic CLI 执行 Elasticsearch 操作。如果未安装
elastic CLI,请告知用户需要安装它的原因。不要猜测凭据、直接调用 HTTP API,也不要尝试其他变通方法。
此技能以 HTTP 简写形式引用操作(例如,GET /、GET /_cat/indices、GET /{index}/_mapping、
GET /{index}/_settings/index.mode、POST /_query)。本文档末尾的 操作 表格将每种简写映射到对应的 elastic CLI 命令——始终使用 CLI,而不要直接调用 HTTP API。
什么是 ES|QL?
ES|QL(Elasticsearch Query Language)是 Elasticsearch 的管道式查询语言。它不同于:
- Elasticsearch Query DSL(基于 JSON)
- SQL
- EQL(Event Query Language)
ES|QL 使用管道符(|)串联命令:
FROM index | WHERE condition | STATS aggregation BY field | SORT field | LIMIT n
前提条件: ES|QL 要求查询的索引启用
_source。禁用_source的索引(例如,"_source": { "enabled": false })会导致 ES|QL 查询失败。版本兼容性: ES|QL 于 8.11 引入(技术预览版),并于 8.14 正式发布。
LOOKUP JOIN(8.18+)、MATCH(8.17+)和INLINE STATS(9.2+)等功能是在后续版本中添加的。在 8.18 之前的集群上,请使用ENRICH作为LOOKUP JOIN的替代方案(参见生成提示)。在 9.2 之前,INLINE STATS和计数器字段RATE()没有替代方案。请查看 references/esql-version-history.md,了解各版本的功能可用情况。集群检测: 调用
GET /以确定集群类型和版本:
build_flavor: "serverless"— Elastic Cloud Serverless。version.number会跟踪正在积极开发的堆栈版本线(即从 main 分支衍生的下一个次要版本),因此只进行语义化版本比较的客户端可能会将 Serverless 视为“最新版本”。不要使用version.number判断功能是否可用:如果build_flavor为"serverless",则假定所有正式发布和预览版 ES|QL 功能均可用。build_flavor: "default"— Stack(自管理或由 Cloud 托管)。根据version.number判断功能是否可用。- Snapshot 构建的
version.number类似9.4.0-SNAPSHOT。去掉-SNAPSHOT后缀,并使用主次版本号进行版本检查。Snapshot 构建包含该版本的所有功能,以及可能尚未发布的开发中功能——如果查询因未知函数或命令而失败,可能只是该功能尚未合入。Elastic 员工通常使用 Snapshot 构建进行测试。
流程
-
验证连接并检测部署类型。 首先调用
GET /。这会确认连接,并检测部署是 Serverless 项目(所有功能均可用)还是带版本号的集群(功能取决于版本)。build_flavor字段是权威依据——如果其值为"serverless",请忽略返回的版本号,并自由使用所有 ES|QL 功能。如果调用失败,请停止操作,并指引用户查看 CLI 配置说明,不要猜测端点或凭据。 -
发现架构(必需——绝不要猜测索引或字段名称)。 使用
GET /_cat/indices列出候选索引(传入模式以缩小范围),然后使用GET /{index}/_mapping获取所选索引的字段类型。 生成查询前,请务必先发现架构。不同部署中的索引名称和字段名称各不相同,无法可靠地猜测。即使是听起来很常见的数据(例如“日志”),也可能位于名为logs-test、logs-app-*或application_logs的索引中。字段名称可能使用 ECS 点分表示法(source.ip、service.name),也可能使用扁平的自定义名称——只有检查后才能确定。**优先保持简单:**除非用户明确要求跨多个来源查询数据,否则只查询一个索引。除非用户特别要求,否则不要使用
COALESCE合并架构不同的索引——针对问题选择单个最相关的索引。如果多个索引包含相似数据,优先选择对当前任务而言架构最完整的索引。**检测时间序列索引。**使用
GET /{index}/_settings/index.mode检查索引模式。如果是time_series,请使用TS <data-stream>(而不是FROM)、TBUCKET(interval)(而不是DATE_TRUNC),并用SUM(RATE(...))包装计数器字段。编写任何时间序列查询前,请阅读 生成技巧 中完整的 TS 部分。对于 9.4+ 上的 TSDS 索引,优先使用语言内的发现命令METRICS_INFO和TS_INFO(均为 GA),而不是检查映射——这些命令会直接列出指标目录及各时间序列的维度标签,并通过POST /_query作为 ES|QL 查询运行。将METRICS_INFO视为metric_type(counter/gauge/histogram)和field_type(分布指标对应的histogram、tdigest、exponential_histogram)的权威来源。两者都必须放在TS之后,并且必须位于STATS/SORT/LIMIT之前。请参阅 时间序列查询:TS metrics-tsds | METRICS_INFO | SORT metric_name TS metrics-tsds | TS_INFO | KEEP metric_name, dimensions | SORT metric_name -
**为任务选择合适的 ES|QL 功能。**编写查询前,将用户意图与最合适的 ES|QL 功能相匹配。优先使用一个高级查询,而不是多个基础查询。
- “查找模式”“分类”“对相似消息分组” →
CATEGORIZE(field) - “峰值”“低谷”“异常”“X 何时变化” →
CHANGE_POINT value ON key - “随时间变化的趋势”“时间序列” →
STATS ... BY BUCKET(@timestamp, interval);对于 TSDB,则使用TS - “PromQL”“Prometheus 查询/仪表板/告警”、
sum by (instance) (...)、{cluster="prod"}这类标签匹配器 →PROMQL源命令(9.4+ 预览版);请参阅 PROMQL 命令。对于原生 ES|QL 表达方式,优先使用TS。 - “搜索”“查找匹配的文档” →
MATCH(默认)、QSTR(高级布尔查询)、KQL(Kibana 迁移)。对于内容/文档相关性搜索,请遵循 ES|QL 搜索策略 - “计数”“平均值”“细分” → 使用聚合函数的
STATS - “近似值”“估算”“粗略数字”“针对海量数据的快速/低成本统计” → 在
STATS查询前使用SET approximation=true;(在 9.5+/Serverless 中为 GA,在 9.4 中为预览版);请参阅 查询近似
- “查找模式”“分类”“对相似消息分组” →
-
生成查询前先阅读参考资料:
- 生成提示 - 关键模式(TS/TBUCKET/RATE、按聚合设置 WHERE、LOOKUP JOIN、 CIDR_MATCH)、常见模板和歧义处理
- 时间序列查询 - 执行任何 TS 查询前务必阅读:内外层聚合模型、TBUCKET 语法、RATE 限制、直方图指标
- PROMQL 命令 — 执行任何 PROMQL 查询前务必阅读:选项、输出架构、
限制,以及
PROMQL与TS的决策矩阵(9.4+ 预览版) - ES|QL 完整参考 - 所有命令和函数的完整语法
- ES|QL 搜索策略 — 用于内容/文档相关性搜索(检索 → 融合 → 重排)
- ES|QL 搜索参考 — 全文搜索函数语法(MATCH、QSTR、KQL、 评分)
- 查询近似 — 使用
SET approximation前务必阅读:输出 列、采样/置信度调优、不支持的函数和模式(9.5+/Serverless 正式发布,9.4 预览版)
-
按照 ES|QL 语法生成查询。优先使用能够回答问题的最简单查询——除非用户要求,否则不要添加 额外索引、字段或转换。
KEEP中只包含能直接回答问题的字段。不要添加用户未指定的额外筛选条件(例如,用户只说了“错误”时,不要添加OR level == "ERROR")。- 以
FROM index-pattern开始(时间序列索引使用TS index-pattern) - 使用
WHERE进行筛选(9.3+ 的时间范围使用TRANGE) - 使用
EVAL计算字段 - 使用
STATS ... BY进行聚合 - 对于时间序列指标:计数器使用
TS和SUM(RATE(...)),仪表盘指标使用AVG(...),直方图指标使用标准聚合函数 (SUM、AVG、PERCENTILE等——不使用*_OVER_TIME),按时间分桶使用TBUCKET(interval)——参见 生成提示中的 TS 部分和 直方图指标 - 检测突增、骤降或异常时,使用时间分桶聚合后的
CHANGE_POINT - 根据需要添加
SORT和LIMIT
- 以
-
执行查询,使用
POST /_query。请求表格(TSV)输出,以获得简洁、无装饰的结果,便于阅读和后续处理。
ES|QL 快速参考
版本可用性: 为便于阅读,本节省略了版本注释。请查看 ES|QL 版本历史,了解各功能适用的 Elasticsearch 版本。
基本结构
FROM index-pattern
| WHERE condition
| EVAL new_field = expression
| STATS aggregation BY grouping
| SORT field DESC
| LIMIT n
常见模式
筛选并限制结果数量:
FROM logs-*
| WHERE @timestamp > NOW() - 24 hours AND level == "error"
| SORT @timestamp DESC
| LIMIT 100
按时间聚合: 对于时间序列(TSDS)索引,优先使用带有 TRANGE 和 TBUCKET 的 TS,而不是 FROM +
DATE_TRUNC(参见下方的时间序列部分)。
TS metrics-*
| WHERE TRANGE(7 days)
| STATS avg_cpu = AVG(cpu.percent) BY bucket = TBUCKET(1 hour)
| SORT bucket DESC
统计数量前 N 项:
FROM web-logs
| STATS count = COUNT(*) BY response.status_code
| SORT count DESC
| LIMIT 10
文本搜索(8.17+): 全文搜索默认使用 MATCH,而不是 LIKE/RLIKE——它的速度显著更快,并支持相关性评分。单独对 text 字段使用 MATCH 通常就足够了——除非用户明确要求筛选,否则不要在 MATCH 旁添加多余的关键词相等筛选(例如 category == "X")。只有在需要高级布尔逻辑、通配符或在单个表达式中搜索多个字段时,才使用 QSTR。MATCH 的第一个参数必须是一个实际字段名——不能是列出多个字段的字符串(例如 "title,content"),也不能是多个字段参数;请用 MATCH(a, "q") OR MATCH(b, "q") 组合多个字段。KQL 从 8.18/9.0+ 开始可用。对于内容/文档搜索场景,请遵循 ES|QL 搜索策略。完整函数指南请参见
ES|QL 搜索参考。
FROM documents METADATA _score
| WHERE MATCH(content, "search terms")
| SORT _score DESC
| LIMIT 20
字符串提取: 对于基于分隔符的结构化模式,请使用 DISSECT(首选,可生成命名字段);对于基于正则表达式的提取,请使用
GROK。对于简单情况,使用 SUBSTRING(s, start, len) 按固定位置提取,使用 SPLIT(s, delim) 拆分为多值,使用 LOCATE(substr, s) 查找字符位置。SPLIT 会返回多值;请使用 MV_FIRST、MV_LAST 或 MV_SLICE 选取元素。INSTR 和 STRPOS 不存在,请改用
LOCATE。REGEXP_EXTRACT 不存在,请改用 GROK。
// Extract domain from email using DISSECT (preferred — produces named fields)
FROM customers
| DISSECT email "%{local}@%{domain}"
| STATS count = COUNT(*) BY domain
// Alternative: extract domain from email using SPLIT
FROM customers
| EVAL domain = MV_LAST(SPLIT(email, "@"))
| STATS count = COUNT(*) BY domain
// Parse HTTP log lines
FROM logs-*
| DISSECT message "%{method} %{path} %{status_text}"
| KEEP @timestamp, method, path, status_text
日志分类(Platinum 许可证): 使用 CATEGORIZE 自动将日志消息聚类为模式组。在探索非结构化文本或查找其中的模式时,优先使用它,而不是运行多个 STATS ... BY field 查询。
FROM logs-*
| WHERE @timestamp > NOW() - 24 hours
| STATS count = COUNT(*) BY category = CATEGORIZE(message)
| SORT count DESC
| LIMIT 20
变点检测(Platinum 许可证): 使用 CHANGE_POINT 检测指标序列中的峰值、低谷和趋势变化。优先使用它,而不是手动检查按时间分桶的计数。
FROM logs-*
| STATS c = COUNT(*) BY t = BUCKET(@timestamp, 30 seconds)
| SORT t
| CHANGE_POINT c ON t
| WHERE type IS NOT NULL
时间序列指标: 使用 TS 时,可用 TRANGE 进行时间过滤(9.3+),也可以完全省略;不要在 TBUCKET 旁添加冗余的 WHERE @timestamp > NOW() - ...。TBUCKET 的时长定义了聚合窗口。
// Counter metric: SUM(RATE(...)) with TBUCKET(duration)
TS metrics-tsds
| WHERE TRANGE(1 hour)
| STATS SUM(RATE(requests)) BY TBUCKET(1 hour), host
// Gauge metric: AVG(...) — no RATE needed
TS metrics-tsds
| STATS avg_cpu = AVG(cpu) BY service.name, bucket = TBUCKET(5 minutes)
| SORT bucket
// Histogram metric: standard aggregation (merge); cast for wildcard/mixed streams
TS metrics-*
| STATS total_gc = SUM(jvm.gc.duration::exponential_histogram) BY TBUCKET(1 hour), service.name
使用 PromQL 语法的时间序列(9.4+ 预览版): 当用户明确要求使用 PromQL、引用 Prometheus 语法(sum by (instance) (...)、{cluster="prod"} 这样的标签匹配器),或正在迁移 Prometheus 仪表板或告警时,请使用 PROMQL 源命令。PROMQL 命令接受标准 PromQL,并支持可选的 index、step、buckets、start、end 和 scrape_interval 选项;它会生成一张表,供 ES|QL 管道的其余部分处理。范围选择器为可选项;省略时,窗口为 max(step, scrape_interval)。其他情况下优先使用 TS(9.4 中已正式发布)。PROMQL 不支持分组修饰符、集合运算符(or/and/unless),也不支持 histogram_quantile、predict_linear 和 label_join 等函数;对于这些情况,请改用 TS。完整参考请见
PROMQL Command。
// Adaptive Kibana query — date picker drives time range and step
PROMQL index=metrics-* sum by (instance) (rate(http_requests_total))
// Named result, post-processed with ES|QL
PROMQL index=k8s step=1h bytes=(max by (cluster) (network.bytes_in))
| STATS max_bytes = MAX(bytes) BY cluster
| SORT cluster
使用 LOOKUP JOIN 丰富数据: 基本的 ON 子句会按名称匹配两个索引中的字段
(LOOKUP JOIN idx ON field_name)。如果源数据中的联接键名称不同,请先使用 RENAME 统一名称。9.2+ 技术预览版还支持表达式谓词(ON expr == expr);详情请见
ES|QL Complete Reference。执行 LOOKUP JOIN 后,可通过原始字段名称访问查找列;不要在字段名前加表名限定(例如,写 threat_level,而不是
threat_intel.threat_level)。排序提示: 如果问题要求返回前 N 个结果,请在 LOOKUP JOIN 之前执行 SORT 和 LIMIT,以降低数据丰富的成本。对于一般列表或完整数据丰富,请将 LOOKUP JOIN 放在 FROM/WHERE 之后。
// Field name mismatch — RENAME before joining
FROM support_tickets
| RENAME product AS product_name
| LOOKUP JOIN knowledge_base ON product_name
// Aggregate, limit, THEN enrich (top-N only)
FROM orders
| STATS total_spent = SUM(total) BY customer_id
| SORT total_spent DESC
| LIMIT 3
| LOOKUP JOIN customers_lookup ON customer_id
| KEEP name, customer_id, total_spent
// Multi-field join (9.2+)
FROM application_logs
| LOOKUP JOIN service_registry ON service_name, environment
| KEEP service_name, environment, owner_team
多值字段筛选: 使用 MV_CONTAINS 检查多值字段是否包含特定值。使用
MV_COUNT 统计值的数量。
// Filter by multivalue membership
FROM employees
| WHERE MV_CONTAINS(languages, "Python")
// Find entries matching multiple values
FROM employees
| WHERE MV_CONTAINS(languages, "Java") AND MV_CONTAINS(languages, "Python")
// Count multivalue entries
FROM employees
| EVAL num_languages = MV_COUNT(languages)
| SORT num_languages DESC
变点检测(备用示例): 当用户询问峰值、低谷或异常时使用。需要先按时间分桶聚合,再执行 SORT,然后执行 CHANGE_POINT。
FROM logs-*
| STATS error_count = COUNT(*) BY bucket = DATE_TRUNC(1 hour, @timestamp)
| SORT bucket
| CHANGE_POINT error_count ON bucket AS type, pvalue
近似 STATS(9.5+/Serverless 中已正式发布,9.4 中为预览版): 在 STATS 查询前添加 SET approximation=true;,即可在不要求精确值时,通过对大型数据集进行采样和外推来快速估算。每个估算量的结果都会添加 _approximation_confidence_interval(col) 和 _approximation_certified(col) 列;请报告这些范围,不要将估算值当作精确值呈现。COUNT_DISTINCT、MIN、MAX、FIRST、LAST、TOP(以及其他少数函数)不受支持,会回退到精确执行;对于这些函数,请使用 SAMPLE 命令。包含 2 个或更多 STATS 的管道,或使用 TS/PROMQL 源命令的管道,也会回退。请参阅
Query Approximation。
SET approximation=true;
FROM web_traffic
| WHERE @timestamp >= NOW() - 1 week
| STATS total_hits = COUNT(*), avg_load_time = AVG(page_load_ms) BY country_code
| SORT total_hits DESC
| LIMIT 5
完整参考
如需查看完整的 ES|QL 语法,包括所有命令、函数和运算符,请阅读:
- ES|QL 完整参考
- ES|QL 搜索参考 - 全文搜索:MATCH、QSTR、KQL、MATCH_PHRASE、评分、 语义搜索
- ES|QL 搜索策略 - 内容索引的相关性搜索策略:检索 → 融合 → 重排
- ES|QL 版本历史 - 各 Elasticsearch 版本的功能可用性
- 查询模式 - 将自然语言转换为 ES|QL
- 生成提示 - 查询生成最佳实践
- 时间序列查询 - TS 命令、时间序列聚合函数、TBUCKET
- PROMQL 命令 - 用于 TSDS 索引的 PromQL 源命令(9.4+ 预览版)
- 查询近似 - 通过采样/外推近似执行 STATS(9.5+/Serverless 正式发布,9.4 预览版)
- DSL 到 ES|QL 迁移 - 将 Query DSL 转换为 ES|QL
错误处理
查询执行失败时,请读取 Elasticsearch 返回的错误消息并修正查询。常见问题:
- 字段不存在 → 编写查询前,务必检查映射(
GET /{index}/_mapping)并列出索引(GET /_cat/indices)。 切勿猜测字段或索引名称——它们会因部署环境而异。 - 类型不匹配 → 使用类型转换函数(TO_STRING、TO_INTEGER 等)
- 语法错误 → 查看 ES|QL 参考以确认语法正确。字符串务必使用双引号,不要使用单引号。
- 无结果 → 检查时间范围和筛选条件
- 函数名称错误 → ES|QL 使用带下划线的名称:
STD_DEV()而非STDDEV(),MEDIAN_ABSOLUTE_DEVIATION()而非MAD()。字符串拼接请使用CONCAT(),不要使用+。使用CASE(cond, val, ...),而非CASE WHEN...THEN...END。 - 日期部分错误 →
DATE_EXTRACT使用 ES|QL 的部分名称:"hour_of_day"而非"hour","day_of_month"而非"day","month_of_year"而非"month"。日期运算请使用DATE_DIFF("day", start, end),不要使用减法。
示例
每个示例都遵循以下流程:先检查映射,再编写最简单且正确的查询。
“过去一小时内请求数最多的 10 个源 IP” — 按时间窗口筛选,然后聚合并排名:
FROM logs-*
| WHERE @timestamp > NOW() - 1 hour
| STATS requests = COUNT(*) BY source.ip
| SORT requests DESC
| LIMIT 10
“仅针对 5xx 响应的各服务平均响应时间” — 聚合前先筛选错误:
FROM traces-*
| WHERE http.response.status_code >= 500
| STATS avg_ms = AVG(duration_ms) BY service.name
| SORT avg_ms DESC
“过去一周每天的错误数” — 使用 DATE_TRUNC 按天分桶:
FROM logs-*
| WHERE log.level == "error" AND @timestamp > NOW() - 7 days
| STATS errors = COUNT(*) BY day = DATE_TRUNC(1 day, @timestamp)
| SORT day ASC
指南
- 查询前先检查。 编写查询前,先读取映射(
GET /{index}/_mapping)并列出索引(GET /_cat/indices)——切勿猜测字段或索引名称。 - 尽早筛选。 将
WHERE放在STATS之前,让聚合针对尽可能少的行运行。 - 务必限制结果。 探索性查询以
LIMIT结束。 - 正确使用引号。 字符串字面量使用双引号,切勿使用单引号。
- 遵守版本限制。 使用
LOOKUP JOIN或INLINE STATS等较新命令前,通过GET /(build_flavor、version.number)和 references/esql-version-history.md 确认功能是否可用。 - 遇到错误时修正,不要猜测。 阅读 Elasticsearch 错误信息,修复具体问题,然后重新运行。
Operations
| HTTP API (shorthand) | elastic CLI command |
|---|---|
GET / | elastic es info |
GET /_cat/indices | elastic es cat indices --index '<pattern>' |
GET /{index}/_mapping | elastic es indices get-mapping --index '<index>' |
GET /{index}/_settings/index.mode | elastic es indices get-settings --index '<index>' --name index.mode |
POST /_query | elastic es esql query --format tsv --query "<esql>" |