From 134dab6b11c635713921daf5edd3cf195d16e592 Mon Sep 17 00:00:00 2001 From: Alan Woodward Date: Tue, 3 Aug 2021 16:38:31 +0100 Subject: [PATCH] Don't rebuild shadowed field lookup on every document (#76023) #75595 added better checks for fields shadowed by runtime fields, so that we don't index data that would never be searched. However, the shadow lookup was being rebuilt for every document, which has caused a noticeable regression in indexing times. This commit reworks things so that this lookup is built once per mapping update and lives on MappingLookup. --- .../index/mapper/DocumentParserContext.java | 15 +-------------- .../index/mapper/MappingLookup.java | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/index/mapper/DocumentParserContext.java b/server/src/main/java/org/elasticsearch/index/mapper/DocumentParserContext.java index 912b8153f5c05..121ecff565c2a 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/DocumentParserContext.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/DocumentParserContext.java @@ -92,7 +92,6 @@ protected void addDoc(LuceneDocument doc) { private final Set newFieldsSeen; private final Map dynamicObjectMappers; private final List dynamicRuntimeFields; - private final Set shadowedFields; private Field version; private SeqNoFieldMapper.SequenceIDFields seqID; @@ -108,7 +107,6 @@ private DocumentParserContext(DocumentParserContext in) { this.newFieldsSeen = in.newFieldsSeen; this.dynamicObjectMappers = in.dynamicObjectMappers; this.dynamicRuntimeFields = in.dynamicRuntimeFields; - this.shadowedFields = in.shadowedFields; this.version = in.version; this.seqID = in.seqID; } @@ -129,17 +127,6 @@ protected DocumentParserContext(MappingLookup mappingLookup, this.newFieldsSeen = new HashSet<>(); this.dynamicObjectMappers = new HashMap<>(); this.dynamicRuntimeFields = new ArrayList<>(); - this.shadowedFields = buildShadowedFields(mappingLookup); - } - - private static Set buildShadowedFields(MappingLookup lookup) { - Set shadowedFields = new HashSet<>(); - for (RuntimeField runtimeField : lookup.getMapping().getRoot().runtimeFields()) { - for (MappedFieldType mft : runtimeField.asMappedFieldTypes()) { - shadowedFields.add(mft.name()); - } - } - return shadowedFields; } public final IndexSettings indexSettings() { @@ -243,7 +230,7 @@ public final List getDynamicMappers() { } public final boolean isShadowed(String field) { - return shadowedFields.contains(field); + return mappingLookup.isShadowed(field); } public final ObjectMapper getObjectMapper(String name) { diff --git a/server/src/main/java/org/elasticsearch/index/mapper/MappingLookup.java b/server/src/main/java/org/elasticsearch/index/mapper/MappingLookup.java index 61594fa0144da..d3acede018309 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/MappingLookup.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/MappingLookup.java @@ -16,6 +16,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -51,6 +52,7 @@ private CacheKey() {} private final Map indexAnalyzersMap = new HashMap<>(); private final List indexTimeScriptMappers = new ArrayList<>(); private final Mapping mapping; + private final Set shadowedFields; /** * Creates a new {@link MappingLookup} instance by parsing the provided mapping and extracting its field definitions. @@ -157,6 +159,13 @@ private MappingLookup(Mapping mapping, } } + this.shadowedFields = new HashSet<>(); + for (RuntimeField runtimeField : mapping.getRoot().runtimeFields()) { + for (MappedFieldType mft : runtimeField.asMappedFieldTypes()) { + shadowedFields.add(mft.name()); + } + } + this.fieldTypeLookup = new FieldTypeLookup(mappers, aliasMappers, mapping.getRoot().runtimeFields()); this.indexTimeLookup = new FieldTypeLookup(mappers, aliasMappers, Collections.emptyList()); this.fieldMappers = Collections.unmodifiableMap(fieldMappers); @@ -199,6 +208,13 @@ public Iterable fieldMappers() { return fieldMappers.values(); } + /** + * @return {@code true} if the given field is shadowed by a runtime field + */ + public boolean isShadowed(String field) { + return shadowedFields.contains(field); + } + void checkLimits(IndexSettings settings) { checkFieldLimit(settings.getMappingTotalFieldsLimit()); checkObjectDepthLimit(settings.getMappingDepthLimit());