Loading...
Loading...
Execute ES|QL (Elasticsearch Query Language) queries, use when the user wants to query Elasticsearch data, analyze logs, aggregate metrics, explore data, or create charts and dashboards from ES|QL results.
npx skill4agent add elastic/agent-skills elasticsearch-esql|FROM index | WHERE condition | STATS aggregation BY field | SORT field | LIMIT nPrerequisite: ES|QL requiresto be enabled on queried indices. Indices with_sourcedisabled (e.g.,_source) will cause ES|QL queries to fail."_source": { "enabled": false }Version Compatibility: ES|QL was introduced in 8.11 (tech preview) and became GA in 8.14. Features like(8.18+),LOOKUP JOIN(8.17+), andMATCH(9.2+) were added in later versions. On pre-8.18 clusters, useINLINE STATSas a fallback forENRICH(see generation tips).LOOKUP JOINand counter-fieldINLINE STATShave no fallback before 9.2. Check references/esql-version-history.md for feature availability by version.RATE()Cluster Detection: Use theresponse to determine the cluster type and version:GET /
— Elastic Cloud Serverless. Reports versionbuild_flavor: "serverless"but supports all latest ES|QL features. Ignore the version number and assume all GA and preview features are available.8.11.0 — Self-managed or Elastic Cloud Hosted. Usebuild_flavor: "default"for feature availability.version.number- Snapshot builds have
likeversion.number. Strip the9.4.0-SNAPSHOTsuffix and use the major.minor for version checks. Snapshot builds include all features from that version plus potentially unreleased features from development — if a query fails with an unknown function/command, it may simply not have landed yet. Elastic employees commonly use snapshot builds for testing.-SNAPSHOT
node scripts/esql.js testexport ELASTICSEARCH_CLOUD_ID="deployment-name:base64encodedcloudid"
export ELASTICSEARCH_API_KEY="base64encodedapikey"export ELASTICSEARCH_URL="https://elasticsearch:9200"
export ELASTICSEARCH_API_KEY="base64encodedapikey"export ELASTICSEARCH_URL="https://elasticsearch:9200"
export ELASTICSEARCH_USERNAME="elastic"
export ELASTICSEARCH_PASSWORD="changeme"curl -fsSL https://elastic.co/start-local | shhttp://localhost:9200http://localhost:5601elastic.envelastic-start-local.envsource elastic-start-local/.env
export ELASTICSEARCH_URL="$ES_LOCAL_URL"
export ELASTICSEARCH_API_KEY="$ES_LOCAL_API_KEY"node scripts/esql.js testexport ELASTICSEARCH_INSECURE="true"node scripts/esql.js indices # List all indices
node scripts/esql.js indices "logs-*" # List matching indices
node scripts/esql.js schema "logs-2024.01.01" # Get field mappings for an indexnode scripts/esql.js raw "FROM logs-* | STATS count = COUNT(*) BY host.name | SORT count DESC | LIMIT 5"node scripts/esql.js raw "FROM logs-* | STATS count = COUNT(*) BY component | SORT count DESC" --tsv--tsv-t--no-headernode scripts/esql.js testnode scripts/esql.js testbuild_flavorGET /"serverless"node scripts/esql.js indices "pattern*"
node scripts/esql.js schema "index-name"logs-testlogs-app-*application_logssource.ipservice.nameschemaIndex mode: time_seriesTS <data-stream>FROMTBUCKET(interval)DATE_TRUNCSUM(RATE(...))curl -s "$ELASTICSEARCH_URL/<index-name>/_settings/index.mode" -H "Authorization: ApiKey $ELASTICSEARCH_API_KEY"CATEGORIZE(field)CHANGE_POINT value ON keySTATS ... BY BUCKET(@timestamp, interval)TSMATCHQSTRKQLSTATSFROM index-patternTS index-patternWHERETRANGEEVALSTATS ... BYTSSUM(RATE(...))AVG(...)TBUCKET(interval)CHANGE_POINTSORTLIMITnode scripts/esql.js raw "FROM index | STATS count = COUNT(*) BY field" --tsvVersion availability: This section omits version annotations for readability. Check ES|QL Version History for feature availability by Elasticsearch version.
FROM index-pattern
| WHERE condition
| EVAL new_field = expression
| STATS aggregation BY grouping
| SORT field DESC
| LIMIT nFROM logs-*
| WHERE @timestamp > NOW() - 24 hours AND level == "error"
| SORT @timestamp DESC
| LIMIT 100FROM metrics-*
| WHERE @timestamp > NOW() - 7 days
| STATS avg_cpu = AVG(cpu.percent) BY bucket = DATE_TRUNC(1 hour, @timestamp)
| SORT bucket DESCFROM web-logs
| STATS count = COUNT(*) BY response.status_code
| SORT count DESC
| LIMIT 10MATCHQSTRKQLLIKERLIKEFROM documents METADATA _score
| WHERE MATCH(content, "search terms")
| SORT _score DESC
| LIMIT 20CATEGORIZESTATS ... BY fieldFROM logs-*
| WHERE @timestamp > NOW() - 24 hours
| STATS count = COUNT(*) BY category = CATEGORIZE(message)
| SORT count DESC
| LIMIT 20CHANGE_POINTFROM logs-*
| STATS c = COUNT(*) BY t = BUCKET(@timestamp, 30 seconds)
| SORT t
| CHANGE_POINT c ON t
| WHERE type IS NOT NULL// 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 bucketRENAMEON// Field name mismatch — RENAME before joining
FROM support_tickets
| RENAME product AS product_name
| LOOKUP JOIN knowledge_base ON product_name
// Multi-field join (9.2+)
FROM application_logs
| LOOKUP JOIN service_registry ON service_name, environment
| KEEP service_name, environment, owner_teamMV_CONTAINSMV_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 DESCSORTCHANGE_POINTFROM logs-*
| STATS error_count = COUNT(*) BY bucket = DATE_TRUNC(1 hour, @timestamp)
| SORT bucket
| CHANGE_POINT error_count ON bucket AS type, pvaluenode scripts/esql.js schema "index"# Schema discovery
node scripts/esql.js test
node scripts/esql.js indices "logs-*"
node scripts/esql.js schema "logs-2024.01.01"
# Execute queries
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