news 2026/5/1 16:52:25

用于 JavaScript 和 TypeScript 的 ES|QL 查询构建器:流式、类型安全的查询构建

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用于 JavaScript 和 TypeScript 的 ES|QL 查询构建器:流式、类型安全的查询构建

作者:来自 Elastic Margaret Gu

探索用于 JavaScript 和 TypeScript 的 ES|QL 查询构建器,并通过实际示例讲解如何构建 ES|QL 查询。

更多阅读:Elasticsearch:ES|QL 查询展示

开始动手使用 Elasticsearch:可以浏览 Elasticsearch Labs 仓库中的示例 notebooks,启动免费的云端试用,或在本地机器上直接体验 Elastic。


我们很高兴地宣布,Elasticsearch Query Language( ES|QL )查询构建器现已支持 JavaScript 和 TypeScript。它是一个流式(fluent)、类型安全的库,可以通过方法链式调用来构建 ES|QL 查询,并具备自动值转义以及完整的 IDE 支持;不再需要手动拼接原始字符串。

通过实际示例学习如何立即上手使用。

JavaScript 和 TypeScript 的 ES|QL 查询构建器

如果你曾在 JavaScript 中构建过 ES|QL 查询,你可能写过类似这样的代码:

const query = `FROM logs-* | WHERE status_code >= ${minStatus} AND host.name == ${hostname} AND @timestamp >= "${startDate}" | STATS error_count = COUNT(*) BY status_code | SORT error_count DESC | LIMIT 10`

它看起来没问题,直到 hostname 变成 O'Brien's server,然后整个查询因为解析错误直接崩掉。或者直到某个用户在搜索字段里传入"; DROP INDEX logs,你才意识到你一直在用字符串拼接来构建查询。

有更好的方式。JavaScript 和 TypeScript 的 ES|QL 查询构建器可以让你改成这样写查询:

import { ESQL, E, f } from '@elastic/elasticsearch-esql-dsl' const query = ESQL.from('logs-*') .where(E('status_code').gte(minStatus)) .where(E('host.name').eq(hostname)) .where(E('@timestamp').gte(startDate)) .stats({ error_count: f.count() }) .by('status_code') .sort(E('error_count').desc()) .limit(10)

值会被自动转义(escaped)。你可以在编辑器中获得自动补全(autocomplete),并且无需再“脑内解析”模板字符串,就能清晰理解查询实际在做什么。

ES|QL 查询构建器已经在 Elastic 的多种语言客户端中提供支持,包括 Python、Ruby 等。本篇文章重点介绍 JavaScript 和 TypeScript 版本,并通过一些可以直接上手的实际示例来讲解它的用法。

入门开始

安装该包:

npm install @elastic/elasticsearch-esql-dsl

这是一个最小查询示例:

import { ESQL, E } from '@elastic/elasticsearch-esql-dsl' const query = ESQL.from('employees') .where(E('still_hired').eq(true)) .sort(E('last_name').asc()) .limit(10) console.log(query.render())

渲染结果如下:

FROM employees | WHERE still_hired == true | SORT last_name ASC | LIMIT 10

要在 Elasticsearch 上执行它:

import { Client } from '@elastic/elasticsearch' const client = new Client({ node: 'http://localhost:9200' }) const response = await client.esql.query({ query: query.render() })

就是这样。没有字符串插值,也不需要手动转义。

一步一步构建真实查询

我们来看一个更贴近实际的场景:你正在构建一个用于分析 Web 服务器错误日志的仪表盘。我们先从简单开始,然后逐步增加功能。

步骤 1:过滤错误日志

import { ESQL, E } from '@elastic/elasticsearch-esql-dsl' const errors = ESQL.from('logs-*') .where(E('status_code').gte(400)) .limit(100)
FROM logs-* | WHERE status_code >= 400 | LIMIT 100

步骤 2:添加计算列

你的时间戳是以毫秒为单位,但你希望将响应时间转换为秒:

const errors = ESQL.from('logs-*') .where(E('status_code').gte(400)) .eval({ response_secs: E('response_time_ms').div(1000) }) .limit(100)
FROM logs-* | WHERE status_code >= 400 | EVAL response_secs = response_time_ms / 1000 | LIMIT 100

步骤 3:按状态码聚合错误

import { f } from '@elastic/elasticsearch-esql-dsl' const errorBreakdown = ESQL.from('logs-*') .where(E('status_code').gte(400)) .stats({ error_count: f.count(), avg_response: f.avg('response_time_ms'), }) .by('status_code') .sort(E('error_count').desc())
FROM logs-* | WHERE status_code >= 400 | STATS error_count = COUNT(*), avg_response = AVG(response_time_ms) BY status_code | SORT error_count DESC

这个 f 命名空间提供了 150+ 个 ES|QL 函数封装:包括聚合函数、字符串函数、日期函数、数学函数、地理函数等等。它们都返回可链式调用的表达式,因此可以在任何原本使用 E() 的地方使用。

步骤 4:使用日期函数进行时间维度分析

const hourlyErrors = ESQL.from('logs-*') .where(E('status_code').gte(400)) .eval({ hour: f.dateTrunc('@timestamp', '1 hour') }) .stats({ error_count: f.count() }) .by('hour') .sort(E('hour'))
FROM logs-* | WHERE status_code >= 400 | EVAL hour = DATE_TRUNC(@timestamp, "1 hour") | STATS error_count = COUNT(*) BY hour | SORT hour

步骤 5:安全地分支查询

每个方法都会返回一个新的查询对象,原始查询不会被修改。这意味着你可以先构建一个基础查询,然后为不同的视图进行分支扩展:

const base = ESQL.from('logs-*') .where(E('status_code').gte(400)) .where(E('@timestamp').gte('2026-01-01T00:00:00Z')) const byStatus = base .stats({ count: f.count() }) .by('status_code') .sort(E('count').desc()) const byHost = base .stats({ count: f.count() }) .by('host.name') .sort(E('count').desc()) .limit(20) const recent = base .sort(E('@timestamp').desc()) .keep('@timestamp', 'status_code', 'url.path', 'message') .limit(50)

三个不同的查询,共用一个基础查询。修改 base 的过滤条件,三个查询都会同步更新。这在仪表盘场景中特别有用,因为多个面板通常会对同一数据集使用不同的聚合方式。

三种表达式写法

该领域专用语言(DSL)提供了多种编写条件的方式。下面是同一个 WHERE 子句的三种不同写法:

原始字符串(raw strings):适用于快速一次性查询:

.where('status_code >= 400 AND host.name == "web-01"')

E() 表达式构建器:当你需要类型安全和自动补全时使用:

import { and_ } from '@elastic/elasticsearch-esql-dsl' .where(and_( E('status_code').gte(400), E('host.name').eq('web-01') ))

esql 模板标签(template tag):当你需要安全地插入动态值时使用:

import { esql } from '@elastic/elasticsearch-esql-dsl' const minStatus = 400 const host = 'web-01' .where(esql`status_code >= ${minStatus} AND host.name == ${host}`)

这三种方式最终都会生成相同的 ES|QL 查询。你可以根据具体场景选择合适方式:简单场景用 raw string,程序化构建表达式用 E(),而需要在静态 ES|QL 中安全插入动态值时使用 template tag。

保持查询安全

如果查询的任何部分来自用户输入,就必须考虑注入风险。ES|QL 支持参数绑定,而 DSL 可以让这一点变得更简单直观:

function searchLogs(userQuery: string) { const query = ESQL.from('logs-*') .where(E('message').eq(E('?'))) .limit(100) return client.esql.query({ query: query.render(), params: [userQuery], }) }

?占位符会在 Elasticsearch 服务器端被替换,因此用户输入不会直接进入查询字符串中。这意味着无需手动转义,也能避免注入风险。

进阶内容

当你熟悉了基础用法之后,这个 DSL 支持所有高级 ES|QL 特性,例如:

混合搜索(Hybrid search)中的 FORK 和 FUSE:

const results = ESQL.from('articles') .fork( ESQL.branch() .where(f.match('title', 'elasticsearch')) .sort(E('_score').desc()) .limit(50), ESQL.branch() .where(f.knn('embedding', 10)) .sort(E('_score').desc()) .limit(50), ) .fuse('RRF') .limit(10)

数据增强(Data enrichment)

const enriched = ESQL.from('logs-*') .enrich('ip_lookup') .on('client.ip') .with('geo.city', 'geo.country')

条件聚合(Conditional aggregation):

const stats = ESQL.from('employees') .stats({ eng_avg: f.avg('salary').where(E('dept').eq('Engineering')), sales_avg: f.avg('salary').where(E('dept').eq('Sales')), total: f.count(), })

AI / 机器学习(ML)集成:

const summarized = ESQL.from('docs') .completion('Summarize this document') .with({ inferenceId: 'my-llm' })

完整命令与函数列表请查看 ES|QL query builder 文档。

下一步

这是 @elastic/elasticsearch-esql-dsl 的首个版本发布。你可以在 npm 上找到该包,在 GitHub 上查看源码,并在仓库中阅读完整文档。如果你遇到问题或有功能需求,欢迎提交 issue;我们正在持续迭代,希望真正构建 JavaScript 和 TypeScript 开发者需要的工具。

原文:https://www.elastic.co/search-labs/blog/esql-query-builder-javascript-typescript

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 16:51:29

八大网盘直链下载助手:免费开源工具彻底告别下载限速烦恼

八大网盘直链下载助手:免费开源工具彻底告别下载限速烦恼 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天…

作者头像 李华
网站建设 2026/5/1 16:49:49

如何快速掌握PPTAgent:AI智能演示文稿生成的完整指南

如何快速掌握PPTAgent:AI智能演示文稿生成的完整指南 【免费下载链接】PPTAgent An Agentic Framework for Reflective PowerPoint Generation 项目地址: https://gitcode.com/gh_mirrors/pp/PPTAgent 你是否厌倦了花费数小时制作演示文稿?PPTAge…

作者头像 李华
网站建设 2026/5/1 16:49:33

从零到一:用10分钟语音数据打造你的专属AI声音实验室

从零到一&#xff1a;用10分钟语音数据打造你的专属AI声音实验室 【免费下载链接】Retrieval-based-Voice-Conversion-WebUI Easily train a good VC model with voice data < 10 mins! 项目地址: https://gitcode.com/GitHub_Trending/re/Retrieval-based-Voice-Conversi…

作者头像 李华