執行 ES|QL (Elasticsearch 查詢語言) 查詢,當使用者想要查詢 Elasticsearch 資料、分析日誌、彙總指標、探索資料,或從 ES|QL 結果建立圖表與儀表板時使用。
Elasticsearch ES|QL
對 Elasticsearch 執行 ES|QL 查詢。
什麼是 ES|QL?
ES|QL (Elasticsearch 查詢語言) 是 Elasticsearch 的管線式查詢語言。它不同於:
- Elasticsearch Query 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追蹤正在開發中的堆疊線(主線的下一個次要版本),因此僅進行 semver 比較的客戶端可能會將 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 員工通常使用快照版本進行測試。
環境設定
請參閱 Environment Setup 了解完整的連線設定選項(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:以 Tab 分隔值輸出(乾淨,無裝飾)--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(...))中。在撰寫任何時間序列查詢之前,請先閱讀
Generation Tips 中的完整 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之前。請參閱
Time Series Queries。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 Command。偏好使用TS進行原生
ES|QL 表達。 - "搜尋"、"尋找符合的文件" →
MATCH(預設)、QSTR(進階布林)、KQL(Kibana 遷移)。對於
內容/文件相關性搜尋,請遵循 ES|QL Search Strategy - "計數"、"平均"、"細分" → 使用彙總函數的
STATS
- "尋找模式"、"分類"、"分組相似訊息" →
-
在生成查詢之前閱讀參考資料:
- Generation Tips - 關鍵模式(TS/TBUCKET/RATE、每個彙總的 WHERE、LOOKUP JOIN、
CIDR_MATCH)、常見範本和歧義處理 - Time Series Queries - 在任何 TS 查詢之前閱讀:內/外層彙總
模型、TBUCKET 語法、RATE 限制 - PROMQL Command — 在任何 PROMQL 查詢之前閱讀:選項、輸出結構描述、
限制,以及PROMQL與TS的決策矩陣(9.4+ 預覽) - ES|QL Complete Reference - 所有指令和函數的完整語法
- ES|QL Search Strategy — 用於內容/文件相關性搜尋(檢索 →
融合 → 重新排序) - ES|QL Search Reference — 用於全文搜尋函數語法(MATCH、QSTR、KQL、
評分)
- Generation Tips - 關鍵模式(TS/TBUCKET/RATE、每個彙總的 WHERE、LOOKUP JOIN、
-
生成查詢,遵循 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)
進行時間分桶 — 請參閱 Generation Tips 中的 TS 章節,了解三個關鍵語法規則 - 若要偵測突波、驟降或異常,請在時間分桶彙總後使用
CHANGE_POINT - 視需要新增
SORT和LIMIT
- 以
-
使用 TSV 標誌執行:
node scripts/esql.js raw "FROM index | STATS count = COUNT(*) BY field" --tsv
ES|QL 快速參考
版本可用性: 本節為求可讀性省略了版本註解。請查閱
ES|QL Version History 了解各 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 通常就足夠了 — 除非使用者明確要求篩選,否則不要
在 MATCH 旁邊新增冗餘的關鍵字相等篩選(例如 category == "X")。僅在需要進階布林邏輯、
萬用字元或單一表達式中的多欄位搜尋時才使用 QSTR。MATCH 的第一個引數必須是一個真實的欄位名稱 — 不是列出多個欄位的字串(例如 "title,content")
也不是多個欄位引數;使用 MATCH(a, "q") OR MATCH(b, "q") 組合欄位。KQL 從 8.18/9.0+ 開始可用。
對於內容/文件搜尋使用案例,請遵循 ES|QL Search Strategy。請參閱
ES|QL Search Reference 了解完整的函數指南。
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 Command 了解完整參考。
// 適應性 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 Complete Reference 了解詳細資訊。在 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 Complete Reference
- ES|QL Search Reference - 全文搜尋:MATCH、QSTR、KQL、MATCH_PHRASE、評分、
語意搜尋 - ES|QL Search Strategy - 內容索引的相關性搜尋策略:檢索
→ 融合 → 重新排序 - ES|QL Version History - 各 Elasticsearch 版本的功能可用性
- Query Patterns - 自然語言到 ES|QL 的轉換
- Generation Tips - 查詢生成的最佳實務
- Time Series Queries - TS 指令、時間序列彙總函數、TBUCKET
- PROMQL Command - TSDS 索引的 PromQL 來源指令(9.4+ 預覽)
- DSL to ES|QL Migration - 將 Query DSL 轉換為 ES|QL
- Environment Setup - 連線設定選項
錯誤處理
當查詢執行失敗時,腳本會回傳:
- 生成的 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






