Skip to content

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": {}}}'
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" }]
}'

Pagination

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"}}'