From 9b120a0b484a2df3091dc5dc150cb9edb2fd4f71 Mon Sep 17 00:00:00 2001 From: Yanjun Huang Date: Fri, 18 Mar 2016 17:36:40 -0700 Subject: [PATCH] Add total number of fields limit to index mapping This is to prevent mapping explosion when dynamic keys such as UUID are used as field names. index.mapping.total_fields.limit specifies the total number of fields an index can have. An exception will be thrown when the limit is reached. The default limit is 500. Setting the limit to 0 will disable the checking. This setting is runtime adjustable. --- .../common/settings/IndexScopedSettings.java | 1 + .../org/elasticsearch/index/mapper/MapperService.java | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/core/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java b/core/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java index b8b751477408a..b5bdccd3b14de 100644 --- a/core/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java +++ b/core/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java @@ -127,6 +127,7 @@ public final class IndexScopedSettings extends AbstractScopedSettings { PercolatorQueriesRegistry.INDEX_MAP_UNMAPPED_FIELDS_AS_STRING_SETTING, MapperService.INDEX_MAPPER_DYNAMIC_SETTING, MapperService.INDEX_MAPPING_NESTED_FIELDS_LIMIT_SETTING, + MapperService.INDEX_MAPPING_TOTAL_FIELDS_LIMIT_SETTING, BitsetFilterCache.INDEX_LOAD_RANDOM_ACCESS_FILTERS_EAGERLY_SETTING, IndexModule.INDEX_STORE_TYPE_SETTING, IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING, diff --git a/core/src/main/java/org/elasticsearch/index/mapper/MapperService.java b/core/src/main/java/org/elasticsearch/index/mapper/MapperService.java index b25f5f6a02dfd..bc5b68ef499d2 100755 --- a/core/src/main/java/org/elasticsearch/index/mapper/MapperService.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/MapperService.java @@ -82,6 +82,7 @@ public enum MergeReason { public static final String DEFAULT_MAPPING = "_default_"; public static final Setting INDEX_MAPPING_NESTED_FIELDS_LIMIT_SETTING = Setting.longSetting("index.mapping.nested_fields.limit", 50L, 0, true, Setting.Scope.INDEX); + public static final Setting INDEX_MAPPING_TOTAL_FIELDS_LIMIT_SETTING = Setting.longSetting("index.mapping.total_fields.limit", 500L, 0, true, Setting.Scope.INDEX); public static final boolean INDEX_MAPPER_DYNAMIC_DEFAULT = true; public static final Setting INDEX_MAPPER_DYNAMIC_SETTING = Setting.boolSetting("index.mapper.dynamic", INDEX_MAPPER_DYNAMIC_DEFAULT, false, Setting.Scope.INDEX); private static ObjectHashSet META_FIELDS = ObjectHashSet.from( @@ -281,6 +282,7 @@ private synchronized DocumentMapper merge(DocumentMapper mapper, MergeReason rea if (reason == MergeReason.MAPPING_UPDATE) { checkNestedFieldsLimit(fullPathObjectMappers); + checkTotalFieldsLimit(objectMappers.size() + fieldMappers.size()); } Set parentTypes = this.parentTypes; @@ -400,6 +402,13 @@ private void checkNestedFieldsLimit(Map fullPathObjectMapp } } + private void checkTotalFieldsLimit(long totalMappers) { + long allowedTotalFields = indexSettings.getValue(INDEX_MAPPING_TOTAL_FIELDS_LIMIT_SETTING); + if (allowedTotalFields > 0 && allowedTotalFields < totalMappers) { + throw new IllegalArgumentException("Limit of total fields [" + allowedTotalFields + "] in index [" + index().getName() + "] has been exceeded"); + } + } + public DocumentMapper parse(String mappingType, CompressedXContent mappingSource, boolean applyDefault) throws MapperParsingException { String defaultMappingSource; if (PercolatorService.TYPE_NAME.equals(mappingType)) {