Elasticsearch - Quick Reference

SkillSearch

Elasticsearch search and analytics engine. Full-text search, aggregations, document store. Use when implementing search functionality or log analytics.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Elasticsearch - Quick Reference skill

What this skill tells your AI

The instructions your AI receives, as published by claude-dev-suite/claude-dev-suite in skills/databases/elasticsearch/SKILL.md and read by ahel’s review.

Full Reference: See advanced.md for aggregations, autocomplete/suggestions, highlighting, custom analyzers, index templates, ILM, and Spring Data Elasticsearch.

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: elasticsearch for comprehensive documentation.

Setup

# Docker
docker run -d --name elasticsearch \
  -p 9200:9200 -p 9300:9300 \
  -e "discovery.type=single-node" \
  -e "xpack.security.enabled=false" \
  elasticsearch:8.12.0
# docker-compose.yml
services:
  elasticsearch:
    image: elasticsearch:8.12.0
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ports:
      - "9200:9200"
    volumes:
      - esdata:/usr/share/elasticsearch/data

volumes:
  esdata:

Node.js Client

npm install @elastic/elasticsearch
import { Client } from '@elastic/elasticsearch';

const client = new Client({
  node: 'http://localhost:9200',
  // With authentication
  // auth: { username: 'elastic', password: 'password' }
});

// Health check
const health = await client.cluster.health();
console.log(health);

Index Management

Create Index

await client.indices.create({
  index: 'products',
  body: {
    settings: {
      number_of_shards: 1,
      number_of_replicas: 0,
      analysis: {
        analyzer: {
          custom_analyzer: {
            type: 'custom',
            tokenizer: 'standard',
            filter: ['lowercase', 'asciifolding'],
          },
        },
      },
    },
    mappings: {
      properties: {
        name: {
          type: 'text',
          analyzer: 'custom_analyzer',
          fields: {
            keyword: { type: 'keyword' },
          },
        },
        description: { type: 'text' },
        price: { type: 'float' },
        category: { type: 'keyword' },
        tags: { type: 'keyword' },
        inStock: { type: 'boolean' },
        createdAt: { type: 'date' },
        location: { type: 'geo_point' },
      },
    },
  },
});

Index Operations

// Check if exists
const exists = await client.indices.exists({ index: 'products' });

// Get mapping
const mapping = await client.indices.getMapping({ index: 'products' });

// Update mapping (add fields only)
await client.indices.putMapping({
  index: 'products',
  body: {
    properties: {
      newField: { type: 'keyword' },
    },
  },
});

// Delete index
await client.indices.delete({ index: 'products' });

// Reindex
await client.reindex({
  body: {
    source: { index: 'products' },
    dest: { index: 'products_v2' },
  },
});

Document Operations

CRUD

// Index document
await client.index({
  index: 'products',
  id: '1', // optional, auto-generated if not provided
  body: {
    name: 'iPhone 15',
    description: 'Latest Apple smartphone',
    price: 999.99,
    category: 'electronics',
    tags: ['phone', 'apple', 'smartphone'],
    inStock: true,
    createdAt: new Date(),
  },
});

// Get document
const doc = await client.get({ index: 'products', id: '1' });

// Update document
await client.update({
  index: 'products',
  id: '1',
  body: {
    doc: { price: 899.99, inStock: false },
  },
});

// Delete document
await client.delete({ index: 'products', id: '1' });

Bulk Operations

const products = [
  { name: 'Product 1', price: 10 },
  { name: 'Product 2', price: 20 },
  { name: 'Product 3', price: 30 },
];

const body = products.flatMap((doc, i) => [
  { index: { _index: 'products', _id: String(i + 1) } },
  doc,
]);

const { body: bulkResponse } = await client.bulk({ body, refresh: true });

if (bulkResponse.errors) {
  const erroredDocuments = bulkResponse.items.filter(
    (item: any) => item.index?.error
  );
  console.error('Bulk errors:', erroredDocuments);
}

Search

Basic Search

const result = await client.search({
  index: 'products',
  body: {
    query: {
      match: { name: 'iphone' },
    },
  },
});

console.log(result.hits.hits); // Array of matching documents
console.log(result.hits.total); // Total count

Query Types

// Match (full-text search)
{ match: { name: 'iphone pro' } }

// Match phrase
{ match_phrase: { name: 'iphone pro' } }

// Multi-match (search multiple fields)
{
  multi_match: {
    query: 'iphone',
    fields: ['name^2', 'description'],  // name has 2x weight
  }
}

// Term (exact match for keywords)
{ term: { category: 'electronics' } }

// Terms (multiple exact values)
{ terms: { category: ['electronics', 'phones'] } }

// Range
{ range: { price: { gte: 100, lte: 500 } } }

// Bool (combine queries)
{
  bool: {
    must: [{ match: { name: 'iphone' } }],
    filter: [
      { term: { inStock: true } },
      { range: { price: { lte: 1000 } } }
    ],
    should: [{ term: { category: 'electronics' } }],
    must_not: [{ term: { category: 'refurbished' } }],
    minimum_should_match: 1
  }
}

// Wildcard
{ wildcard: { name: 'iph*' } }

// Fuzzy (typo tolerance)
{ fuzzy: { name: { value: 'iphne', fuzziness: 'AUTO' } } }

// Prefix
{ prefix: { name: 'iph' } }

Pagination & Sorting

const result = await client.search({
  index: 'products',
  body: {
    from: 0,
    size: 10,
    query: { match_all: {} },
    sort: [
      { price: 'asc' },
      { createdAt: 'desc' },
      '_score',
    ],
    _source: ['name', 'price', 'category'], // Select fields
  },
});

Search After (for deep pagination)

// First page
const firstPage = await client.search({
  index: 'products',
  body: {
    size: 10,
    query: { match_all: {} },
    sort: [{ createdAt: 'desc' }, { _id: 'asc' }],
  },
});

// Next page (use sort values from last hit)
const lastHit = firstPage.hits.hits[firstPage.hits.hits.length - 1];
const nextPage = await client.search({
  index: 'products',
  body: {
    size: 10,
    query: { match_all: {} },
    sort: [{ createdAt: 'desc' }, { _id: 'asc' }],
    search_after: lastHit.sort,
  },
});

Anti-Patterns

Anti-PatternProblemSolution
Dynamic mapping in productionSchema drift, type conflictsDefine explicit mappings
Deep pagination with from/sizeMemory issues, slow queriesUse search_after or scroll
No index lifecycle managementDisk space exhaustionConfigure ILM policies
Wildcard queries starting with *Very slow, full index scanAvoid or use ngrams
Storing everything in _sourceDisk wasteUse _source filtering
No refresh interval tuningIndex lag or performance issuesSet 30s for production
Missing replicasData loss risk, no HAConfigure at least 1 replica

Performance Tips

OptimizationRecommendation
Bulk indexingBatch 5000-15000 docs
Refresh interval30s in production
Replicas during indexSet to 0, restore after
MappingExplicit, not dynamic
Shards1 shard per 50GB

Monitoring Metrics

MetricTarget
Search latency< 100ms p99
Indexing rateDepends on use case
JVM heap< 75%
Disk usage< 80%

Checklist

  • Explicit mapping defined
  • Analyzers configured for language
  • Index template for patterns
  • ILM policy for retention
  • Replicas configured
  • Monitoring active

When NOT to Use This Skill

  • Primary database - Use postgresql or mongodb for transactional data
  • Caching - Use redis for session storage and caching
  • ACID transactions - Elasticsearch is eventual consistency, use SQL for strong consistency
  • Small datasets - Overhead not justified for <100K documents
  • Real-time updates - Near-real-time (1s delay by default), use websockets if needed

Quick Troubleshooting

ProblemDiagnosticFix
Cluster yellow/redGET _cluster/healthCheck shard allocation, disk space
Slow searchesGET _search?explain=trueAdd caching, optimize queries
Out of memoryCheck JVM heap usageIncrease heap, reduce field data cache
Index not updatingCheck refresh_intervalForce refresh or wait for interval
Mapping conflictsGET index/_mappingReindex with correct mapping
High disk usageGET _cat/indices?vConfigure ILM, delete old indices

Reference Documentation

Signals

GitHub stars
33
Forks
6
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
elasticsearch-claude-dev-suite
Source
github.com/claude-dev-suite/claude-dev-suite