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.

Intermediate100–120 minutesSchema evolution labElasticsearch 9.5.3 · OpenSearch 3.8.0Last reviewed: September 2026

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.

01

Distinguish additive mapping updates from incompatible field changes that require a new index generation.

02

Create and simulate a v2 template/index before moving any production alias.

03

Explain why reindex alone is not zero-downtime when source writes continue and choose a write-coordination strategy.

04

Validate counts, rejected documents, representative search/aggregation behavior and freshness before alias cutover.

05

Perform an atomic read/write alias switch and demonstrate rollback without deleting the previous generation.

Chapter baseline reviewed 11 September 2026

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.

Execution and safety note

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

Dev Tools · v2 artifact and destination
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

Dev Tools · one-time v1 aliases
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

Dev Tools · deterministic lab reindex under a short write pause
# 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.”

Wrong approach

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

Migration acceptance evidence
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

Dev Tools · cut over read + write aliases
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.

Dev Tools · rollback while v1 is retained
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

Disposable-course cleanup · after validation
# 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

  1. Why can’t changing the index template fix an incompatible field in an existing index?
  2. Why is reindex not by itself a zero-downtime migration protocol?
  3. What does equal document count fail to prove?
  4. Why keep v1 after cutover?
  5. 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

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.