Chapter 09 · Dynamic Templates, Index Templates, Component Templates, and Schema Evolution
Changing Mappings Safely: Additive Changes, New Indices, Reindex, Alias Cutover, and Rollback
Separate additive mapping changes from incompatible changes, build a new generation, reindex under controlled writes, validate it, switch aliases atomically, and retain a tested rollback path.
Learning outcomes
AtlasMart decides that a field needs incompatible search semantics in the next generation. Updating a template is not enough, and an existing field type generally cannot be rewritten in place. The safe unit of change is a new physical index generation with explicit write coordination, reindex validation, atomic alias switch, observation window and rollback.
Distinguish additive mapping updates from incompatible field changes that require a new index generation.
Create and simulate a v2 template/index before moving any production alias.
Explain why reindex alone is not zero-downtime when source writes continue and choose a write-coordination strategy.
Validate counts, rejected documents, representative search/aggregation behavior and freshness before alias cutover.
Perform an atomic read/write alias switch and demonstrate rollback without deleting the previous generation.
The reproducible examples target self-managed Elasticsearch
9.5.3 and OpenSearch 3.8.0 using the existing AtlasMart
local-course conventions: Elasticsearch on
https://localhost:9200 with its copied CA certificate,
OpenSearch on https://localhost:9201 with the disposable demo
certificate explicitly treated as local-only, and no moving
latest tags. Template and mapping syntax is verified against
current official documentation. Both products support
create-new-index + reindex + aliases as the portable migration
pattern. Exact task/throttling/remote-reindex options differ;
this lab uses only a local source and destination. Reindex
requires readable _source and does not itself
solve writes that arrive after the source snapshot is taken.
The generation environment does not run the two search servers, so commands are specified as deterministic labs and expected invariants rather than represented as captured live output. Run them only against the disposable AtlasMart course indices/templates, record the actual API responses from your pinned versions, and never test alias cutover or destructive cleanup against production names.
1. Additive versus incompatible changes
| Change | Typical treatment | Why |
|---|---|---|
| Add a new field | Update mapping or include it in future template | Existing indexed fields are not reinterpreted. |
| Add a multi-field where supported | Supported mapping update; verify old documents/search semantics | Old terms are not magically backfilled for every kind of mapping change; test actual behavior. |
| Change keyword to numeric/date/text | New index + reindex | Existing indexed structures are incompatible with the new type. |
| Change analyzer used at index time | New index + reindex | Already-indexed token streams do not change. |
| Rename a logical field | Field alias can help some read compatibility; physical rename needs reindex | Stored/indexed field identity already exists in old segments. |
| Change shard count arbitrarily | Use supported resize/new-index strategy | Primary shard topology is a physical index property. |
2. Build generation 2 before touching aliases
PUT _component_template/atlasmart-products-mappings-v2
{
"version": 2,
"_meta":{"owner":"search-platform","schema":"atlasmart-products","generation":2},
"template": {
"mappings": {
"dynamic":"strict",
"properties": {
"product_id":{"type":"keyword"},
"name":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},
"category":{"type":"keyword"},
"price":{"type":"scaled_float","scaling_factor":100},
"available":{"type":"boolean"},
"updated_at":{"type":"date"},
"merchant_sku":{"type":"keyword"},
"rating":{"type":"half_float"}
}
}
}
}
PUT _index_template/atlasmart-products-template-v2
{
"index_patterns":["atlasmart-products-v2-*"] ,
"priority": 210,
"version": 2,
"_meta":{"owner":"search-platform","schema":"atlasmart-products","generation":2},
"composed_of":["atlasmart-products-settings-v1","atlasmart-products-mappings-v2"]
}
POST _index_template/_simulate_index/atlasmart-products-v2-000001
PUT atlasmart-products-v2-000001
Create a disposable canary document in v2 and exercise the queries/facets the application needs. The new index must be able to serve traffic before migration begins. Do not let “reindex task completed” be the first time the new mapping is queried.
3. Establish a v1 alias contract
POST _aliases
{
"actions": [
{"add":{"index":"atlasmart-products-v1-000001","alias":"atlasmart-products-read"}},
{"add":{"index":"atlasmart-products-v1-000001","alias":"atlasmart-products-write","is_write_index":true}}
]
}
GET _alias/atlasmart-products-read
GET _alias/atlasmart-products-write
Applications should use stable aliases rather than physical
generation names. The write alias makes the intended write
target explicit. If multiple indices share a write alias,
understand and test is_write_index behavior rather
than relying on accidental single-index state.
4. Reindex is a snapshot copy, not a concurrency protocol
# LAB COORDINATION:
# 1) stop/pause AtlasMart writes to atlasmart-products-write
# 2) record source count and max updated_at/event sequence
POST _reindex?wait_for_completion=true
{
"source":{"index":"atlasmart-products-v1-000001"},
"dest":{"index":"atlasmart-products-v2-000001","op_type":"create"}
}
GET atlasmart-products-v1-000001/_count
GET atlasmart-products-v2-000001/_count
GET atlasmart-products-v2-000001/_mapping
In production, a long reindex cannot simply pause writes for hours. Choose one of: dual-write both generations, replay an authoritative change log/CDC stream after the bulk copy, or take a bounded write pause only for the final delta/cutover. The correctness contract is “every accepted source write appears exactly once in the new generation with the intended final value,” not merely “reindex reported no failures.”
Start a multi-hour reindex while writes continue, compare counts once, switch the alias, then delete v1. Documents created/updated after the reindex snapshot or during validation can be missing/stale in v2. Reindex is data movement, not a write-fencing protocol.
5. Validate semantics, not just counts
Required evidence before cutover:
- reindex failures == 0 (or every failure classified/resolved)
- source count == destination count for the frozen/reconciled boundary
- deterministic IDs match expected set
- representative GET/search/filter/facet tests pass
- mapping and field_caps match v2 contract
- relevance regression suite within agreed threshold
- p95/p99 latency measured separately on representative load
- no unexpected shard failures
- destination freshness boundary >= final source write boundary
- rollback generation remains intact and readable
Equal counts do not prove equal content, and equal content does not prove equivalent search semantics. If the mapping/analyzer changed intentionally, compare against v2 expectations rather than demanding identical scores. Preserve the migration report with source/destination generation identifiers.
6. Atomic alias cutover and explicit rollback
POST _aliases
{
"actions": [
{"remove":{"index":"atlasmart-products-v1-000001","alias":"atlasmart-products-read"}},
{"add":{"index":"atlasmart-products-v2-000001","alias":"atlasmart-products-read"}},
{"remove":{"index":"atlasmart-products-v1-000001","alias":"atlasmart-products-write"}},
{"add":{"index":"atlasmart-products-v2-000001","alias":"atlasmart-products-write","is_write_index":true}}
]
}
Issue the multi-action alias update as one management operation so clients never observe the intentionally removed intermediate alias state. Immediately re-read alias state and run smoke queries through the aliases, not the physical v2 index.
POST _aliases
{
"actions": [
{"remove":{"index":"atlasmart-products-v2-000001","alias":"atlasmart-products-read"}},
{"add":{"index":"atlasmart-products-v1-000001","alias":"atlasmart-products-read"}},
{"remove":{"index":"atlasmart-products-v2-000001","alias":"atlasmart-products-write"}},
{"add":{"index":"atlasmart-products-v1-000001","alias":"atlasmart-products-write","is_write_index":true}}
]
}
A rollback is only safe if data written after cutover is reconciled. For the deterministic lab, writes remain paused until smoke tests pass, so rollback has no forward-write delta. In production, define how writes made to v2 during the observation window are replayed back or why rollback is read-only.
7. Cleanup only after the rollback window
# Inspect first; then remove only the Chapter 09 lab artifacts you created.
GET _alias/atlasmart-products-read
GET _alias/atlasmart-products-write
# Do not delete v1 immediately after cutover.
# Retain it through the documented rollback window and snapshot policy.
Check your understanding
- Why can’t changing the index template fix an incompatible field in an existing index?
- Why is reindex not by itself a zero-downtime migration protocol?
- What does equal document count fail to prove?
- Why keep v1 after cutover?
- What must rollback consider after production writes have reached v2?
Review the answers
1. Templates affect new index creation; existing indexed structures keep their current mapping/type.
2. It copies a source snapshot and does not coordinate later concurrent writes; you need dual-write, CDC/replay, or a bounded write fence.
3. Field-level equality, freshness, no duplicates/stale versions, and correct search/relevance semantics.
4. It is the rollback target and evidence source until the observation/reconciliation window closes.
5. Those writes need a reconciliation strategy; alias reversal alone can lose newer accepted data.
Production judgment
Estimate migration duration and recovery headroom before starting. Reindex consumes search/indexing CPU, IO and shard resources; throttle/sequence migrations based on measured cluster capacity rather than folklore. Snapshot policy and rollback retention must account for compliance and storage cost. Restrict alias/template/reindex privileges because a technically valid request can redirect or duplicate application traffic.
Summary and next step
You can now evolve an incompatible mapping using a new generation, controlled writes, semantic validation, alias cutover and rollback. The final lesson turns those steps into a repeatable schema-deployment workflow with automated template tests and promotion gates.
Authoritative references
- Elastic mapping overview — Dynamic versus explicit mapping and schema-management guidance.
- Elastic dynamic field mapping — Detection rules, dynamic modes, date detection and numeric detection.
- Elastic dynamic templates — match/path/type conditions, template variables, ordering and runtime-field options.
- Elastic templates — Composable index/component templates, precedence, priority and reusable configuration.
- Elastic simulate index template API — Dry-run composition and overlapping-template evidence.
- Elastic simulate index API — Resolve the configuration that a concrete index name would receive.
- Elastic update mapping examples — Why incompatible field-type changes require a new index and reindex.
- Elastic aliases — Index aliases, write-index behavior and no-downtime reindex patterns.
- OpenSearch mappings — Dynamic mapping rules and dynamic-template controls.
- OpenSearch dynamic parameter — OpenSearch-specific dynamic modes including allow-templates variants.
- OpenSearch index templates — Composable templates, priorities and component composition.
- OpenSearch component template API — Reusable settings/mappings/aliases and creation-time behavior.
- OpenSearch simulate index template API — Preview template resolution before index creation.
- OpenSearch reindex API — Source snapshot behavior and destination-index requirements.
- OpenSearch alias API — Alias creation/update APIs and the distinction from manage-alias actions.