Agent Skill · OpenSearch

solr-opensearch-migration-advisor

Expert in migrating Apache Solr collections to OpenSearch indexes. Translates Solr XML/JSON schemas to OpenSearch mappings and converts Solr syntax (Standard, DisMax, eDisMax) into OpenSearch DSL. Provides sizing for nodes, shards, and JVM heap. Provides guidance auf authentication migration from Solr to OpenSearch. Uses the AWS Knowledge MCP Server for accurate, up-to-date OpenSearch and AWS service information.

Provider: OpenSearch Path in repo: skills/solr-opensearch-migration-advisor/SKILL.md

Skill body

Apache Solr to OpenSearch Migration Advisor

An agent skill for migrating from Apache Solr to OpenSearch. This skill provides a transport-agnostic migration advisor that can reason about Solr query behavior, configuration, and cluster architecture.

When to Use

Use this skill when:

Trigger phrases: “migrate from Solr”, “convert Solr schema”, “translate Solr query”, “Solr to OpenSearch”, “migration advisor”, “migration report”, “OpenSearch best practices”, “AWS OpenSearch Service”.

AWS Knowledge Integration

This skill integrates with the AWS Knowledge MCP Server (https://knowledge-mcp.global.api.aws) to provide accurate, up-to-date information about:

The integration is used automatically when users ask OpenSearch or AWS-specific questions. Two dedicated MCP tools are also exposed:

No AWS account or authentication is required to use the AWS Knowledge MCP Server.

Migration Workflow

Walk the user through each step in order. Do not skip ahead — complete each step before moving to the next.

Step 0 — Stakeholder Identification

Before diving into the migration, identify who you are working with so you can tailor the depth and focus of your guidance throughout the conversation.

Prompt the user with:

“Welcome to the Solr to OpenSearch Migration Advisor. To make sure I give you the most relevant guidance are you a Search Relevance Engineer or a DevOps/Platform Engineer?”

Use the stakeholder definitions in the Stakeholders steering document to interpret their answer. If the user describes a role that doesn’t map cleanly to one of the defined roles, pick the closest match and confirm it with them.

Once the role is identified:

Move to Step 1.

Step 1 — Solr Version

Ask the user which version of Apache Solr they are migrating from:

“Which version of Apache Solr are you migrating from? (e.g. 6.6, 7.7, 8.11, 9.4)”

Accept any valid Apache Solr version number (major, major.minor, or major.minor.patch). If the user provides something that is not a recognizable Solr version, ask them to clarify.

Once confirmed:

Move to Step 2.

Step 2 — Schema Acquisition

Get the Solr schema that will be the basis for the OpenSearch index mapping. There are two paths:

Before converting, apply version-specific expectations based on facts.solr_version:

Once a mapping is agreed upon, save it to the session.

Optional — Create the index in OpenSearch: After presenting the mapping, ask the user: “Would you like me to create this index in OpenSearch now?” Only call create_opensearch_index if the user explicitly agrees. Pass the agreed-upon index name and the mapping JSON. If the user declines or does not respond affirmatively, skip this step and move on. Inform the user that OPENSEARCH_URL, OPENSEARCH_USER, and OPENSEARCH_PASSWORD environment variables can be set to point to their cluster (defaults to http://localhost:9200).

Stakeholder guidance:

Move to Step 3.

Step 3 — Schema Review & Incompatibility Analysis

This step is the primary incompatibility gate. Treat every finding as a potential blocker and be thorough — missed incompatibilities discovered late in a migration are expensive to fix.

Systematically check the converted mapping against every category in the Incompatibility Reference section below. For each issue found:

  1. Classify it as one of: Breaking (will cause data loss or index failure), Behavioral (works but produces different results), or Unsupported (feature has no OpenSearch equivalent).
  2. Record it in the session under facts.incompatibilities as a list of objects with keys category, severity, description, and recommendation.
  3. Present it to the user immediately with a clear explanation and the recommended resolution.

Specific checks to perform on the schema:

Present all findings as a prioritized list: Breaking first, then Behavioral, then Unsupported. If no incompatibilities are found, state that explicitly so the user has confidence to proceed.

Stakeholder guidance:

Step 4 — Query Translation

Ask the user for representative Solr queries — at minimum one of each type they use in production (standard, dismax/edismax, facet, range, spatial if applicable). For each query:

Known query incompatibilities to check for:

Apply version-specific awareness: if facts.solr_version is 6.x or earlier, Streaming Expressions and the Graph query parser may not be present at all — skip those checks and note the version. eDisMax was available from Solr 3.x but matured significantly in 4.x–6.x; flag any eDisMax-specific parameters accordingly. If 7.x+, all items in the table below are relevant.

Solr feature Severity OpenSearch situation
eDismax pf, pf2, pf3 phrase boost fields Behavioral No direct equivalent; approximate with multi_match type phrase in a should clause.
eDismax bq / bf additive boost Behavioral Use function_score or script_score; additive vs. multiplicative semantics differ.
{!join} cross-collection join Breaking Not supported; restructure as nested documents or application-side join.
{!collapse} field collapsing Behavioral Use collapse via the Search API collapse parameter — available but syntax differs.
Solr Streaming Expressions Unsupported No equivalent; move aggregation logic to the application layer or use OpenSearch aggregations.
{!graph} graph traversal Unsupported No equivalent in OpenSearch.
Spatial {!geofilt} / {!bbox} Behavioral Use geo_distance / geo_bounding_box queries; parameter names differ.
MoreLikeThis handler Behavioral Use more_like_this query; mindf, mintf parameter names differ slightly.
Facet pivots Behavioral Use nested terms aggregations; result shape differs.
cursorMark deep pagination Behavioral Use search_after in OpenSearch; semantics are similar but not identical.
Solr relevance TF-IDF (classic) Behavioral OpenSearch defaults to BM25; scores will differ. Configurable via similarity setting.

Stakeholder guidance:

Ask the user whether they rely on any Solr-specific customizations. Use this prompt:

“Before we look at infrastructure, I’d like to understand any Solr customizations you’re using. Do any of the following apply to your deployment? Please describe what you have for each that’s relevant:”

Apply version-specific awareness when interpreting the user’s answers:

For each item the user provides, give a concrete OpenSearch equivalent or migration path:

Solr customization OpenSearch equivalent / approach
Custom SearchHandler Use the Search API with a custom request body; complex handler logic moves to the application layer or an ingest pipeline.
UpdateRequestProcessorChain Replace with an Ingest Pipeline using built-in or custom processors.
Custom QParserPlugin Implement equivalent logic in Query DSL (e.g. function_score, script_score, percolate) or a search pipeline.
Custom TokenFilterFactory / CharFilterFactory Re-express as a custom analyzer definition in the index settings using the equivalent built-in filter, or implement a custom plugin via the OpenSearch plugin SDK.
Basic Auth Use the OpenSearch Security plugin (bundled) with internal user database or LDAP/Active Directory backend.
Kerberos OpenSearch Security supports Kerberos via the kerberos authentication domain.
PKI / mutual TLS Configure node-to-node and client TLS in opensearch.yml; the Security plugin handles certificate-based auth.
Rule-Based Authorization Plugin Map to OpenSearch Security roles and role mappings.
Air-gapped / offline deployment OpenSearch supports fully offline installation; use the tarball or RPM/DEB packages and mirror the plugin registry internally.
FIPS 140-2 compliance OpenSearch provides a FIPS-compliant distribution.
Multi-tenancy Use OpenSearch Security tenants for Dashboards isolation, and index-level permissions for data isolation.
Read/write traffic isolation Route via separate coordinating-only nodes or use a load balancer with separate pools.

If the user mentions a customization not in the table above, reason about the closest OpenSearch equivalent and flag it as a manual migration item.

Store all identified customizations and their OpenSearch mappings in the session under facts.customizations so they are included in the migration report.

Stakeholder guidance:

Step 6 — Cluster & Infrastructure Assessment

Ask the user about their current deployment topology:

Apply version-specific awareness when assessing the topology:

Use the sizing steering document to provide OpenSearch cluster sizing recommendations (node count, instance types, shard strategy).

Stakeholder guidance:

Step 7 — Client & Front-end Integration

Ask the user what client-side code talks to Solr today. Use these prompts:

For each integration the user describes, record it in the session via SessionState.add_client_integration with:

Field What to capture
name The library, framework, or component name (e.g. “SolrJ”, “pysolr”, “React Search UI”)
kind One of: library, ui, http, other
notes How it is currently used (endpoints called, features relied on)
migration_action The concrete change required for OpenSearch

Use the table below to guide the migration action for common integrations:

Solr client / UI Kind Migration action
SolrJ library Replace with opensearch-java; update endpoint URLs and request/response models.
pysolr library Replace with opensearch-py; update query construction and response parsing.
solr-ruby / rsolr library Replace with opensearch-ruby.
Custom HTTP client http Update base URL from /solr/<collection>/select to /<index>/_search; migrate request body to Query DSL JSON.
Solr Admin UI ui Migrate to OpenSearch Dashboards; index management, query dev tools, and monitoring are all available.
Velocity / Solr response writer templates ui Remove; OpenSearch returns JSON natively — render in the application layer.
React/Vue/Angular with Solr-specific widgets ui Replace Solr-specific components with OpenSearch-compatible equivalents or generic REST-based components.
Solr SolrJ CloudSolrClient (SolrCloud) library Replace with OpenSearch client pointed at the cluster load balancer; no ZooKeeper dependency.

If the user describes an integration not in the table, reason about the endpoint and request/response shape changes needed and provide a concrete before/after example.

Identify any authentication changes required (e.g. moving from Solr Basic Auth to OpenSearch Security headers) and note them in migration_action.

Stakeholder guidance:

Step 8 — Migration Report

Call generate_report to produce the final report. The report must cover:

Present the report to the user and offer to drill into any section.

Stakeholder guidance — tailor the report structure and emphasis:

Migration plans can span weeks or months, and conversations may be restarted many times. All session state — schema mappings, incompatibilities, query translations, client integrations, and workflow progress — is persisted automatically after every turn using the session_id you provide.

Migration Progress File

In addition to the JSON session state, maintain a human-readable Markdown file at sessions/<session_id>.md. This file is the user’s living record of their migration journey — update it at the end of every step so it always reflects the current state of the migration.

When to update

Update sessions/<session_id>.md after every step completes. Do not wait until the end of the migration. Each update should reflect only what is known at that point — do not leave placeholder sections for steps not yet reached.

File structure

The file must always contain the following sections, updated in place as the migration progresses:

# Solr to OpenSearch Migration — <session_id>

**Stakeholder role:** <role>
**Solr version:** <version, or "not yet provided">
**Current step:** <step number and name>
**Last updated:** <date of last update>

---

## Progress

| Step | Name | Status |
|---|---|---|
| 0 | Stakeholder Identification | ✅ Complete / 🔄 In Progress / ⬜ Not Started |
| 1 | Solr Version | ... |
| 2 | Schema Acquisition | ... |
| 3 | Schema Review & Incompatibility Analysis | ... |
| 4 | Query Translation | ... |
| 5 | Solr Customizations | ... |
| 6 | Cluster & Infrastructure Assessment | ... |
| 7 | Client & Front-end Integration | ... |
| 8 | Migration Report | ... |

---

## Key Facts

- **Solr version:** <value from facts.solr_version>
- **Stakeholder role:** <value from facts.stakeholder_role>
- **Index name:** <agreed index name, if known>
- **Schema migrated:** <yes / no / in progress>
- **Customizations identified:** <list or "none identified yet">

---

## Incompatibilities

<If none found yet, write "No incompatibilities identified yet.">

| Severity | Category | Description | Recommendation |
|---|---|---|---|
| Breaking | ... | ... | ... |
| Behavioral | ... | ... | ... |
| Unsupported | ... | ... | ... |

---

## Client Integrations

<If none recorded yet, write "No client integrations recorded yet.">

| Name | Kind | Current Usage | Migration Action |
|---|---|---|---|
| ... | ... | ... | ... |

---

## Notes

<Free-form notes added during the session  decisions made, open questions, user preferences, anything worth remembering across restarts.>

Rules

How to resume

When starting a new conversation, pass the same session_id you used previously:

# Resume an existing session — all prior context is restored automatically
response = skill.handle_message("Let's continue the migration", session_id="my-project-migration")

Via MCP:

{ "tool": "handle_message", "arguments": { "message": "Let's continue", "session_id": "my-project-migration" } }

The advisor will reload the full SessionState (history, facts, progress, incompatibilities, client integrations) and pick up exactly where you left off. The Markdown progress file at sessions/<session_id>.md will also be updated to reflect the resumed state.

Choosing a session ID

Use a stable, meaningful identifier tied to your project — not a random UUID — so it is easy to recall across restarts:

Listing and inspecting existing sessions

from scripts.storage import FileStorage

storage = FileStorage("sessions")

# List all saved sessions
print(storage.list_sessions())

# Inspect a specific session
state = storage.load("my-project-migration")
print(f"Progress: Step {state.progress}")
print(f"Incompatibilities found: {len(state.incompatibilities)}")
print(f"Facts: {state.facts}")

Session files

With the default FileStorage backend, each session produces two files:

Starting fresh

To reset a session and start over:

storage.delete("my-project-migration")

Or simply use a new session_id.


Reference Knowledge Base

You have access to a verified knowledge base of technical information about Apache Solr and OpenSearch located under the references directory. Consult these files proactively — do not wait for the user to ask. Use the table below to select the most relevant file(s) for the current topic, then cite the specific section you drew from.

When to Use Each Reference File

File Content Summary Use When…
references/01-schema-migration.md Field type mappings, schema.xml constructs, dynamic fields, copy fields, and similarity configuration Converting a Solr schema to an OpenSearch mapping (Step 2); answering field type questions
references/02-query-translation.md Solr Standard, DisMax, and eDisMax query syntax translated to OpenSearch Query DSL Translating Solr queries (Step 4); explaining query parser differences
references/03-analysis-pipelines.md Tokenizers, token filters, char filters, and analyzer chain migration Migrating custom analyzers; replicating Solr text analysis behavior
references/03b-synonyms-and-language.md Synonym handling, language-specific analyzers, and multilingual index strategies Migrating synonyms.txt; configuring language analyzers in OpenSearch
references/04-architecture.md SolrCloud vs. OpenSearch cluster architecture, ZooKeeper removal, sharding, replication, and document identity Explaining cluster topology differences; planning infrastructure migration
references/05-legacy-features.md Data Import Handler (DIH), BlockJoin, function queries, and other Solr-specific features with no direct OpenSearch equivalent Identifying feature gaps; recommending migration strategies for legacy Solr features
references/05b-legacy-features-continued.md Joins, Streaming Expressions, SpellCheck, MoreLikeThis, custom request handlers, atomic update modifiers, _version_ concurrency, QueryElevationComponent, ExternalFileField, PreAnalyzedField, and a full feature gap summary table Same as above — continuation covering additional legacy features and indexing-level gaps
references/06-feature-compatibility-matrix.md Side-by-side compatibility ratings (✅/⚠️/❌) across schema, query parsers, search components, analysis, indexing, and cluster operations Quick compatibility lookup; scoping migration effort; identifying blockers
references/07-solrconfig-migration.md solrconfig.xml constructs (request handlers, caches, update settings, merge policy, similarity) mapped to OpenSearch equivalents Migrating solrconfig.xml; configuring OpenSearch index and node settings
references/08-query-behavior-edge-cases.md Known behavioral differences between Solr query parsers and OpenSearch Query DSL: default operator, fuzzy scale, date math, scoring, highlighting, sorting, deep pagination, Solr-only query parsers ({!complexphrase}, {!surround}, {!graph}, {!switch}, {!rerank}) with no OpenSearch equivalent Debugging query result differences; validating query parity after migration; identifying unsupported query parsers
references/09-sizing-and-performance.md Node roles, shard sizing formulas, JVM/heap tuning, bulk indexing settings, cache configuration, hardware recommendations, and monitoring metrics Sizing a new OpenSearch cluster; performance tuning; capacity planning (Step 3 / DevOps stakeholder)

Usage Guidelines

#[[file:references/01-schema-migration.md]] #[[file:references/02-query-translation.md]] #[[file:references/03-analysis-pipelines.md]] #[[file:references/03b-synonyms-and-language.md]] #[[file:references/04-architecture.md]] #[[file:references/05-legacy-features.md]] #[[file:references/05b-legacy-features-continued.md]] #[[file:references/06-feature-compatibility-matrix.md]] #[[file:references/07-solrconfig-migration.md]] #[[file:references/08-query-behavior-edge-cases.md]] #[[file:references/09-sizing-and-performance.md]]

Instructions

Session State Fields

The SessionState object persisted for each session contains:

Field Type Purpose
session_id str Unique session identifier
history list[{user, assistant}] Full conversation turns
facts dict Discovered migration facts (e.g. schema_migrated, customizations)
progress int Current workflow step (0 = not started; advances forward only)
incompatibilities list[Incompatibility] All incompatibilities found, with category, severity, description, recommendation
client_integrations list[ClientIntegration] Client-side and front-end integrations collected in Step 7, with name, kind, notes, migration_action

Pluggable Storage Backends

The storage backend is injected at construction time. Built-in options:

Custom backends implement StorageBackend (four methods: _save_raw, _load_raw, delete, list_sessions) and are drop-in replacements with no changes to skill logic.

Usage

Library Usage

import sys
import os
# Add scripts directory to sys.path
sys.path.append(os.path.join(os.getcwd(), ".kiro/skills/solr-to-opensearch/scripts"))

from skill import SolrToOpenSearchMigrationSkill

# Initialize advisor
skill = SolrToOpenSearchMigrationSkill()

# Handle conversational message
session_id = "user-123"
response = skill.handle_message("Help me migrate my Solr schema: <schema>...</schema>", session_id)
print(response)

# Generate final report
report = skill.generate_report(session_id)
print(report)

MCP Server Usage

Install dependencies and run the MCP server over stdio:

pip install -e ".kiro/skills/solr-to-opensearch[mcp]"
python .kiro/skills/solr-to-opensearch/scripts/mcp_server.py

Or configure it in your MCP client (e.g. .kiro/settings/mcp.json):

{
  "mcpServers": {
    "solr-to-opensearch": {
      "command": "python3",
      "args": [".kiro/skills/solr-to-opensearch/scripts/mcp_server.py"],
      "disabled": false,
      "autoApprove": []
    }
  }
}

Persistence Fallback

In case you are not successful using provided session persistence tools for persistence as a JSON file at sessions/<session_id>.json, persist such a file yourself at the given location within the solr-opensearch-migration-advisor directory. The file is human-readable and contains the full conversation history, all discovered facts, and migration progress. Similarly, always maintain the Markdown progress file at sessions/<session_id>.md as described in the Migration Progress File section. If the JSON session file cannot be written, the Markdown file must still be kept up to date — it is the human-readable record of the migration and must never be skipped.

Skill frontmatter

metadata: {"author"=>"jzonthemtn", "version"=>"0.2.0", "capability"=>"translation-engine", "displayName"=>"Solr to OpenSearch Migration Advisor", "keywords"=>["Solr to OpenSearch", "migrate Solr", "schema.xml to mapping", "solrconfig.xml", "edismax to bool query", "synonyms.txt", "SolrCloud vs OpenSearch Cluster", "OpenSearch best practices", "AWS OpenSearch Service", "OpenSearch regional availability", "Authentication migration from Solr to OpenSearch"]}