Elasticsearch
Connection and cluster health
# version info
curl -X GET $ELASTIC_HOST
# cluster health
curl -X GET "$ELASTIC_HOST/_cluster/health?pretty"
# health with shard detail
curl -X GET "$ELASTIC_HOST/_cluster/health?level=shards&pretty"
# node info
curl -X GET "$ELASTIC_HOST/_nodes?pretty"
# cluster stats
curl -X GET "$ELASTIC_HOST/_cluster/stats?pretty"
Authentication
# basic auth — pass as --user or -u
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X GET "$ELASTIC_HOST/_cluster/health?pretty"
# check your own privileges
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X GET "$ELASTIC_HOST/_security/user/_privileges"
# list all users (requires manage_security)
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X GET "$ELASTIC_HOST/_security/user"
Indices
List and inspect
# list all indices (name, health, docs, size)
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" "$ELASTIC_HOST/_cat/indices?v"
# list specific index
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" "$ELASTIC_HOST/_cat/indices/$INDEX_NAME?v"
# document count for an index
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" "$ELASTIC_HOST/_cat/count/$INDEX_NAME?v"
# index mapping
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" "$ELASTIC_HOST/$INDEX_NAME/_mapping?pretty"
# index settings
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" "$ELASTIC_HOST/$INDEX_NAME/_settings?pretty"
Create an index
# create with explicit mapping and settings
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X PUT "$ELASTIC_HOST/$INDEX_NAME" \
-H 'Content-Type: application/json' -d '{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings": {
"properties": {
"timestamp": { "type": "date" },
"user_id": { "type": "keyword" },
"message": { "type": "text" },
"status_code":{ "type": "integer" }
}
}
}'
Update a mapping
# add a new field to an existing index (cannot change existing field types)
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X PUT "$ELASTIC_HOST/$INDEX_NAME/_mapping" \
-H 'Content-Type: application/json' -d '{
"properties": {
"new_field": { "type": "keyword" }
}
}'
Delete an index
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X DELETE "$ELASTIC_HOST/$INDEX_NAME"
Documents
Index a document
# with auto-generated ID (POST)
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X POST "$ELASTIC_HOST/$INDEX_NAME/_doc" \
-H 'Content-Type: application/json' -d '{
"user_id": "abc123",
"message": "login successful",
"timestamp": "2024-01-15T10:30:00Z"
}'
# with explicit ID (PUT)
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X PUT "$ELASTIC_HOST/$INDEX_NAME/_doc/1" \
-H 'Content-Type: application/json' -d '{
"user_id": "abc123",
"message": "login successful"
}'
Get a document
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" "$ELASTIC_HOST/$INDEX_NAME/_doc/1?pretty"
Update a document
# partial update (only changes specified fields)
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X POST "$ELASTIC_HOST/$INDEX_NAME/_update/1" \
-H 'Content-Type: application/json' -d '{
"doc": {
"message": "updated message"
}
}'
Delete a document
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X DELETE "$ELASTIC_HOST/$INDEX_NAME/_doc/1"
Search (Query DSL)
Match all
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X GET "$ELASTIC_HOST/$INDEX_NAME/_search?pretty" \
-H 'Content-Type: application/json' -d '{"query": {"match_all": {}}}'
Full-text search
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X GET "$ELASTIC_HOST/$INDEX_NAME/_search?pretty" \
-H 'Content-Type: application/json' -d '{
"query": {
"match": {
"message": "login failed"
}
}
}'
Term (exact match, keyword field)
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X GET "$ELASTIC_HOST/$INDEX_NAME/_search?pretty" \
-H 'Content-Type: application/json' -d '{
"query": {
"term": {
"user_id.keyword": "abc123"
}
}
}'
Range query
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X GET "$ELASTIC_HOST/$INDEX_NAME/_search?pretty" \
-H 'Content-Type: application/json' -d '{
"query": {
"range": {
"timestamp": {
"gte": "2024-01-01",
"lte": "2024-01-31"
}
}
}
}'
Boolean query (must / should / must_not / filter)
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X GET "$ELASTIC_HOST/$INDEX_NAME/_search?pretty" \
-H 'Content-Type: application/json' -d '{
"query": {
"bool": {
"must": [
{ "match": { "message": "error" } }
],
"filter": [
{ "term": { "status_code": 500 } },
{ "range": { "timestamp": { "gte": "now-24h" } } }
],
"must_not": [
{ "term": { "user_id.keyword": "test-user" } }
]
}
},
"size": 20,
"sort": [{ "timestamp": "desc" }]
}'
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X GET "$ELASTIC_HOST/$INDEX_NAME/_search?pretty" \
-H 'Content-Type: application/json' -d '{
"query": { "match_all": {} },
"from": 0,
"size": 50,
"sort": [{ "timestamp": "desc" }]
}'
URL query string (quick searches)
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" \
"$ELASTIC_HOST/$INDEX_NAME/_search?q=status_code:500&size=10&pretty"
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" \
"$ELASTIC_HOST/$INDEX_NAME/_search?q=message:error+AND+status_code:>=400&pretty"
Aggregations
Count by field value
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X GET "$ELASTIC_HOST/$INDEX_NAME/_search?pretty" \
-H 'Content-Type: application/json' -d '{
"size": 0,
"aggs": {
"by_status": {
"terms": { "field": "status_code", "size": 10 }
}
}
}'
Date histogram
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X GET "$ELASTIC_HOST/$INDEX_NAME/_search?pretty" \
-H 'Content-Type: application/json' -d '{
"size": 0,
"aggs": {
"requests_per_hour": {
"date_histogram": {
"field": "timestamp",
"calendar_interval": "hour"
}
}
}
}'
Average / min / max / sum
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X GET "$ELASTIC_HOST/$INDEX_NAME/_search?pretty" \
-H 'Content-Type: application/json' -d '{
"size": 0,
"aggs": {
"avg_response_ms": { "avg": { "field": "response_ms" } },
"max_response_ms": { "max": { "field": "response_ms" } },
"p99_response_ms": {
"percentiles": { "field": "response_ms", "percents": [50, 95, 99] }
}
}
}'
Bulk operations
# bulk index (newline-delimited JSON — each action line followed by a source line)
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X POST "$ELASTIC_HOST/_bulk" \
-H 'Content-Type: application/x-ndjson' --data-binary @- << 'EOF'
{"index": {"_index": "logs", "_id": "1"}}
{"timestamp": "2024-01-15T10:00:00Z", "message": "started"}
{"index": {"_index": "logs", "_id": "2"}}
{"timestamp": "2024-01-15T10:01:00Z", "message": "ready"}
EOF
Delete by query
# delete documents matching a query
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X POST "$ELASTIC_HOST/$INDEX_NAME/_delete_by_query" \
-H 'Content-Type: application/json' -d '{
"query": {
"term": { "user_id.keyword": "test-user" }
}
}'
# delete all documents in an index (without deleting the index itself)
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X POST "$ELASTIC_HOST/$INDEX_NAME/_delete_by_query" \
-H 'Content-Type: application/json' -d '{"query": {"match_all": {}}}'
Index lifecycle (ILM)
# check ILM status for an index
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" "$ELASTIC_HOST/$INDEX_NAME/_ilm/explain?pretty"
# list ILM policies
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" "$ELASTIC_HOST/_ilm/policy?pretty"
Snapshots and backups
# list snapshot repositories
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" "$ELASTIC_HOST/_snapshot?pretty"
# list snapshots in a repo
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" "$ELASTIC_HOST/_snapshot/my_repo/_all?pretty"
# create a snapshot
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X PUT "$ELASTIC_HOST/_snapshot/my_repo/snapshot_1?wait_for_completion=true" \
-H 'Content-Type: application/json' -d '{
"indices": "logs-*",
"ignore_unavailable": true
}'
Common errors
| Error |
Likely cause |
illegal_argument_exception: Can't merge because of conflicts |
Trying to change a field's type in an existing mapping — reindex instead |
index_not_found_exception |
Index name typo or index hasn't been created yet |
circuit_breaking_exception |
Node is out of JVM heap — reduce query result size or add nodes |
too_many_requests (429) |
Bulk indexing too fast — back off and retry |
version_conflict_engine_exception |
Concurrent updates to the same document — use retry_on_conflict |
# update with retry on conflict
curl -u "$ELASTIC_USER:$ELASTIC_PASSWORD" -X POST \
"$ELASTIC_HOST/$INDEX_NAME/_update/1?retry_on_conflict=3" \
-H 'Content-Type: application/json' -d '{"doc": {"status": "done"}}'