Mapping explosion
Mapping explosion occurs when an index accumulates an excessive number of fields, which can lead to performance degradation, memory issues, and cluster instability. This situation commonly arises when using dynamic mapping with highly variable document structures, where each new document introduces additional fields that are automatically added to the index mapping.
When OpenSearch encounters new fields in documents, it automatically creates mappings for these fields through dynamic mapping. While this feature provides flexibility, it can become problematic in scenarios such as:
- Log data with varying structures: Different log sources may include unique fields, leading to rapid field proliferation.
- User-generated content: Applications that allow users to define custom fields or attributes.
- Nested object structures: Documents with deeply nested objects that contain many subfields.
- Time-series data: Metrics or events that include dynamic field names based on timestamps or identifiers.
As the number of fields grows, several issues can emerge:
- Increased memory consumption for storing field mappings
- Slower query performance due to larger mapping structures
- Potential out-of-memory errors during indexing or searching
- Difficulty in cluster recovery scenarios
Mapping limit settings
OpenSearch provides several index-level settings to prevent mapping explosion by limiting various aspects of mapping growth. These settings can be configured when creating an index or updated for existing indexes:
PUT /my-index/_settings
{
"index.mapping.total_fields.limit": 2000
}
The following table lists all available mapping limit settings. All settings are dynamic. For more information, see Dynamic settings.
| Setting | Default | Valid values | Description |
|---|---|---|---|
index.mapping.total_fields.limit | 1000 | [0, ∞) | Sets the maximum number of fields allowed in an index, including regular fields, object mappings, and field aliases. Increasing this limit requires careful consideration of cluster resources. When increasing this limit, consider also adjusting the indices.query.bool.max_clause_count setting to accommodate larger queries. |
index.mapping.depth.limit | 20 | [1, 100] | Controls the maximum nesting depth for field mappings. Depth is calculated by counting the levels of nested objects, starting from the root level (depth 1 for root-level fields, depth 2 for fields within 1 level of object nesting, and so on). |
index.mapping.nested_fields.limit | 50 | [0, ∞) | Limits the number of distinct nested field types in an index. Since nested fields require special handling and additional memory, this setting helps prevent excessive resource consumption. |
index.mapping.nested_objects.limit | 10000 | [0, ∞) | Restricts the total number of nested JSON objects that a single document can contain across all nested field types. This prevents individual documents from consuming excessive memory during indexing. |
index.mapping.field_name_length.limit | 50000 | [1, 50000] | Sets the maximum allowed length for field names. This setting can help maintain reasonable mapping sizes by preventing extremely long field names. |
index.mapper.dynamic | true | true,false | Determines whether new fields should be dynamically added to a mapping. Setting this to false can prevent uncontrolled field growth. |
Best practices
To avoid mapping explosion, follow these guidelines.
Use explicit mappings
Define explicit mappings whenever possible instead of relying on dynamic mapping:
PUT /logs
{
"mappings": {
"properties": {
"timestamp": {
"type": "date"
},
"message": {
"type": "text"
},
"level": {
"type": "keyword"
},
"source": {
"type": "keyword"
}
}
}
}
Configure dynamic mapping templates
Use dynamic templates to control how new fields are mapped:
PUT /logs
{
"mappings": {
"dynamic_templates": [
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
}
]
}
}
Use the flat_object field type
For documents with arbitrary key-value pairs, use the flat_object field type instead of allowing dynamic mapping:
PUT /products
{
"mappings": {
"properties": {
"name": {
"type": "text"
},
"attributes": {
"type": "flat_object"
}
}
}
}
Disable dynamic mapping
For indexes with well-defined schemas, disable dynamic mapping entirely:
PUT /structured-data
{
"mappings": {
"dynamic": "strict",
"properties": {
"id": {
"type": "keyword"
},
"value": {
"type": "double"
}
}
}
}
Monitoring and maintenance
Regular monitoring helps you detect mapping growth early and take action before it affects cluster performance. You can monitor field mappings in the following ways.
Check the current field count
Monitor the number of fields in your indexes:
GET /my-index/_mapping
You can also use the Cluster Stats API to get field count information:
GET /_cluster/stats
Identify problematic indexes
Use index statistics to find indexes with high field counts:
GET /_cat/indices?v&h=index,docs.count,store.size,pri.store.size&s=store.size:desc
Clean up unused fields
For indexes with dynamic mapping enabled, regularly review and clean up fields that are no longer needed by reindexing with a more restrictive mapping.
Recovery from mapping explosion
If an index has already experienced mapping explosion:
- Determine which fields are actually needed.
- Create a new index with explicit mappings and appropriate limits.
- Reindex the data using the Reindex API, filtering out unnecessary fields.
- Update aliases to point to the new index.
- Delete the old index once the migration is complete:
POST /_reindex
{
"source": {
"index": "old-index"
},
"dest": {
"index": "new-index"
},
"script": {
"source": "ctx._source.remove('unwanted_field')"
}
}