Elasticsearch interviews test your understanding of distributed search, the inverted index, Query DSL, aggregations, cluster management, and performance tuning. This guide covers 50 common questions — with concise answers and examples.
Quick reference
| Topic | Most asked questions |
|---|---|
| Core concepts | Inverted index, nodes, shards, replicas, documents |
| Indexing | Mappings, dynamic vs explicit, index templates |
| Query DSL | match, term, bool, range, nested, filter vs query |
| Aggregations | Bucket, metric, pipeline aggregations |
| Performance | Sharding strategy, bulk API, caching, refresh interval |
| Cluster | Node roles, allocation, routing, health, snapshots |
| Analysis | Analyzers, tokenizers, token filters |
| Advanced | Scripting, function score, percolators, cross-cluster |
Core Concepts
1. What is Elasticsearch and what problem does it solve?
Elasticsearch is a distributed, RESTful search and analytics engine built on top of Apache Lucene. It solves the problem of full-text search at scale — enabling fast queries across billions of documents with near-real-time indexing.
Key use cases:
- Application search (product search, site search)
- Log analytics (ELK stack: Elasticsearch + Logstash + Kibana)
- APM and observability
- Geospatial data search
- Vector/semantic search (since 8.x)
2. What is an inverted index?
An inverted index maps each unique term (word) to the list of documents that contain it — the opposite of a forward index (document → terms).
Term → Documents
"javascript" → [doc1, doc3, doc7]
"python" → [doc2, doc3, doc5]
"docker" → [doc1, doc4]
When you search for "python", Elasticsearch looks up "python" in the inverted index and retrieves the matching document IDs in microseconds — regardless of how many documents exist.
3. What is a document, index, and shard?
| Concept | Description |
|---|---|
| Document | A JSON object stored in Elasticsearch (analogous to a row in SQL) |
| Index | A collection of documents with similar structure (analogous to a SQL table) |
| Shard | A single Lucene index; Elasticsearch distributes shards across nodes |
| Primary shard | Handles write operations; set at index creation |
| Replica shard | Copy of a primary; provides redundancy and read scalability |
// A document in the "products" index
{
"_index": "products",
"_id": "42",
"_source": {
"name": "Mechanical Keyboard",
"price": 149.99,
"category": "electronics"
}
}
4. What is the difference between a node and a cluster?
- Node: A single running Elasticsearch instance. Each node stores data and participates in the cluster's indexing and search operations.
- Cluster: A collection of one or more nodes identified by a shared
cluster.name. All nodes in a cluster communicate and share data.
Every Elasticsearch cluster has a master node that manages cluster-wide settings (creating/deleting indices, allocating shards). Other nodes can have roles: data, coordinating, ingest, ML.
5. How does Elasticsearch achieve near-real-time (NRT) search?
Elasticsearch uses a refresh interval (default: 1 second) to make newly indexed documents searchable.
The pipeline:
- Documents are written to an in-memory buffer and a transaction log (translog)
- On refresh, the buffer is flushed to a new Lucene segment (searchable)
- On flush (every 30 min or when translog is large), segments are written to disk
// Increase refresh interval for bulk indexing (faster throughput)
PUT /my-index/_settings
{
"index": {
"refresh_interval": "30s"
}
}
// Set back to default after bulk load
PUT /my-index/_settings
{
"index": {
"refresh_interval": "1s"
}
}
Indexing & Mappings
6. What is a mapping in Elasticsearch?
A mapping defines the schema for an index — the data types and indexing behaviour of each field.
PUT /products
{
"mappings": {
"properties": {
"name": { "type": "text" },
"sku": { "type": "keyword" },
"price": { "type": "double" },
"stock": { "type": "integer" },
"created": { "type": "date" },
"in_stock": { "type": "boolean" },
"tags": { "type": "keyword" }
}
}
}
7. What is the difference between text and keyword field types?
| Feature | text |
keyword |
|---|---|---|
| Use case | Full-text search | Exact match, aggregations, sorting |
| Analysed? | Yes (tokenised, lowercased) | No (stored as-is) |
| Example | Product description, article body | SKU, status, email, tag |
| Aggregation | Not supported (unless fielddata) |
Supported |
| Sorting | Not supported | Supported |
A field often needs both:
"title": {
"type": "text",
"fields": {
"keyword": { "type": "keyword" }
}
}
8. What is dynamic mapping and when is it a problem?
Dynamic mapping automatically creates field types when a new field is encountered. Elasticsearch infers the type:
- JSON string →
text+keyword - JSON number →
longorfloat - JSON boolean →
boolean
Problems:
- Mapping explosions: thousands of dynamically created fields degrade performance
- Wrong type inferred (e.g., "123" stored as
longinstead ofkeyword) - Can't change mapping after creation (must reindex)
Solution: Use explicit mappings or set "dynamic": "strict" to reject unknown fields.
PUT /my-index
{
"mappings": {
"dynamic": "strict",
"properties": { ... }
}
}
9. What are index templates and data streams?
Index templates apply mappings and settings automatically when a new index matching a pattern is created:
PUT /_index_template/logs-template
{
"index_patterns": ["logs-*"],
"template": {
"settings": { "number_of_shards": 2 },
"mappings": {
"properties": {
"@timestamp": { "type": "date" },
"level": { "type": "keyword" },
"message": { "type": "text" }
}
}
}
}
Data streams are time-series indices backed by multiple rolling indices (useful for logs). They always include a @timestamp field and support automated rollover via ILM (Index Lifecycle Management).
10. Why can't you change an existing field mapping?
Changing a field type (e.g., text → keyword) requires rebuilding the inverted index, which Elasticsearch can't do in place. You must:
- Create a new index with the correct mapping
- Reindex data with the
_reindexAPI - Update aliases to point to the new index
POST /_reindex
{
"source": { "index": "products-v1" },
"dest": { "index": "products-v2" }
}
Query DSL
11. What is the difference between query context and filter context?
| Query context | Filter context | |
|---|---|---|
| Computes relevance score? | Yes | No |
| Cached? | No | Yes (bitset cache) |
| Use for | Full-text search, relevance ranking | Exact match, range, yes/no filtering |
| Performance | Slower | Faster |
Best practice: Use filter for anything that doesn't affect relevance (date ranges, status, category).
GET /products/_search
{
"query": {
"bool": {
"must": [{ "match": { "name": "keyboard" } }], // scored
"filter": [
{ "term": { "in_stock": true } }, // not scored
{ "range": { "price": { "lte": 200 } } } // not scored
]
}
}
}
12. What is a bool query?
A bool query combines multiple queries using logical clauses:
| Clause | Behaviour |
|---|---|
must |
Must match; contributes to score |
filter |
Must match; does NOT contribute to score (cached) |
should |
Should match; boosts score if it does |
must_not |
Must NOT match; does not contribute to score |
{
"bool": {
"must": [{ "match": { "title": "python" } }],
"should": [{ "term": { "tags": "beginner" } }],
"must_not": [{ "term": { "status": "draft" } }],
"filter": [{ "range": { "date": { "gte": "2024-01-01" } } }]
}
}
13. What is the difference between match and term queries?
match |
term |
|
|---|---|---|
| Input analysed? | Yes | No |
| Best for | text fields (full-text) |
keyword, numeric, boolean |
| Example | Searching product descriptions | Filtering by status="active" |
// match: "Mechanical KEYBOARD" → tokenised → matches "mechanical", "keyboard"
{ "match": { "description": "Mechanical KEYBOARD" } }
// term: exact value (case-sensitive for keyword fields)
{ "term": { "status": "active" } }
14. What is a multi_match query?
Search the same query string across multiple fields:
{
"multi_match": {
"query": "keyboard",
"fields": ["name^3", "description", "tags"],
"type": "best_fields"
}
}
^3boosts thenamefield score by 3×- Types:
best_fields(default),most_fields,cross_fields,phrase,phrase_prefix
15. What is a match_phrase query and how does it differ from match?
match_phrase requires the terms to appear in the exact order with no gaps:
// Only matches documents with "quick brown fox" in that exact order
{ "match_phrase": { "description": "quick brown fox" } }
// Matches "quick brown fox", "fox quick brown", "quick and brown fox"
{ "match": { "description": "quick brown fox" } }
Use match_phrase_prefix for autocomplete (e.g., "quick br" matches "quick brown").
16. What is a nested query and when is it needed?
When you have an array of objects in a document, Elasticsearch flattens them by default, losing object boundaries. Use nested type + nested query to query object arrays correctly.
// Problem: without nested, cross-object matches happen
// "Alice" + 30 might match a doc where Alice is 25 and Bob is 30
// Mapping
"comments": {
"type": "nested",
"properties": {
"author": { "type": "keyword" },
"score": { "type": "integer" }
}
}
// Query
{
"nested": {
"path": "comments",
"query": {
"bool": {
"must": [
{ "term": { "comments.author": "Alice" } },
{ "range": { "comments.score": { "gte": 4 } } }
]
}
}
}
}
Aggregations
17. What are the three types of aggregations in Elasticsearch?
| Type | Description | Examples |
|---|---|---|
| Bucket | Group documents into buckets | terms, range, date_histogram, filters |
| Metric | Compute a single metric over a set | avg, sum, min, max, cardinality, stats |
| Pipeline | Compute over the output of other aggregations | avg_bucket, derivative, moving_avg |
18. How do you write a terms aggregation with a sub-aggregation?
GET /orders/_search
{
"size": 0,
"aggs": {
"by_category": {
"terms": { "field": "category", "size": 10 },
"aggs": {
"avg_price": { "avg": { "field": "price" } },
"total_revenue": { "sum": { "field": "price" } }
}
}
}
}
"size": 0 — skip returning documents (only return aggregation results).
19. What is a date_histogram aggregation?
Groups documents by time intervals — essential for time-series analysis (e.g., logs, metrics):
GET /logs/_search
{
"size": 0,
"aggs": {
"by_hour": {
"date_histogram": {
"field": "@timestamp",
"calendar_interval": "1h"
},
"aggs": {
"error_count": {
"filter": { "term": { "level": "ERROR" } }
}
}
}
}
}
20. What is the cardinality aggregation and what should you know about its accuracy?
cardinality returns an approximate count of distinct values using the HyperLogLog++ algorithm:
{ "cardinality": { "field": "user_id" } }
- Default precision: ~1% error
- Exact count is expensive at scale; approximate is acceptable for dashboards
- Tune with
precision_threshold(0–40000) — higher = more memory but more accurate
Performance
21. How do you optimise Elasticsearch for bulk indexing?
| Technique | Effect |
|---|---|
| Use Bulk API (batch 1000–5000 docs) | Reduces network overhead |
Set refresh_interval: -1 during load |
Disables refresh; ~2× speed |
Increase number_of_replicas: 0 during load |
No replica writes during load |
Increase index.translog.durability: async |
Faster writes (risk: data loss on crash) |
Tune thread pool: bulk queue |
Prevent rejections |
# Bulk API example
curl -X POST "http://localhost:9200/_bulk" -H "Content-Type: application/json" -d '
{"index": {"_index": "products", "_id": "1"}}
{"name": "Widget A", "price": 9.99}
{"index": {"_index": "products", "_id": "2"}}
{"name": "Widget B", "price": 14.99}
'
22. How should you choose the number of shards?
Too few: Can't scale horizontally.
Too many: Overhead per shard (memory, CPU); query fan-out cost.
| Guideline | Recommendation |
|---|---|
| Shard size | 10–50 GB per shard |
| For search-heavy workloads | 20–40 GB |
| For log/time-series (ILM) | 30–50 GB |
| Shards per node | < 20 per GB of heap |
| Replicas | 1+ for production |
Once an index is created, you cannot change number_of_shards without reindexing.
23. What is the query cache and request cache?
| Cache | Caches | Invalidated when |
|---|---|---|
| Node query cache | Filter results (bitsets) | Index changes |
| Shard request cache | Aggregation results for size: 0 queries |
Segment refresh |
| Field data cache | text field aggregations (fielddata=true) |
Eviction by LRU |
// Check cache stats
GET /_nodes/stats/indices/query_cache
24. What is a force merge and when should you use it?
force merge reduces the number of Lucene segments in a shard, improving search performance and reclaiming disk space from deleted documents.
POST /my-index/_forcemerge?max_num_segments=1
Use only on read-only indices (e.g., historical time-series shards). Force merging an actively written index causes I/O storms.
25. What is Index Lifecycle Management (ILM)?
ILM automatically manages time-series indices through phases:
| Phase | Action |
|---|---|
| Hot | Active writes + reads, force merge to optimize |
| Warm | Read-only, reduce replicas, move to slower hardware |
| Cold | Infrequent reads, searchable snapshots |
| Frozen | Very infrequent, minimal resources (search on demand) |
| Delete | Remove index after retention period |
PUT /_ilm/policy/logs-policy
{
"policy": {
"phases": {
"hot": { "min_age": "0ms", "actions": { "rollover": { "max_size": "50gb" } } },
"warm": { "min_age": "7d", "actions": { "shrink": { "number_of_shards": 1 } } },
"delete": { "min_age": "30d", "actions": { "delete": {} } }
}
}
}
Cluster Management
26. What are node roles in Elasticsearch?
| Role | Description |
|---|---|
master |
Manages cluster state (index creation, shard allocation) |
data |
Stores shards, handles CRUD and search |
data_hot/warm/cold/frozen |
Tiered storage roles |
ingest |
Runs ingest pipelines before indexing |
coordinating |
Routes requests; no data stored |
ml |
Runs machine learning jobs |
remote_cluster_client |
Joins remote clusters for cross-cluster search |
For large clusters, dedicate separate nodes to master and data roles to avoid resource contention.
27. What is cluster health and what do the states mean?
GET /_cluster/health
| Status | Meaning |
|---|---|
| Green | All primary and replica shards are active |
| Yellow | All primary shards active; some replicas unassigned |
| Red | Some primary shards are unassigned (data unavailable) |
A single-node cluster with replicas is always yellow (no other node to assign replicas to).
28. How do you take and restore a snapshot?
// 1. Register a repository (S3)
PUT /_snapshot/my-s3-repo
{
"type": "s3",
"settings": { "bucket": "my-elasticsearch-backups" }
}
// 2. Take a snapshot
PUT /_snapshot/my-s3-repo/snapshot-2025-01-15
// 3. Monitor snapshot progress
GET /_snapshot/my-s3-repo/snapshot-2025-01-15
// 4. Restore
POST /_snapshot/my-s3-repo/snapshot-2025-01-15/_restore
{
"indices": "products",
"rename_pattern": "(.+)",
"rename_replacement": "restored-$1"
}
29. What is shard allocation and how can you control it?
Elasticsearch automatically allocates shards across nodes. You can influence allocation with:
// Exclude a node from receiving new shards (e.g., for decommissioning)
PUT /_cluster/settings
{
"transient": {
"cluster.routing.allocation.exclude._name": "node-3"
}
}
// Require shards to be on nodes with a specific attribute
PUT /my-index/_settings
{
"index.routing.allocation.require.data_tier": "hot"
}
30. What is a split brain problem and how does Elasticsearch prevent it?
Split brain occurs when a network partition causes two parts of the cluster to each elect their own master, resulting in data divergence.
Elasticsearch prevents it with:
discovery.zen.minimum_master_nodes(ES 6-): set to(master_eligible_nodes / 2) + 1- ES 7+: automatic quorum via
cluster.initial_master_nodes— nodes vote; majority wins
Always deploy an odd number of master-eligible nodes (3 or 5) to ensure a clear quorum.
Text Analysis
31. What is an analyzer and what are its components?
An analyzer processes text during indexing and querying. It consists of:
- Character filters — pre-process raw text (e.g., strip HTML, replace chars)
- Tokenizer — splits text into tokens (e.g.,
standard,whitespace,pattern) - Token filters — transform tokens (e.g.,
lowercase,stop,stemmer,synonym)
// Custom analyzer
PUT /my-index
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"type": "custom",
"char_filter": ["html_strip"],
"tokenizer": "standard",
"filter": ["lowercase", "stop", "porter_stem"]
}
}
}
}
}
// Test the analyzer
POST /my-index/_analyze
{
"analyzer": "my_analyzer",
"text": "<p>The Quick Brown Foxes jumped!</p>"
}
// Tokens: ["quick", "brown", "fox", "jump"]
32. What is stemming and why is it used?
Stemming reduces words to their root form so that morphological variants match:
- "jumping", "jumped", "jumps" → "jump"
- "running", "runner", "runs" → "run"
Common stemmers: porter_stem (English), snowball (multi-language), kstem (less aggressive).
{ "filter": { "my_stemmer": { "type": "stemmer", "language": "english" } } }
33. What is the difference between standard, whitespace, and keyword tokenizers?
| Tokenizer | Splits on | Lowercases | Example: "Hello World!" |
|---|---|---|---|
standard |
Word boundaries, punctuation | Yes | ["hello", "world"] |
whitespace |
Spaces only | No | ["Hello", "World!"] |
keyword |
No splitting | No | ["Hello World!"] |
34. What are synonyms and how do you configure them?
// Synonym token filter
{
"settings": {
"analysis": {
"filter": {
"synonym_filter": {
"type": "synonym",
"synonyms": [
"laptop, notebook => laptop",
"tv, television, telly"
]
}
},
"analyzer": {
"search_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase", "synonym_filter"]
}
}
}
}
}
Apply synonyms only at search time (not index time) to allow synonym updates without reindexing.
35. What is the _analyze API and when do you use it?
The _analyze API lets you debug how text is processed by an analyzer:
GET /_analyze
{
"analyzer": "english",
"text": "Running quickly through the forest"
}
// Returns tokens with type and position info
// ["run", "quick", "forest"] (stop words removed, stemmed)
Use it when queries don't return expected results — to verify that indexing and querying produce the same tokens.
Advanced Topics
36. What is a function_score query?
function_score modifies the relevance score of documents using custom functions:
{
"function_score": {
"query": { "match": { "name": "keyboard" } },
"functions": [
{
"filter": { "term": { "featured": true } },
"weight": 3
},
{
"field_value_factor": {
"field": "rating",
"factor": 1.5,
"modifier": "log1p"
}
}
],
"score_mode": "sum",
"boost_mode": "multiply"
}
}
Common functions: weight, field_value_factor, random_score, decay (gauss/linear/exp for geo/date proximity).
37. What are ingest pipelines?
Ingest pipelines pre-process documents before indexing:
PUT /_ingest/pipeline/log-pipeline
{
"processors": [
{ "grok": {
"field": "message",
"patterns": ["%{IP:client} %{WORD:method} %{URIPATHPARAM:path}"]
}
},
{ "date": {
"field": "timestamp",
"formats": ["yyyy-MM-dd HH:mm:ss"]
}
},
{ "remove": { "field": "message" } }
]
}
// Apply to index
PUT /logs/_doc/1?pipeline=log-pipeline
{ "message": "192.168.1.1 GET /api/products", "timestamp": "2025-01-15 10:30:00" }
38. What is a percolator?
A percolator indexes queries and matches incoming documents against them — the reverse of normal search.
Use case: real-time alerts ("notify me whenever a product matching my criteria is added").
// Index a percolator query (a stored "query")
PUT /alerts/_doc/1
{
"query": {
"bool": {
"must": [
{ "term": { "category": "laptop" } },
{ "range": { "price": { "lte": 1000 } } }
]
}
}
}
// Percolate a new product document
GET /alerts/_search
{
"query": {
"percolate": {
"field": "query",
"document": { "category": "laptop", "price": 899 }
}
}
}
39. What is cross-cluster search (CCS)?
CCS allows a single query to span multiple Elasticsearch clusters — useful for searching across environments or geographic regions:
// Configure remote cluster
PUT /_cluster/settings
{
"persistent": {
"cluster.remote.eu-cluster.seeds": ["eu-node1:9300"]
}
}
// Search across clusters
GET /eu-cluster:products,products/_search
{ "query": { "match_all": {} } }
40. What is k-nearest neighbour (kNN) search in Elasticsearch?
Since Elasticsearch 8.0, you can index vector embeddings and perform semantic/similarity search using kNN:
// Mapping with dense_vector
PUT /articles
{
"mappings": {
"properties": {
"title": { "type": "text" },
"embedding": { "type": "dense_vector", "dims": 768, "index": true, "similarity": "cosine" }
}
}
}
// kNN search
GET /articles/_search
{
"knn": {
"field": "embedding",
"query_vector": [0.12, 0.34, ...],
"k": 10,
"num_candidates": 100
}
}
Use with models from _inference API or external embedding models (OpenAI, Sentence Transformers).
Security & Monitoring
41. What authentication and authorisation options does Elasticsearch offer?
| Feature | Description |
|---|---|
| Native realm | Username/password stored in Elasticsearch |
| LDAP/AD realm | Authenticate against Active Directory |
| PKI realm | X.509 certificates |
| OIDC/SAML | SSO integration |
| API keys | For service-to-service authentication |
| Role-based access control (RBAC) | Fine-grained index/field/document level permissions |
# Create a user with a role
POST /_security/user/app-user
{
"password": "s3cureP@ss!",
"roles": ["read_products"]
}
# Create a role
POST /_security/role/read_products
{
"indices": [{
"names": ["products"],
"privileges": ["read"]
}]
}
42. What is document-level and field-level security?
POST /_security/role/restricted_user
{
"indices": [{
"names": ["orders"],
"privileges": ["read"],
"query": "{\"term\": {\"user_id\": \"{{_user.username}}\"}}", // DLS: only own orders
"field_security": { "grant": ["order_id", "total", "status"] } // FLS: specific fields only
}]
}
43. What key Elasticsearch metrics should you monitor?
| Metric | Why it matters |
|---|---|
| Cluster health | Green/yellow/red status |
| JVM heap used % | > 75% = GC pressure; > 85% = critical |
| GC pause time | Long pauses cause latency spikes |
| Search latency (p99) | User-facing performance |
| Indexing rate | Throughput indicator |
| Rejected threads | Thread pool saturation |
| Disk usage | Shard allocation stops at 90% |
| Unassigned shards | Indicates allocation problems |
# Check cluster stats
GET /_cluster/stats
# Node stats
GET /_nodes/stats
# Index stats
GET /my-index/_stats
44. What are common causes of OutOfMemoryError (OOM) in Elasticsearch?
- Fielddata on text fields — unbounded memory for aggregations on unanalysed text
- Too many shards — each shard has per-shard overhead (~1–5 MB heap)
- Deep pagination with
from + size— loads all results into memory - Large aggregations —
termswith unboundedsize - Wildcard queries (
*foo*) — expand to many terms
Solutions: Use keyword fields for aggregations, limit shard count, use search_after for pagination, set circuit_breaker limits.
Practical Questions
45. How do you implement pagination in Elasticsearch?
| Method | Use case | Limitation |
|---|---|---|
from + size |
Simple, small datasets | Max 10,000 docs (index.max_result_window) |
search_after |
Deep pagination, real-time | Requires sort on unique field |
scroll API |
Export all docs, batch processing | Deprecated in 7.10+ for deep pagination |
Point in Time (PIT) + search_after |
Consistent pagination on live index | Recommended since ES 7.10 |
// Step 1: Open a PIT
POST /products/_pit?keep_alive=1m
// Step 2: Search with PIT + search_after
GET /_search
{
"size": 10,
"query": { "match_all": {} },
"sort": [{ "price": "asc" }, { "_id": "asc" }],
"pit": { "id": "<pit_id>", "keep_alive": "1m" },
"search_after": [149.99, "abc123"]
}
46. How do you handle multi-language search?
// Per-language fields
{
"mappings": {
"properties": {
"title_en": { "type": "text", "analyzer": "english" },
"title_fr": { "type": "text", "analyzer": "french" },
"title_de": { "type": "text", "analyzer": "german" }
}
}
}
// Search the right field based on user language
{
"match": { "title_en": "quick brown fox" }
}
Alternative: separate indices per language with an alias (products → products-en, products-fr).
47. How do you implement autocomplete (search-as-you-type)?
Two approaches:
1. search_as_you_type field type (built-in):
"title": {
"type": "search_as_you_type"
}
// Query
{ "multi_match": { "query": "mec key", "type": "bool_prefix", "fields": ["title", "title._2gram", "title._3gram"] } }
2. completion suggester (fast, purpose-built):
"suggest": { "type": "completion" }
// Query
{ "suggest": { "title-suggest": { "prefix": "mec", "completion": { "field": "suggest" } } } }
48. What is the difference between Elasticsearch, OpenSearch, and Solr?
| Feature | Elasticsearch | OpenSearch | Solr |
|---|---|---|---|
| Origin | Elastic (commercial) | AWS fork of ES 7.10 | Apache Lucene project |
| Licence | SSPL (7.11+) / Elastic Licence | Apache 2.0 | Apache 2.0 |
| Query syntax | JSON DSL | JSON DSL (compatible) | Solr Query / JSON |
| Aggregations | Rich | Same as ES | Less flexible |
| ML / vector search | Yes (native) | Yes (k-NN plugin) | Yes (via contrib) |
| Managed service | Elastic Cloud | Amazon OpenSearch Service | None (self-hosted) |
49. What are common anti-patterns in Elasticsearch?
| Anti-pattern | Problem | Fix |
|---|---|---|
| Many small shards | Per-shard overhead; slow queries | Target 10–50 GB per shard |
from + size deep pagination |
Memory exhaustion | Use search_after + PIT |
| Storing all data in one giant index | Hot spot; hard to manage lifecycle | Use time-based indices + ILM |
fielddata: true on text fields |
Heap exhaustion | Use keyword for aggregations |
Wildcard prefix queries (*foo) |
Full segment scan | Use edge_ngram tokenizer |
Not setting number_of_replicas: 0 during bulk load |
Slow indexing | Set replicas to 0, restore after |
| Ignoring JVM heap | OOM errors | Set heap to 50% of RAM, max 26 GB |
Using _all field (removed in ES 6+) |
Unnecessary indexing | Use multi_match across specific fields |
50. How would you design an Elasticsearch setup for a high-traffic e-commerce search?
Architecture:
- 3 dedicated master-eligible nodes (no data)
- 6+ data nodes (hot tier: NVMe SSDs)
- Warm/cold tiers for historical data (cheaper storage)
- Coordinating-only nodes behind a load balancer
Index design:
- One index per product catalogue
- Separate
activity_logsindex with ILM (30-day retention) - Explicit mappings with
keywordfor facets,textfor full-text - Per-language analysers for international sites
Query strategy:
boolwithfilterfor facets (cached),mustfor full-textfunction_scoreto boost featured products, high-rated itemssearch_after+ PIT for paginated resultsdate_histogram+termsaggregations for facet counts
Performance:
- Enable
_source: falseor include/exclude fields to reduce response size - Cache warm popular queries using
request_cache - ILM to manage old product data
- Circuit breakers configured to prevent OOM
Comparison table
| Feature | Elasticsearch | PostgreSQL FTS | MongoDB Atlas Search | Redis Search |
|---|---|---|---|---|
| Full-text search | Excellent | Good | Good | Good |
| Aggregations | Excellent | Limited | Good | Limited |
| Scalability | Horizontal (shards) | Vertical | Horizontal | Horizontal |
| Near-real-time | Yes (1s refresh) | Yes (live) | Yes | Yes |
| Vector search | Yes (kNN, ES 8+) | Yes (pgvector) | Yes | Yes |
| Operational complexity | High | Low | Low (managed) | Low |
| Best for | Dedicated search | Existing Postgres app | MongoDB apps | Low-latency cache |
Common mistakes
| Mistake | Consequence | Fix |
|---|---|---|
| Not planning shard count upfront | Can't change without reindex | Estimate data size; target 10–50 GB/shard |
| Dynamic mapping on user-generated data | Mapping explosion | Use dynamic: strict, explicit mappings |
Using text fields for aggregations |
OOM / errors | Use keyword sub-field |
| Ignoring JVM heap | OOM crashes | Set to 50% RAM, max 26 GB |
Deep pagination with from + size |
Memory exhaustion | Use search_after + PIT |
Not using filter context for non-scoring queries |
Slower queries | Wrap exact matches in filter |
| Force merging active indices | I/O storm | Only force merge read-only/historical shards |
| No ILM for log indices | Unbounded disk usage | Set up rollover + delete policies |
FAQ
Can I change a field's mapping after creation?
No. You must create a new index with the correct mapping and reindex data using the _reindex API. Use index aliases to make the switch seamless.
What is the difference between ES 7 and ES 8?
ES 8 introduced: kNN vector search (dense_vector as first-class), security enabled by default (TLS + auth), removal of types (already deprecated in 7), improved NLP/ML features, and new Elastic inference API.
How does Elasticsearch compare to a relational database for search?
Elasticsearch is optimised for full-text search (inverted index, relevance scoring, aggregations), while relational databases are optimised for transactional integrity (ACID, joins, foreign keys). Use Elasticsearch as a search layer on top of your primary database, not as a replacement.
What is the recommended JVM heap size?
Set to 50% of available RAM, capped at 26–30 GB. Beyond 26 GB, the JVM switches from compressed oops (8-byte pointers) to full 64-bit pointers — effectively wasting memory. More heap goes to OS file cache, which benefits Lucene segment access.
How do you handle zero-downtime reindexing?
- Create new index with correct mapping
- Start
_reindexin the background - Continue writing to the old index + new index (dual-write)
- Once reindex catches up, switch alias to the new index
- Stop dual-write, verify, delete old index
What is a coordinating-only node?
A node with no data, master, or ingest roles. It receives client requests, distributes them to the right data nodes (scatter phase), and merges results (gather phase). Useful for offloading coordination overhead from data nodes in large clusters.