# Elasticsearch Patterns

> When to activate: Elasticsearch, ES, OpenSearch, full-text search, mappings, analyzers, aggregations, Kibana

- Skill: `mattakushi432/elasticsearch-patterns` (Agent Skill)
- Install (CLI): `npx skillmds@latest add mattakushi432/elasticsearch-patterns`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mattakushi432/elasticsearch-patterns/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Mattakushi432 (https://skillmd.com/u/mattakushi432)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/mattakushi432/elasticsearch-patterns

---

# Elasticsearch Patterns

## Mappings and Analyzers

```json
PUT /articles
{
  "settings": {
    "analysis": {
      "analyzer": {
        "custom_english": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["lowercase", "stop", "snowball"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title":   { "type": "text", "analyzer": "custom_english", "fields": { "keyword": { "type": "keyword" } } },
      "body":    { "type": "text", "analyzer": "custom_english" },
      "tags":    { "type": "keyword" },
      "price":   { "type": "double" },
      "created": { "type": "date" },
      "author":  { "type": "object", "properties": { "id": { "type": "keyword" }, "name": { "type": "text" } } }
    }
  }
}
```

## Query DSL

```json
// Bool query — the workhorse
GET /articles/_search
{
  "query": {
    "bool": {
      "must":   [{ "match": { "title": "elasticsearch patterns" } }],
      "filter": [{ "term": { "tags": "backend" } }, { "range": { "created": { "gte": "2024-01-01" } } }],
      "should": [{ "match": { "body": "performance" } }],
      "must_not": [{ "term": { "status": "draft" } }]
    }
  },
  "highlight": { "fields": { "title": {}, "body": {} } },
  "_source": ["title", "tags", "author"],
  "from": 0, "size": 20
}
```

```json
// Nested query (for nested objects)
GET /orders/_search
{
  "query": {
    "nested": {
      "path": "items",
      "query": { "bool": {
        "must": [
          { "match": { "items.name": "laptop" } },
          { "range": { "items.price": { "gte": 500 } } }
        ]
      }}
    }
  }
}
```

## Aggregations

```json
GET /orders/_search
{
  "size": 0,
  "aggs": {
    "by_status": {
      "terms": { "field": "status", "size": 10 },
      "aggs": {
        "total_revenue": { "sum": { "field": "amount" } },
        "avg_amount":    { "avg": { "field": "amount" } }
      }
    },
    "revenue_over_time": {
      "date_histogram": { "field": "created", "calendar_interval": "month" },
      "aggs": { "revenue": { "sum": { "field": "amount" } } }
    },
    "price_percentiles": {
      "percentiles": { "field": "amount", "percents": [50, 75, 90, 99] }
    }
  }
}
```

## Index Lifecycle Management

```json
PUT /_ilm/policy/logs-policy
{
  "policy": {
    "phases": {
      "hot":    { "actions": { "rollover": { "max_size": "50gb", "max_age": "1d" } } },
      "warm":   { "min_age": "7d",  "actions": { "shrink": { "number_of_shards": 1 }, "forcemerge": { "max_num_segments": 1 } } },
      "cold":   { "min_age": "30d", "actions": { "freeze": {} } },
      "delete": { "min_age": "90d", "actions": { "delete": {} } }
    }
  }
}
```

## Python Client

```python
from elasticsearch import Elasticsearch, helpers

es = Elasticsearch("https://localhost:9200", api_key="key")

# Bulk indexing
def bulk_index(docs):
    actions = [
        {"_index": "articles", "_id": d["id"], "_source": d}
        for d in docs
    ]
    helpers.bulk(es, actions, chunk_size=500, request_timeout=60)

# Search with pagination (search_after for deep pagination)
resp = es.search(index="articles", body={
    "query": { "match_all": {} },
    "sort": [{ "created": "desc" }, { "_id": "asc" }],
    "size": 100
})
last_sort = resp["hits"]["hits"][-1]["sort"]
# Next page:
resp = es.search(index="articles", body={
    "query": { "match_all": {} },
    "sort": [{ "created": "desc" }, { "_id": "asc" }],
    "search_after": last_sort,
    "size": 100
})
```

## Performance Tuning

- Shards: 1 shard per 20-40GB; avoid over-sharding
- `refresh_interval: 30s` during bulk indexing (set back to `1s` after)
- `number_of_replicas: 0` during initial load, restore after
- Use `filter` (cached) over `query` (scored) when relevance not needed
- Avoid `wildcard` queries on `text` fields — use n-gram analyzer instead
- Monitor: `_cat/indices`, `_nodes/stats`, `_cluster/health`

