执行 ES|QL(Elasticsearch 查询语言)查询,当用户想要查询 Elasticsearch 数据、分析日志、聚合指标、探索数据,或根据 ES|QL 结果创建图表和仪表板时使用。
Elasticsearch ES|QL
对 Elasticsearch 执行 ES|QL 查询。
什么是 ES|QL?
ES|QL(Elasticsearch 查询语言)是一种用于 Elasticsearch 的管道查询语言。它不同于:
- Elasticsearch 查询 DSL(基于 JSON)
- SQL
- EQL(事件查询语言)
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 中正式发布(GA)。像
LOOKUP JOIN(8.18+)、MATCH(8.17+)和INLINE STATS(9.2+)等功能是在后续版本中添加的。在 8.18 之前的集群上,使用ENRICH作为LOOKUP JOIN的替代方案(参见生成技巧)。INLINE STATS和计数器字段的RATE()在 9.2 之前没有替代方案。请查看 references/esql-version-history.md 了解各版本的功能可用性。集群检测: 使用
GET /响应来确定集群类型和版本:
build_flavor: "serverless"— Elastic Cloud Serverless。version.number跟踪当前正在开发的主线版本(下一个次要版本),因此仅进行语义版本比较的客户端可能会将 Serverless 视为“最新”。不要使用version.number来判断功能:如果build_flavor是"serverless",则假定所有 GA 和预览版 ES|QL 功能都可用。build_flavor: "default"— 自管理或 Elastic Cloud Hosted。使用version.number判断功能可用性。- 快照构建的
version.number类似于9.4.0-SNAPSHOT。去掉-SNAPSHOT后缀,使用主版本.次版本进行版本检查。快照构建包含该版本的所有功能以及可能尚未发布的开发中功能——如果查询因未知函数/命令而失败,可能只是该功能尚未落地。Elastic 员工通常使用快照构建进行测试。
环境配置
有关完整的连接配置选项(Elastic Cloud、直接 URL、基本认证、本地开发),请参见 环境设置。
运行 node scripts/esql.js test 来验证连接。如果测试失败,请引导用户查看环境设置指南,然后停止。在成功连接测试之前,不要尝试进一步探索。
用法
获取索引信息(用于模式发现)
node scripts/esql.js indices # 列出所有索引
node scripts/esql.js indices "logs-*" # 列出匹配的索引
node scripts/esql.js schema "logs-2024.01.01" # 获取索引的字段映射
执行原始 ES|QL
node scripts/esql.js raw "FROM logs-* | STATS count = COUNT(*) BY host.name | SORT count DESC | LIMIT 5"
以 TSV 格式输出执行
node scripts/esql.js raw "FROM logs-* | STATS count = COUNT(*) BY component | SORT count DESC" --tsv
TSV 输出选项:
--tsv或-t:输出为制表符分隔的值(干净,无装饰)--no-header:省略标题行
测试连接
node scripts/esql.js test
指南
-
检测部署类型:始终先运行
node scripts/esql.js test。这会检测部署是 Serverless 项目(所有功能可用)还是版本化集群(功能取决于版本)。来自GET /的build_flavor字段是权威信号——如果它等于"serverless",则忽略报告的版本号,自由使用所有 ES|QL 功能。 -
发现模式(必需——切勿猜测索引或字段名称):
node scripts/esql.js indices "pattern*" node scripts/esql.js schema "index-name"在生成查询之前始终运行模式发现。索引名称和字段名称因部署而异,无法可靠猜测。即使是听起来很常见的数据(例如“logs”)也可能存在于名为
logs-test、logs-app-*或application_logs的索引中。字段名称可能使用 ECS 点分表示法(source.ip、service.name)或扁平的自定义名称——唯一的方法是检查。优先选择简单性: 除非用户明确要求跨多个源的数据,否则查询单个索引。不要使用
COALESCE组合不同模式的索引,除非特别要求——选择与问题最相关的单个索引。当多个索引包含相似数据时,优先选择模式最完整的索引。schema命令报告索引模式。如果显示Index mode: time_series,则输出包括数据流名称和可复制的 TS 语法——使用TS <data-stream>(而不是FROM)、TBUCKET(interval)(而不是DATE_TRUNC),并用SUM(RATE(...))包裹计数器字段。在编写任何时间序列查询之前,请阅读 生成技巧 中的完整 TS 部分。您也可以通过 Elasticsearch 索引设置 API 直接检查索引模式:curl -s "$ELASTICSEARCH_URL/<index-name>/_settings/index.mode" -H "Authorization: ApiKey $ELASTICSEARCH_API_KEY"对于 9.4+ 上的 TSDS 索引,优先使用语言内发现命令
METRICS_INFO和TS_INFO(均为 GA),而不是检查映射——它们直接枚举指标目录和每个时间序列的维度标签。两者都必须跟在TS之后,并且必须在STATS/SORT/LIMIT之前。请参见 时间序列查询。node scripts/esql.js raw "TS metrics-tsds | METRICS_INFO | SORT metric_name" --tsv node scripts/esql.js raw "TS metrics-tsds | TS_INFO | KEEP metric_name, dimensions | SORT metric_name" --tsv -
为任务选择正确的 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
- “查找模式”、“分类”、“对相似消息分组” →
-
在生成查询之前阅读参考资料:
- 生成技巧 - 关键模式(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、评分)
-
生成查询,遵循 ES|QL 语法。优先选择最简单的查询来回答问题——除非用户要求,否则不要添加额外的索引、字段或转换。只包含直接回答问题的字段在
KEEP中。不要添加超出用户指定的额外过滤条件(例如,当用户只说“errors”时,不要添加OR level == "ERROR")。- 以
FROM index-pattern(或时间序列索引的TS index-pattern)开头 - 添加
WHERE进行过滤(在 9.3+ 上使用TRANGE进行时间范围) - 使用
EVAL计算字段 - 使用
STATS ... BY进行聚合 - 对于时间序列指标:计数器使用
TS配合SUM(RATE(...)),仪表使用AVG(...),时间分桶使用TBUCKET(interval)——请参见 生成技巧 中的 TS 部分了解三个关键语法规则 - 对于检测尖峰、下降或异常,在时间分桶聚合后使用
CHANGE_POINT - 根据需要添加
SORT和LIMIT
- 以
-
使用 TSV 标志执行:
node scripts/esql.js raw "FROM index | STATS count = COUNT(*) BY field" --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
按时间聚合:
FROM metrics-*
| WHERE @timestamp > NOW() - 7 days
| STATS avg_cpu = AVG(cpu.percent) BY bucket = DATE_TRUNC(1 hour, @timestamp)
| 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 通常就足够了——不要添加冗余的关键字相等性过滤器(例如 category == "X")与 MATCH 一起使用,除非用户明确要求过滤。仅当需要高级布尔逻辑、通配符或单表达式多字段搜索时,才使用 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。
// 使用 DISSECT 从电子邮件中提取域名(首选——生成命名字段)
FROM customers
| DISSECT email "%{local}@%{domain}"
| STATS count = COUNT(*) BY domain
// 替代方案:使用 SPLIT 从电子邮件中提取域名
FROM customers
| EVAL domain = MV_LAST(SPLIT(email, "@"))
| STATS count = COUNT(*) BY domain
// 解析 HTTP 日志行
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 持续时间定义了聚合窗口。
// 计数器指标:SUM(RATE(...)) 配合 TBUCKET(duration)
TS metrics-tsds
| WHERE TRANGE(1 hour)
| STATS SUM(RATE(requests)) BY TBUCKET(1 hour), host
// 仪表指标:AVG(...) — 不需要 RATE
TS metrics-tsds
| STATS avg_cpu = AVG(cpu) BY service.name, bucket = TBUCKET(5 minutes)
| SORT bucket
使用 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 中 GA)。PROMQL 不支持组修饰符、集合运算符(or/and/unless)或像 histogram_quantile、predict_linear 和 label_join 这样的函数——对于这些情况,回退到 TS。请参见 PROMQL 命令 获取完整参考。
// 自适应 Kibana 查询——日期选择器驱动时间范围和步长
PROMQL index=metrics-* sum by (instance) (rate(http_requests_total))
// 命名结果,使用 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 完整参考 了解详情。在 LOOKUP JOIN 之后,查找列可通过其原始字段名称使用——不要使用表限定(例如,写 threat_level,而不是 threat_intel.threat_level)。排序提示: 当问题要求前 N 个结果时,在 LOOKUP JOIN 之前进行 SORT 和 LIMIT 以减少丰富成本。对于一般列表或完整丰富,将 LOOKUP JOIN 放在 FROM/WHERE 之后。
// 字段名称不匹配——在连接前使用 RENAME
FROM support_tickets
| RENAME product AS product_name
| LOOKUP JOIN knowledge_base ON product_name
// 聚合、限制、然后丰富(仅前 N 个)
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
// 多字段连接(9.2+)
FROM application_logs
| LOOKUP JOIN service_registry ON service_name, environment
| KEEP service_name, environment, owner_team
多值字段过滤: 使用 MV_CONTAINS 检查多值字段是否包含特定值。使用 MV_COUNT 计数。
// 按多值成员资格过滤
FROM employees
| WHERE MV_CONTAINS(languages, "Python")
// 查找匹配多个值的条目
FROM employees
| WHERE MV_CONTAINS(languages, "Java") AND MV_CONTAINS(languages, "Python")
// 计数多值条目
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
完整参考
有关完整的 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+ 预览)
- DSL 到 ES|QL 迁移 - 将查询 DSL 转换为 ES|QL
- 环境设置 - 连接配置选项
错误处理
当查询执行失败时,脚本返回:
- 生成的 ES|QL 查询
- Elasticsearch 的错误消息
- 常见问题的建议
常见问题:
- 字段不存在 → 在编写查询之前始终使用
get_schema和list_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)进行日期算术,而不是减法。
示例
# 模式发现
node scripts/esql.js test
node scripts/esql.js indices "logs-*"
node scripts/esql.js schema "logs-2024.01.01"
# 执行查询
node scripts/esql.js raw "FROM logs-* | STATS count = COUNT(*) BY host.name | LIMIT 10"
node scripts/esql.js raw "FROM metrics-* | STATS avg = AVG(cpu.percent) BY hour = DATE_TRUNC(1 hour, @timestamp)" --tsv






