Elasticsearch Cheatsheet
Elasticsearch Cheatsheet
REST API reference in Kibana Dev Tools console syntax (prefix with curl -XGET localhost:9200/… to run from a shell). Covers the query DSL, aggregations, bulk/reindex, and the Optimize settings that keep indexing and search fast.
Cluster & node health
| Request | Returns |
|---|---|
| GET /_cluster/health | Overall status: green / yellow / red, shard counts. |
| GET /_cat/health?v | One-line cluster health with column headers. |
| GET /_cat/nodes?v | Nodes, roles, CPU, heap, load. |
| GET /_cat/indices?v&s=store.size:desc | Indices sorted by size, with health and doc counts. |
| GET /_cat/shards?v | Shard placement and state. |
| GET /_nodes/stats | Detailed per-node stats (JVM, threads, IO). |
| GET /_cluster/allocation/explain | Why a shard is unassigned. |
Yellow vs red Yellow means replicas are unassigned (common on a single node) — the data is fine. Red means a primary shard is missing.
Index management
# Create an index with settings + explicit mappings PUT /logs-2026 { "settings": { "number_of_shards": 1, "number_of_replicas": 1 }, "mappings": { "properties": { "@timestamp": { "type": "date" }, "level": { "type": "keyword" }, "message": { "type": "text" }, "bytes": { "type": "long" } } } } # Inspect GET /logs-2026 GET /logs-2026/_mapping GET /logs-2026/_settings # Change a dynamic setting PUT /logs-2026/_settings { "index": { "number_of_replicas": 2 } } # Open / close / delete POST /logs-2026/_close POST /logs-2026/_open DELETE /logs-2026
# Alias: atomic swap for zero-downtime reindex
POST /_aliases
{
"actions": [
{ "remove": { "index": "logs-old", "alias": "logs" } },
{ "add": { "index": "logs-new", "alias": "logs" } }
]
}Documents (CRUD)
# Index with an auto-generated ID POST /logs/_doc { "level": "error", "message": "disk full", "bytes": 512 } # Index / overwrite with an explicit ID PUT /logs/_doc/1 { "level": "info", "message": "started" } # Get one GET /logs/_doc/1 # Partial update POST /logs/_update/1 { "doc": { "level": "warn" } } # Scripted update POST /logs/_update/1 { "script": { "source": "ctx._source.bytes += params.n", "params": { "n": 10 } } } # Delete DELETE /logs/_doc/1
Search basics
# Everything GET /logs/_search { "query": { "match_all": {} } } # Full-text match (the field is analyzed) GET /logs/_search { "query": { "match": { "message": "disk full" } } } # Exact term (keyword / numeric, not analyzed) GET /logs/_search { "query": { "term": { "level": "error" } } } # Boolean: must scores, filter is cached + unscored GET /logs/_search { "query": { "bool": { "must": [ { "match": { "message": "timeout" } } ], "filter": [ { "term": { "level": "error" } }, { "range": { "@timestamp": { "gte": "now-1d" } } } ], "must_not": [ { "term": { "env": "test" } } ] } } } # Quick URI search GET /logs/_search?q=level:error&size=5
Query clauses
| Clause | Use |
|---|---|
| match | Full-text search on an analyzed field. |
| match_phrase | Phrase match; word order matters. |
| multi_match | One query across several fields. |
| term / terms | Exact value(s) on keyword / numeric fields. |
| range | gte / lte / gt / lt; dates accept now-1d. |
| bool | Combine with must / filter / should / must_not. |
| exists | Documents where a field is present. |
| prefix / wildcard | Pattern match on keyword (can be costly). |
| query_string | Lucene mini-syntax in a single string. |
Filter vs query context Put yes/no conditions (term, range, exists) in filter — results are cached and skip relevance scoring. Reserve must for things you want ranked.
Pagination & sort
# Shallow paging (default cap: 10,000 results) GET /logs/_search { "from": 0, "size": 20, "sort": [ { "@timestamp": "desc" } ] } # Deep paging: search_after (stateless, no offset cost) GET /logs/_search { "size": 100, "sort": [ { "@timestamp": "asc" }, { "_id": "asc" } ], "search_after": [ 1717200000000, "abc123" ] } # Point in Time for a consistent view across pages POST /logs/_pit?keep_alive=1m # Return only the fields you need GET /logs/_search { "_source": [ "level", "message" ], "query": { "match_all": {} } }
Deep pagination Prefer search_after + PIT over the legacy scroll API and over large from offsets.
Aggregations
# size:0 skips hits; nest metrics inside buckets
GET /logs/_search
{
"size": 0,
"aggs": {
"by_level": {
"terms": { "field": "level", "size": 10 },
"aggs": {
"avg_bytes": { "avg": { "field": "bytes" } }
}
},
"per_hour": {
"date_histogram": { "field": "@timestamp", "calendar_interval": "hour" }
}
}
}Metric vs bucket Metric aggs compute a value (avg, sum, min, max, cardinality); bucket aggs group docs (terms, range, date_histogram) and can nest sub-aggs.
Mappings & analysis
| Type | For |
|---|---|
| keyword | Exact values, aggregations, sorting (IDs, status, tags). |
| text | Full-text, analyzed (messages, descriptions). |
| long / double | Numerics and range queries. |
| date | Timestamps (epoch millis or ISO-8601). |
| boolean / ip | True/false; IP addresses with CIDR range support. |
| object / nested | Structured data; nested for arrays of objects queried independently. |
# Add a field (existing field types can't be changed in place) PUT /logs/_mapping { "properties": { "host": { "type": "keyword" } } } # text + keyword multi-field: search AND aggregate the same data # "message": { "type": "text", "fields": { "raw": { "type": "keyword" } } } # Test how an analyzer tokenizes POST /_analyze { "analyzer": "standard", "text": "The Quick Brown Fox" }
Bulk & reindex
# Bulk NDJSON: action line + source line, body ends with a newline POST /_bulk { "index": { "_index": "logs", "_id": "1" } } { "level": "info", "message": "a" } { "index": { "_index": "logs", "_id": "2" } } { "level": "warn", "message": "b" } { "delete": { "_index": "logs", "_id": "3" } } # Copy / transform between indices POST /_reindex { "source": { "index": "logs-old" }, "dest": { "index": "logs-new" } } # Mutate in place POST /logs/_update_by_query { "query": { "term": { "level": "debug" } }, "script": { "source": "ctx._source.level = 'trace'" } } # Bulk delete by query (e.g. retention) POST /logs/_delete_by_query { "query": { "range": { "@timestamp": { "lt": "now-30d" } } } }
_cat quick reference
| Endpoint | Shows |
|---|---|
| /_cat/indices?v | Indices: health, docs, size. |
| /_cat/health?v | Cluster health summary. |
| /_cat/nodes?v | Nodes and roles. |
| /_cat/shards?v | Shard placement. |
| /_cat/allocation?v | Disk usage per node. |
| /_cat/thread_pool?v | Queues and rejections (spot backpressure). |
| /_cat/aliases?v | Alias to index mapping. |
Params ?v headers · ?s=col:desc sort · ?h=c1,c2 pick columns · &format=json for machine output.
Cluster ops
| Request | Purpose |
|---|---|
| GET /_tasks?detailed | Running tasks (reindex, by-query jobs). |
| GET /_cluster/settings | Current cluster settings. |
| PUT /_index_template/… | Templates that apply settings/mappings to new indices. |
| PUT /_ilm/policy/… | Index Lifecycle Management (rollover, delete). |
| POST /index/_forcemerge | Merge segments on a read-only index. |
# Snapshot to a registered repository PUT /_snapshot/backup/snap-2026-06?wait_for_completion=true { "indices": "logs-*", "include_global_state": false } # Restore POST /_snapshot/backup/snap-2026-06/_restore { "indices": "logs-2026" } # Tune a cluster setting at runtime PUT /_cluster/settings { "persistent": { "indices.recovery.max_bytes_per_sec": "100mb" } }
Optimize
Indexing throughput and query latency, with the highest-payoff levers first.
| Area | Lever |
|---|---|
| Indexing | Use _bulk in batches of ~5–15 MB, never one doc per request. |
| Indexing | During big loads set refresh_interval: “30s” (or -1), then refresh after. |
| Indexing | Set number_of_replicas: 0 for the initial load, restore replicas afterward. |
| Indexing | Let Elasticsearch auto-generate IDs — skips the exists lookup. |
| Sharding | Aim ~10–50 GB per shard; over-sharding wastes heap and slows search. |
| Query | Put exact/range conditions in filter context — cached, no scoring. |
| Query | Use keyword for aggregations/sorting; doc_values are on by default. |
| Query | search_after + PIT for deep pages; trim payloads with _source filtering. |
| Storage | _forcemerge read-only indices down to one segment. |
| Mapping | Set “index”: false on fields you store but never search. |