mcpField
E
elasticsearch-esql

elasticsearch-esql

github.com/elastic数据与数据库6024.9k 次安装今天更新
代码仓库

关于 elasticsearch-esql

此技能通过 elastic CLI 引导 Elasticsearch 用户发现索引结构、编写 ES|QL 查询并执行。它会根据部署版本选择功能,并要求先检查字段名称,避免猜测。

主要功能

  1. 01验证连接并识别集群版本
  2. 02发现索引和字段映射
  3. 03按查询意图选择功能
  4. 04生成简洁的 ES|QL 查询
  5. 05通过 elastic CLI 执行查询

适用场景

  1. 01探索 Elasticsearch 数据字段
  2. 02汇总日志或指标
  3. 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.md
esql-reference.md
esql-search-strategy.md
esql-search.md
esql-version-history.md
generation-tips.md
promql-command.md
query-approximation.md
query-patterns.md
time-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 构建进行测试。

流程

  1. 验证连接并检测部署类型。 首先调用 GET /。这会确认连接,并检测部署是 Serverless 项目(所有功能均可用)还是带版本号的集群(功能取决于版本)。build_flavor 字段是权威依据——如果其值为 "serverless",请忽略返回的版本号,并自由使用所有 ES|QL 功能。如果调用失败,请停止操作,并指引用户查看 CLI 配置说明,不要猜测端点或凭据。

  2. 发现架构(必需——绝不要猜测索引或字段名称)。 使用 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
    
  3. **为任务选择合适的 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 中为预览版);请参阅 查询近似
  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 预览版)
  5. 按照 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
  6. 执行查询,使用 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 语法,包括所有命令、函数和运算符,请阅读:

错误处理

查询执行失败时,请读取 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/indiceselastic es cat indices --index '<pattern>'
GET /{index}/_mappingelastic es indices get-mapping --index '<index>'
GET /{index}/_settings/index.modeelastic es indices get-settings --index '<index>' --name index.mode
POST /_queryelastic es esql query --format tsv --query "<esql>"

评论

支持 Markdown