Inventory every compatibility contract before choosing a migration mechanism.

Assess API, Mapping, Query, Security, Plugin, Snapshot, and Client Compatibility Before Migration

Turn Elasticsearch↔OpenSearch migration into an evidence-based compatibility program covering APIs, mappings, queries, clients, plugins, snapshots, security, managed-service boundaries, data sync, relevance and rollback.

Intermediate → Advanced150–200 minutesCompatibility assessment lab · Chapter 29 · Lesson 01Elasticsearch/Kibana 9.5.3 · elasticsearch-py 9.5.1 · OpenSearch/Dashboards 3.8.0 · opensearch-py 3.2.0Last reviewed: September 2026

Learning outcomes

01

Build a migration compatibility inventory that separates syntax similarity from semantic compatibility.

02

Test mappings, analyzers, query behavior, security, plugins, snapshots, and clients as independent migration surfaces.

03

Classify each feature as portable, translatable, replaceable, or blocking instead of assuming drop-in compatibility.

04

Create automated evidence for data parity, relevance, latency, authorization, and rollback readiness.

05

Explain why current Elasticsearch 9.5.3 to OpenSearch 3.8.0 migration needs explicit validation rather than a product-name shortcut.

Execution and safety note

Run mutating, destructive, security, lifecycle, snapshot, failure-injection, and load-test commands only in the disposable AtlasMart lab or an equivalently isolated environment. Verify the target cluster, index, tenant, credentials, and rollback path before execution; treat shown output as an expected invariant unless the lesson explicitly labels it as captured evidence.

Pinned migration baseline. Examples are reviewed against Elasticsearch/Kibana 9.5.3 (released 2026-09-03) and OpenSearch/OpenSearch Dashboards 3.8.0 (released 2026-08-04), using their bundled JVMs. Where application-client behavior matters, the current documented Python baselines are elasticsearch-py 9.5.1 and opensearch-py 3.2.0; the mandatory migration lab itself uses curl/HTTP plus Python 3 standard-library code so the data path is inspectable and client-neutral. The generation environment did not execute live clusters, so timing, throughput, sync-lag, and relevance values in this chapter are acceptance criteria to measure locally—not fabricated results.

1. AtlasMart problem: “the APIs look familiar” is not a migration plan

AtlasMart has accumulated catalog mappings, analyzers, Query DSL templates, an Elasticsearch API-key model, Kibana saved objects, an ILM retention policy, client retry logic, and a relevance test set. A project manager sees similar JSON syntax in OpenSearch and asks for a weekend endpoint switch. The engineering risk is not whether both products expose /_search; it is whether every behavior the application depends on still means the same thing after the move.

A compatibility program is a versioned inventory of contracts. Each contract has a source behavior, target behavior, evidence, owner, migration action, and rollback trigger. Shared historical ancestry is useful context, not a guarantee.

2. Start with seven independent compatibility surfaces

Surface Evidence to collect Typical hidden drift
REST/API request/response fixtures, error codes, defaults parameter names, defaults, deprecations, response metadata
Mappings/analysis mapping JSON, analyzer tests, token outputs field types, normalizers, vector fields, dynamic behavior
Queries/relevance golden queries, top-k IDs, NDCG/MRR/Recall scoring implementation, unsupported queries, hybrid semantics
Security identity, role, API-key, DLS/FLS negative tests privilege names, role mapping, tenant/space semantics
Plugins/features plugin inventory, API probes, feature status plugin absence, version coupling, license/subscription boundaries
Snapshots/lifecycle repository metadata, restore matrix, ILM/ISM state index-version rules, product boundary, lifecycle non-equivalence
Clients/SDKs integration tests, retry/error/auth behavior version checks, serializers, namespaces, removed APIs

3. Compatibility classification: portable is the rarest and safest label

Class Meaning AtlasMart example
Portable same intent and tested behavior with no translation basic keyword/text product fields
Translatable same business intent, different platform construct Elastic ILM retention intent → OpenSearch ISM policy
Replaceable feature is not equivalent; use a different design ES|QL workflow → PPL/SQL or Query DSL/aggregations
Blocking no acceptable target behavior within project constraints required plugin/managed feature absent on target

The classification is per version pair. A construct marked “translatable” for Elasticsearch 9.5.3 → OpenSearch 3.8.0 might change when either product version changes.

4. Inventory the exact running systems

All Chapter 29 labs preserve the established local endpoints and security assumptions: Elasticsearch 9.5.3 at https://localhost:9200 with ELASTIC_PASSWORD and the copied CA file atlasmart-es-http-ca; OpenSearch 3.8.0 at https://localhost:9201 with OPENSEARCH_INITIAL_ADMIN_PASSWORD. The shared Docker network remains atlasmart-search. OpenSearch's demo certificate trust bypass (-k) is acceptable only for this disposable local lab. The migration fixture uses one primary and zero replicas to fit a single workstation; production redundancy, recovery headroom, and managed-service networking must be designed separately.

Capture source/target version and plugin evidence
# Elasticsearch
curl --cacert atlasmart-es-http-ca -u "elastic:$ELASTIC_PASSWORD" \
  https://localhost:9200/
curl --cacert atlasmart-es-http-ca -u "elastic:$ELASTIC_PASSWORD" \
  https://localhost:9200/_cat/plugins?v

# OpenSearch disposable lab only; -k trusts the demo certificate.
curl -k -u "admin:$OPENSEARCH_INITIAL_ADMIN_PASSWORD" \
  https://localhost:9201/
curl -k -u "admin:$OPENSEARCH_INITIAL_ADMIN_PASSWORD" \
  https://localhost:9201/_cat/plugins?v

Store these responses with the migration report. “Elasticsearch 9” and “OpenSearch 3” are too coarse for plugin/client/managed-service compatibility decisions.

5. Mapping and analyzer compatibility is observable

Portable AtlasMart migration source mapping
PUT atlasmart-migrate-source-v1
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0
  },
  "mappings": {
    "dynamic": "strict",
    "properties": {
      "sku":       {"type":"keyword"},
      "tenant_id": {"type":"keyword"},
      "name":      {"type":"text", "fields":{"raw":{"type":"keyword"}}},
      "category":  {"type":"keyword"},
      "price":     {"type":"scaled_float", "scaling_factor":100},
      "available": {"type":"boolean"},
      "updated_at": {"type":"date"}
    }
  }
}
Seed a deterministic five-document fixture
POST _bulk?refresh=wait_for
{"index":{"_index":"atlasmart-migrate-source-v1","_id":"P-1001"}}
{"sku":"P-1001","tenant_id":"tenant-a","name":"Waterproof Hiking Boot","category":"footwear","price":129.90,"available":true,"updated_at":"2026-09-12T10:00:00Z"}
{"index":{"_index":"atlasmart-migrate-source-v1","_id":"P-1002"}}
{"sku":"P-1002","tenant_id":"tenant-a","name":"Trail Running Shoe","category":"footwear","price":99.50,"available":true,"updated_at":"2026-09-12T10:01:00Z"}
{"index":{"_index":"atlasmart-migrate-source-v1","_id":"P-1003"}}
{"sku":"P-1003","tenant_id":"tenant-a","name":"Insulated Water Bottle","category":"outdoor","price":32.00,"available":true,"updated_at":"2026-09-12T10:02:00Z"}
{"index":{"_index":"atlasmart-migrate-source-v1","_id":"P-1004"}}
{"sku":"P-1004","tenant_id":"tenant-b","name":"Lightweight Hiking Pack","category":"outdoor","price":74.00,"available":false,"updated_at":"2026-09-12T10:03:00Z"}
{"index":{"_index":"atlasmart-migrate-source-v1","_id":"P-1005"}}
{"sku":"P-1005","tenant_id":"tenant-b","name":"Merino Hiking Sock","category":"apparel","price":18.50,"available":true,"updated_at":"2026-09-12T10:04:00Z"}
Analyzer regression probe
POST atlasmart-migrate-source-v1/_analyze
{
  "field": "name",
  "text": ["Waterproof hiking boots"]
}

Record the token sequence, positions, offsets, and any normalization that affects matching. Recreate the destination mapping deliberately, then run the same probe. Do not rely on copying an entire source mapping if it contains platform-specific settings or fields.

6. Query compatibility means result semantics, not HTTP 200

Golden retrieval fixture
POST atlasmart-migrate-source-v1/_search
{
  "size": 3,
  "query": {
    "bool": {
      "filter": [
        {"term":{"tenant_id":"tenant-a"}},
        {"term":{"available":true}}
      ],
      "must": [
        {"match":{"name":"hiking"}}
      ]
    }
  },
  "sort": [
    {"_score":"desc"},
    {"sku":"asc"}
  ]
}

Persist top IDs and judged relevance labels, not raw score equality. BM25 and product-specific scoring details can diverge; the migration acceptance question is whether user-visible relevance remains within the agreed quality envelope.

7. Security and UI are separate migration projects

Elasticsearch roles, realms, API keys, Kibana Spaces, and subscription-gated DLS/FLS/audit controls do not map one-to-one to the OpenSearch Security plugin’s internal users, role mappings, tenants, DLS/FLS, audit configuration, and API keys. A successful document copy says nothing about authorization parity. Build negative tests: a reader can search tenant-a, cannot index, cannot read tenant-b, and cannot administer snapshots.

Likewise, Kibana saved objects are not a generic portable dashboard format for OpenSearch Dashboards. Recreate or convert dashboards only after the underlying data views/index patterns, query language, security, and field contracts have been validated.

8. Snapshots are not a cross-product interchange format

Elastic documents snapshot restore compatibility within Elasticsearch version/index-version rules. OpenSearch documents its own snapshot and migration rules. Do not restore an arbitrary Elasticsearch snapshot directly into OpenSearch or the reverse unless the exact source/target/service workflow explicitly documents it. OpenSearch Migration Assistant uses Reindex-from-Snapshot as a migration mechanism, which reads source snapshot shard data and reindexes it into the target—it is not evidence that an Elasticsearch repository is a universally restorable OpenSearch repository.

Current boundary. The OpenSearch Migration Assistant support table currently lists Elasticsearch sources through 8.x for OpenSearch 3.x. Elasticsearch 9.x is not listed. For this Chapter 29 baseline (Elasticsearch 9.5.3 ↔ OpenSearch 3.8.0), the mandatory lab therefore uses a neutral ETL/common-API path and does not claim Migration Assistant support for the 9.x source.

9. Client compatibility must be tested as code

Elastic’s current Python client documentation says the 9.x client family is for Elasticsearch 9.x (and forward to 10.x under its documented compatibility policy), while an 8.x client can span Elasticsearch 8.x→9.x during upgrades but does not expose new 9.x features. OpenSearch explicitly warns that Elasticsearch clients are not fully compatible with OpenSearch 2.0 and later and recommends OpenSearch clients for OpenSearch clusters. Do not preserve a single “Elasticsearch client” abstraction by merely changing the URL.

10. Compatibility matrix artifact

Minimal evidence record
{
  "source": {"product":"Elasticsearch","version":"9.5.3"},
  "target": {"product":"OpenSearch","version":"3.8.0"},
  "contract": "catalog-search-v3",
  "items": [
    {"surface":"mapping", "feature":"text+keyword", "class":"portable", "test":"mapping-001"},
    {"surface":"lifecycle", "feature":"ILM", "class":"translatable", "target":"ISM", "test":"lifecycle-003"},
    {"surface":"analytics", "feature":"ES|QL", "class":"replaceable", "target":"PPL/DSL", "test":"analytics-007"},
    {"surface":"security", "feature":"API-key role descriptors", "class":"translatable", "test":"auth-004"}
  ]
}

Migration approval requires every production dependency to have a class and a test. “Unknown” is a blocking state, not a harmless omission.

11. Wrong approach → repaired approach

Wrong: restore a snapshot, point the existing client at the new URL, see green health, and delete the source. Repair: inventory every contract, create destination mappings/policies/security explicitly, migrate data through a supported path, dual-read golden queries, test authorization failures, benchmark representative load, freeze a rollback window, and retire the source only after the exit criteria are met.

Check your understanding

  1. Why is REST similarity insufficient evidence?
  2. What should raw score equality be replaced with?
  3. Why are snapshots a separate compatibility surface?
  4. What is the current Migration Assistant caveat for this course baseline?
  5. What does Lesson 2 decide?
Review the answers

1. Because the same-looking endpoint can differ in defaults, response shape, feature support, scoring, security, plugins, or version semantics.

2. Judged relevance evidence such as top-k IDs, Recall@k, NDCG, or MRR-like metrics plus deterministic tie-breaking where needed.

3. Snapshot restore is constrained by product and version/index compatibility rules; it is not a universal cross-product serialization format.

4. Its current documented OpenSearch 3.x source matrix lists Elasticsearch through 8.x, not Elasticsearch 9.5.3.

5. Which data-movement pattern—snapshot-supported path, remote reindex, ETL/full copy, dual write, or incremental sync—matches the compatibility and downtime constraints.

Summary and next step

Preserve the evidence, assumptions, version boundaries, and safety checks established in this lesson. Carry them into the next lesson—or, at the end of the capstone, into the production runbook—rather than treating this lesson as an isolated recipe.

References and current-version checks

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.