11 min read
System Design Index
Start Here
Tier 1 -- Building Blocks
Scale Reads
Scale Writes
Database Selection
Traffic Control
Consistency & Coordination
Estimation
Tier 2 -- Core Systems
Tier 3 -- Location & Real-Time
Tier 4 -- Infrastructure & Data
Tier 5 -- Finance & Commerce
Tier 6 -- Advanced & Collaborative
System Design Index
Start Here
Tier 1 -- Building Blocks
Scale Reads
Scale Writes
Database Selection
Traffic Control
Consistency & Coordination
Estimation
Tier 2 -- Core Systems
Tier 3 -- Location & Real-Time
Tier 4 -- Infrastructure & Data
Tier 5 -- Finance & Commerce
Tier 6 -- Advanced & Collaborative
Search Engine (Elasticsearch) — Full-Text Search & Inverted Index
1. What Is It?
Elasticsearch is a distributed search and analytics engine built on top of Apache Lucene. It stores data as JSON documents and indexes them using an inverted index — a data structure that maps every unique term to the list of documents containing it. This enables sub-second full-text search across billions of documents: instead of scanning documents one by one, Elasticsearch looks up a term in the inverted index once and instantly retrieves all matching document IDs.
Without Elasticsearch (or a similar search engine), teams implement "search" as SQL LIKE '%query%' — a full-table scan that scales poorly and has no concept of relevance ranking. Elasticsearch solves three problems that SQL databases cannot: (1) full-text search with linguistic analysis (stemming — reducing words to their root form, e.g. "running" → "run"; stop words — filtering out common words like "the" and "is" that don't carry search meaning; synonyms), (2) relevance scoring (which result is most relevant?), and (3) faceted/aggregated search ("show me results grouped by category with counts"). It's used for search boxes, log analytics, security , and increasingly for AI-powered semantic search via vector embeddings.
A product catalog API currently uses a SQL query with LIKE '%laptop%' to power a search endpoint. As the catalog grows to millions of rows, engineers notice the search is becoming unacceptably slow and returns results in no particular order of relevance. Which core limitation of this approach does a search engine like Elasticsearch directly address?
2. How It Works
The Inverted Index
The inverted index is the heart of Elasticsearch. When a document is indexed:
- The text is passed through an analyzer: tokenizer (split into terms) → token filters (lowercase, remove stop words, stem words: "running" → "run")
- Each resulting term is added to the inverted index with a pointer to the document
Documents:
doc1: "Elasticsearch is fast and scalable"
doc2: "Elasticsearch powers Wikipedia search"
doc3: "Fast search with inverted index"
Inverted Index (simplified):
elasticsearch → [doc1, doc2]
fast → [doc1, doc3]
scalable → [doc1]
power → [doc2] ← stemmed from "powers"
wikipedia → [doc2]
search → [doc2, doc3]
invert → [doc3] ← stemmed from "inverted"
index → [doc3]
Query "fast search" → INTERSECT lookup:
fast → [doc1, doc3]
search → [doc2, doc3]
Result: doc3 (contains both), then doc1 and doc2 (contain one each, ranked by BM25 score)
Relevance Scoring: BM25
Since Elasticsearch 5.0, the default ranking algorithm is Okapi BM25, replacing TF-IDF. BM25 scores documents higher when:
- The query term appears frequently in the document (term frequency), but with diminishing returns (term saturation)
- The document is short (length : long documents are penalized less than raw TF-IDF would suggest)
Where (term saturation, default 1.2) and (length , default 0.75) are tunable parameters.
Write / Indexing Path
An Elasticsearch index is split into shards — independent chunks of the index, each stored on a different node. Each shard is a self-contained Lucene index. Replicas are copies of each shard stored on different nodes for redundancy and read .
- Document sent via HTTP
PUT /index/_doc/idor bulk API - Document routed to correct primary shard:
shard = hash(document_id) % num_primary_shards - Document written to the translog () for
- Document added to the in-memory buffer
- On refresh (~every 1 second): in-memory buffer written to a new Lucene segment → document becomes searchable (Near Real-Time)
- On flush: translog cleared, segments written durably to disk
- Background merge: small Lucene segments merged into larger ones to reduce file handles and improve query performance
Write → Translog (durability) + Buffer (in-memory)
↓ (every 1 second)
Refresh → New Lucene segment opened for search (NRT)
↓ (periodic)
Flush → Segments written to disk, translog cleared
↓ (background)
Merge → Small segments merged into larger segments
Read / Search Path
- Query sent to any node (becomes the coordinating node)
- Coordinating node broadcasts query to all relevant shards (primary or replica)
- Each shard executes the query locally against its Lucene index, returns top-K hits with scores
- Coordinating node merges results from all shards, re-ranks by global score, returns top results
Mermaid: Architecture Overview
Mermaid: Indexing Pipeline
A backend engineer indexes the document 'Elasticsearch powers Wikipedia search' into Elasticsearch. After the analyzer processes this text, which term would appear in the inverted index as a result of stemming?
3. Variants & Comparisons
Search Engine Options
| System | Built On | Best For | Managed? |
|---|---|---|---|
| Elasticsearch | Apache Lucene | General-purpose search, log analytics, vector search | Elastic Cloud |
| OpenSearch | Elasticsearch fork (Apache 2.0) | AWS-native search, open-source governance | Amazon OpenSearch Service |
| Apache Solr | Apache Lucene | Enterprise search, batch indexing, XML-heavy enterprise | Self-hosted |
| Meilisearch | Custom Rust engine | Instant typo-tolerant search, developer-friendly | Meilisearch Cloud |
| Typesense | Custom C++ engine | Fast faceted search, developer-friendly alternative to Algolia | Typesense Cloud |
| Algolia | Proprietary | Hosted SaaS search, low-ops, e-commerce search | Fully managed SaaS |
| Vespa | Custom Java/C++ | AI-powered search, large-scale ML ranking | Self-hosted or Vespa Cloud |
Query Types in Elasticsearch
| Query Type | When to Use | Example |
|---|---|---|
match | Full-text search with analysis | User types "running shoes", stems to "run shoe" |
term | Exact value match (no analysis) | Filter by status: "active" |
range | Numeric/date range | timestamp >= 2024-01-01 |
bool | Combine multiple queries | must (AND) + should (OR) + filter (AND, no scoring) |
multi_match | Search across multiple fields | Search title and description together |
knn | Vector similarity search | Semantic search using text embeddings |
aggregations | GROUP BY equivalent | Bucket by category, compute average price |
Your team is building a product catalog search feature where users can filter results by an exact category field value (e.g., category: "electronics") AND search by free-text product descriptions. Which combination of Elasticsearch query types best fits this use case?
4. When to Use It (and When NOT To)
Use Elasticsearch When:
- Full-text search with relevance ranking: User-facing search boxes where "which result is most relevant?" matters. BM25 scoring, fuzzy matching, and linguistic analysis (stemming, synonyms) are built-in.
- Log aggregation and (ELK Stack): Ingest millions of log lines/second with Logstash, index in Elasticsearch, visualize in Kibana. At scale, this beats grep over files by orders of magnitude.
- Faceted/aggregated search: "Show me products in category X, price range Y, and count how many match each subcategory" — Elasticsearch aggregations are purpose-built for this.
- Near-real-time search on frequently changing data: Documents indexed become searchable within ~1 second. Suitable for social feeds, news, e-commerce inventory.
- Semantic / vector search: Dense vector fields + kNN (approximate nearest neighbor via HNSW) enable semantic search with text embeddings. Hybrid search combines BM25 + vector similarity.
- Multi-field search: Search across many JSON fields simultaneously with different boost weights per field.
Do NOT Use Elasticsearch When:
- Primary data store (source of truth): Elasticsearch is a search index, not a database. It lacks transactions, foreign keys, and . Data lives in your primary DB; Elasticsearch gets a copy for search.
- required: Elasticsearch is eventually consistent. During writes, shard replicas may briefly diverge. Don't query Elasticsearch for financial or inventory decisions requiring strong consistency.
- Simple key-value lookups: A
GET /users/123lookup is better served by PostgreSQL or Redis. Don't use Elasticsearch as a glorified key-value store. - Complex relational queries: JOINs in Elasticsearch are limited (nested documents or parent-child) and expensive. Use a relational database.
- Low-budget systems with sparse search traffic: Elasticsearch requires 3+ nodes for a production cluster. For a small app with occasional search, PostgreSQL's full-text search (
tsvector,tsquery) is simpler and cheaper. - Real-time ACID writes: The ~1-second NRT refresh means very recent writes aren't immediately searchable. For applications requiring instant read-your-write consistency, this is a problem.
Decision Triggers
| Constraint | Reach For |
|---|---|
| User-facing search box with relevance ranking | Elasticsearch or Algolia |
| Log analytics at scale (ELK) | Elasticsearch |
| AWS-native, open-source required | OpenSearch |
| Semantic/vector search + full-text hybrid | Elasticsearch (v8+ with kNN) |
| Developer-friendly, typo-tolerant, instant search | Typesense or Meilisearch |
| PostgreSQL team, moderate search traffic | PostgreSQL FTS (tsvector) |
| E-commerce search, fully managed SaaS | Algolia |
Your team is building a financial trading platform where users need to look up account balances and transaction records instantly after each trade executes. A colleague suggests using Elasticsearch as the primary data store to power these lookups. What is the most critical reason this would be a poor architectural choice?
5. Real-World Usage
Wikipedia → Elasticsearch (Site-Wide Search)
Wikipedia uses Elasticsearch to power its search across millions of articles in hundreds of languages. The challenge: multilingual full-text search with complex analyzers per language (different stemming rules, stopwords, character filters for non-Latin scripts), relevance ranking that considers article quality signals alongside BM25 scores, and near-real-time updates as articles are edited. Elasticsearch's per-field analysis and custom similarity plugins make this feasible.
GitHub → Elasticsearch (Code Search)
GitHub uses Elasticsearch to power its code repository search — billions of files searchable by code content, filename, language, and repository metadata. Code search requires specialized tokenizers (split on camelCase, underscores, brackets) rather than natural language analysis. GitHub has a massive deployment with strict SLAs for the search box on every repo page.
Netflix → Elasticsearch (15+ Clusters, ~800 Nodes)
Netflix's Elasticsearch deployment has grown to 15+ clusters with approximately 800 nodes, handling search and data retrieval for multiple internal and external use cases — content search, data discovery, internal tooling. Netflix's scale is a good illustration of the operational complexity of large Elasticsearch deployments: cluster upgrades, shard rebalancing, and index lifecycle management at this scale require significant investment.
A team is building a code search feature that needs to index millions of source files and allow developers to search by function names written in camelCase (e.g., getUserProfile) or with underscores (e.g., get_user_profile). Which indexing approach best addresses this requirement?
6. Interview Cheat Sheet
5 Sentences to Show Deep Understanding
-
"Elasticsearch's inverted index is the inverse of a document store: instead of mapping document IDs to their content, it maps every term to the list of documents containing it — so a search query is just a set of O(1) lookups in this map, not a full scan."
-
"BM25 replaced TF-IDF as the default scorer in Elasticsearch 5.0; the key improvement is term frequency saturation — repeated occurrences of a term yield diminishing score increases, preventing documents that spam keywords from unfairly dominating results."
-
"Elasticsearch is near-real-time, not real-time: a document becomes searchable only after the next refresh (default: every 1 second), when the in-memory buffer is written to a new Lucene segment and opened. If you need instant read-after-write, you either call a manual refresh or accept the NRT constraint."
-
"Elasticsearch is a search index, not a primary database — it's eventually consistent, lacks transactions, and can lose very recent data if nodes fail before segments are flushed. The source of truth lives in your primary DB; Elasticsearch gets a copy via change data capture or dual-write."
-
"Vector search in Elasticsearch (v8+) uses HNSW (Hierarchical Navigable Small World) graphs for approximate kNN — you store dense vector embeddings as
dense_vectorfields and query by cosine similarity. Hybrid search combines BM25 lexical scoring with vector similarity for best of both worlds."
Common Follow-Up Questions
Q: What is the / hot shard problem in Elasticsearch? A: If documents are unevenly distributed across shards (e.g., shard key correlates with a popular category), one shard receives disproportionate queries. Solution: (1) use routing with load spreading across multiple shards; (2) avoid using natural document IDs as routing keys; (3) monitor shard-level metrics and reindex with better distribution.
Q: What happens when the master node goes down? A: Elasticsearch automatically elects a new master from the master-eligible nodes. During master election, the cluster is temporarily unavailable for write operations (no shard allocation, index creation). Reads continue from existing shards. For production, run 3+ master-eligible nodes to tolerate one failure.
Q: How would you keep Elasticsearch in sync with your primary database? A: Three approaches: (1) Dual-write: application writes to DB and Elasticsearch transactionally (risk: partial failure leaves them out of sync). (2) CDC via Debezium/: stream database changes to , consume and index in Elasticsearch (, handles failures gracefully). (3) Bulk re-index on schedule: for batch workloads where NRT isn't needed. The Kafka CDC approach is most robust for production.
Q: How does Elasticsearch handle schema changes?
A: Elasticsearch uses dynamic mapping (auto-detects field types on first write) but the mapping for a field, once set, cannot be changed on existing data (e.g., you can't change a keyword field to text). Schema changes require creating a new index with updated mapping and reindexing the data — the _reindex API or aliased indices with zero-downtime reindex strategies.
Connections to Other Building Blocks
- Message Queues (Kafka): The canonical pattern for keeping Elasticsearch in sync: DB writes stream via Kafka → Elasticsearch consumer indexes the changes. Kafka provides and .
- Document Store (MongoDB/DynamoDB): Elasticsearch is often layered on top of a document store. MongoDB stores the authoritative records; Elasticsearch provides the search layer. A change stream / DynamoDB Streams feeds changes to Elasticsearch.
- Caching (Redis): Cache popular search queries. A Redis
GET query_hashcheck before hitting Elasticsearch reduces load for trending searches (e.g., "iPhone 15" on a product search on Black Friday). - & : Search results for popular queries can be cached at the edge for seconds (with a short ). Autocomplete suggestions (static-ish) can be cached aggressively.
- & : Elasticsearch shards documents across nodes. Choosing shard count is critical: too few → one large shard per node limits parallelism; too many → overhead from coordination. Rule of thumb: aim for shards of 20–50 GB.
Glossary History
Click dotted jargon to save explanations here.
Glossary History
Click dotted jargon to save explanations here.