index.merge.policy.segments_per_tier is a per-index setting that tunes Lucene's TieredMergePolicy. It controls how many segments are allowed in each size tier before the policy schedules a merge. Lower values mean more aggressive merging - fewer segments, faster search, more write amplification. Higher values mean lazier merging - more segments, slower search, less indexing overhead. The setting is one of the more nuanced merge tuning knobs and rarely needs adjustment for typical workloads.
- Default:
10 - Scope: Per-index, dynamic - update via the update settings API
- Possible values: Any value ≥ 2 (and ≥
index.merge.policy.floor_segment-related constraints)
How segments_per_tier Works
Lucene's tiered merge policy groups segments into size tiers and merges them when a tier has too many. segments_per_tier sets the per-tier threshold. A value of 10 means each tier can hold roughly 10 segments before a merge fires. The total segment count on an index is approximately segments_per_tier * log(total_size / floor_segment).
Lower values force more frequent merges, keeping search-time segment count low. The trade-off is write amplification: each byte written may be re-written several times as small segments are merged into bigger ones.
Configuring segments_per_tier
Update dynamically:
PUT /my_index/_settings
{
"index": {
"merge.policy.segments_per_tier": 8
}
}
Apply to new indices via index templates so existing indices aren't affected without intent.
Tuning Guidance
| Workload | Recommendation |
|---|---|
| Mixed read/write, default Elasticsearch use | Leave at 10 |
| Read-heavy (search-dominated) | 4-8 - fewer segments, faster search |
| Write-heavy, append-only logs | 12-20 - reduce merge overhead |
| Time-series with rollover | Default, but force-merge to 1 segment after rollover |
| Bulk reindex into a new index | Raise to 24+ during reindex, then force-merge |
After raising the setting, the index will gradually drift toward a higher segment count. Lowering it triggers extra merges immediately.
Related Merge Policy Settings
| Setting | Default | Purpose |
|---|---|---|
index.merge.policy.max_merge_at_once |
10 | Max segments combined in one normal merge |
index.merge.policy.max_merged_segment |
5gb |
Cap on segment size produced by merging |
index.merge.policy.floor_segment |
2mb |
Segments below this are treated as equal size when tiering |
index.merge.scheduler.max_thread_count |
max(1, processors/2) |
Concurrent merge threads |
Tuning segments_per_tier alone usually under-delivers. Pair changes with max_merged_segment (if you want fewer large segments) and the scheduler thread count (if merges are CPU-bound).
Common Pitfalls
- Lowering
segments_per_tierwhile ingestion rate is high. The cluster falls behind on merges and indexing throughput drops sharply. - Raising it without monitoring segment count. Search latency creeps up because every query consults more segments.
- Comparing segment count across very different shard sizes. A 50 GB shard at
segments_per_tier: 10will have far more segments than a 5 GB one - that's expected. - Treating the setting as a substitute for
force_merge. Force-merge is the right tool for end-of-life indices that should be compacted permanently.
Monitoring Merge Behavior
Useful APIs:
GET /_cat/segments/my_index?v&s=index,segment&h=segment,size,docs.count,merge
GET /_nodes/stats/indices/merges
GET /_cat/recovery
Watch for:
- Total segment count per shard creeping up over time
- Merge throttle time (
indices.merges.total_throttled_time_in_millis) - Search latency p95 correlation with segment count
Prevent segments_per_tier Misconfiguration with Pulse
Pulse is an AI DBA for Elasticsearch and OpenSearch that tracks index.merge.policy.segments_per_tier (default 10) along with max_merged_segment (default 5gb), floor_segment (default 2mb), and merge scheduler thread count, flagging:
- Drift between template intent and actual per-index settings, especially after
PUT /<index>/_settingscalls that override templates - Settings that are unsafe for your workload (e.g. lowered to 4 on a write-heavy index causing merge throttling, or raised to 24 during a reindex and never restored)
- The downstream operational impact: total segment count per shard, merge throttle time (
indices.merges.total_throttled_time_in_millis), and the search latency p95 correlation with segment count
When merge backpressure starts producing write rejections, Pulse names the index, the tier ratio, and the segments_per_tier value behind it - so operators discover merge problems while they are still tunable, not after they cause indexing rejections.
Frequently Asked Questions
Q: What is the default value of index.merge.policy.segments_per_tier?
A: The default is 10. Lucene's tiered merge policy tolerates approximately 10 segments per size tier before scheduling a merge. The setting can be lowered for search-heavy indices or raised for ingest-heavy ones.
Q: How does segments_per_tier affect indexing performance?
A: Lower values mean more frequent merges, which use more CPU and IO and amplify write throughput. Higher values reduce merge overhead but leave more segments around. A doubled value roughly halves the merge cost per byte ingested.
Q: How does segments_per_tier affect search performance?
A: Each search consults every segment, so more segments mean slower searches. Halving segments_per_tier roughly halves the segment count, which can improve search latency by 10-30% for term and range queries.
Q: Can I change segments_per_tier on a live index?
A: Yes, it's a dynamic setting. New merges immediately follow the new value. Existing segments aren't re-merged unless they happen to be selected by the next merge cycle - the effect is gradual.
Q: Should I use force_merge instead of tuning segments_per_tier?
A: They solve different problems. force_merge compacts a non-changing index into a target segment count and is appropriate for rolled-over or read-only indices. segments_per_tier controls steady-state merge behavior on an actively-written index.
Q: Is segments_per_tier per-shard or per-index?
A: The setting is per-index but applies to every shard independently. A shard with more data will end up with more segments at the same threshold.
Q: What's the best tool to tune Elasticsearch merge policy and catch segment-count problems early?
A: Pulse is built for this. It is an AI DBA for Elasticsearch and OpenSearch that continuously tracks segments_per_tier, segment count per shard, merge throttle time, and the correlation with search latency, recommending merge-policy adjustments while they are still preventive rather than reactive.
Related Reading
- Elasticsearch Index Refresh Interval: Refresh frequency interacts with segment count
- Elasticsearch Forcemerge: Manual segment compaction
- Elasticsearch thread_pool.write.size Setting: Write concurrency
- Elasticsearch Slow Queries Diagnose: Search latency triage
- Elasticsearch Settings: Full settings reference