From 5cd56e5cea5ac3a41527b5185449d78baad85d18 Mon Sep 17 00:00:00 2001 From: Shay Banon Date: Thu, 31 Oct 2013 03:11:04 +0100 Subject: [PATCH] Improve new field mapping introduction performance Improve the introduction of new fields into the concrete parsed mappings by not relying on immutable maps and copying over entries, but instead using open maps (which will also use less memory), and using clone to perform the copy on write logic --- .../index/analysis/FieldNameAnalyzer.java | 12 +- .../index/mapper/DocumentFieldMappers.java | 128 +++------ .../index/mapper/DocumentMapper.java | 7 +- .../index/mapper/FieldMappersLookup.java | 243 ++++++++++++++++++ .../index/mapper/MapperService.java | 130 ++-------- .../index/mapper/object/ObjectMapper.java | 48 ++-- 6 files changed, 329 insertions(+), 239 deletions(-) create mode 100644 src/main/java/org/elasticsearch/index/mapper/FieldMappersLookup.java diff --git a/src/main/java/org/elasticsearch/index/analysis/FieldNameAnalyzer.java b/src/main/java/org/elasticsearch/index/analysis/FieldNameAnalyzer.java index 907eb6ca61f..3df83069c0e 100644 --- a/src/main/java/org/elasticsearch/index/analysis/FieldNameAnalyzer.java +++ b/src/main/java/org/elasticsearch/index/analysis/FieldNameAnalyzer.java @@ -19,27 +19,25 @@ package org.elasticsearch.index.analysis; -import com.google.common.collect.ImmutableMap; +import com.carrotsearch.hppc.ObjectObjectOpenHashMap; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.AnalyzerWrapper; -import java.util.Map; - /** * */ public final class FieldNameAnalyzer extends AnalyzerWrapper { - private final ImmutableMap analyzers; + private final ObjectObjectOpenHashMap analyzers; private final Analyzer defaultAnalyzer; - public FieldNameAnalyzer(Map analyzers, Analyzer defaultAnalyzer) { - this.analyzers = ImmutableMap.copyOf(analyzers); + public FieldNameAnalyzer(ObjectObjectOpenHashMap analyzers, Analyzer defaultAnalyzer) { + this.analyzers = analyzers; this.defaultAnalyzer = defaultAnalyzer; } - public ImmutableMap analyzers() { + public ObjectObjectOpenHashMap analyzers() { return analyzers; } diff --git a/src/main/java/org/elasticsearch/index/mapper/DocumentFieldMappers.java b/src/main/java/org/elasticsearch/index/mapper/DocumentFieldMappers.java index 8833cfbf78b..e94b9347d44 100644 --- a/src/main/java/org/elasticsearch/index/mapper/DocumentFieldMappers.java +++ b/src/main/java/org/elasticsearch/index/mapper/DocumentFieldMappers.java @@ -19,65 +19,43 @@ package org.elasticsearch.index.mapper; -import com.google.common.collect.*; +import com.carrotsearch.hppc.ObjectObjectOpenHashMap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.UnmodifiableIterator; import org.apache.lucene.analysis.Analyzer; -import org.elasticsearch.common.regex.Regex; +import org.elasticsearch.common.hppc.HppcMaps; import org.elasticsearch.index.analysis.FieldNameAnalyzer; -import java.util.Map; import java.util.Set; -import static com.google.common.collect.Lists.newArrayList; -import static com.google.common.collect.Maps.newHashMap; - /** * */ public class DocumentFieldMappers implements Iterable { - private final ImmutableList fieldMappers; - private final Map fullNameFieldMappers; - private final Map nameFieldMappers; - private final Map indexNameFieldMappers; + private final DocumentMapper docMapper; + private final FieldMappersLookup fieldMappers; - private final FieldNameAnalyzer indexAnalyzer; - private final FieldNameAnalyzer searchAnalyzer; - private final FieldNameAnalyzer searchQuoteAnalyzer; + private volatile FieldNameAnalyzer indexAnalyzer; + private volatile FieldNameAnalyzer searchAnalyzer; + private volatile FieldNameAnalyzer searchQuoteAnalyzer; - public DocumentFieldMappers(DocumentMapper docMapper, Iterable fieldMappers) { - final Map tempNameFieldMappers = newHashMap(); - final Map tempIndexNameFieldMappers = newHashMap(); - final Map tempFullNameFieldMappers = newHashMap(); + public DocumentFieldMappers(DocumentMapper docMapper) { + this.docMapper = docMapper; + this.fieldMappers = new FieldMappersLookup(); + this.indexAnalyzer = new FieldNameAnalyzer(HppcMaps.newMap(), docMapper.indexAnalyzer()); + this.searchAnalyzer = new FieldNameAnalyzer(HppcMaps.newMap(), docMapper.searchAnalyzer()); + this.searchQuoteAnalyzer = new FieldNameAnalyzer(HppcMaps.newMap(), docMapper.searchQuotedAnalyzer()); + } - final Map indexAnalyzers = newHashMap(); - final Map searchAnalyzers = newHashMap(); - final Map searchQuoteAnalyzers = newHashMap(); + public void addNewMappers(Iterable newMappers) { + fieldMappers.addNewMappers(newMappers); - for (FieldMapper fieldMapper : fieldMappers) { - FieldMappers mappers = tempNameFieldMappers.get(fieldMapper.names().name()); - if (mappers == null) { - mappers = new FieldMappers(fieldMapper); - } else { - mappers = mappers.concat(fieldMapper); - } - tempNameFieldMappers.put(fieldMapper.names().name(), mappers); - - mappers = tempIndexNameFieldMappers.get(fieldMapper.names().indexName()); - if (mappers == null) { - mappers = new FieldMappers(fieldMapper); - } else { - mappers = mappers.concat(fieldMapper); - } - tempIndexNameFieldMappers.put(fieldMapper.names().indexName(), mappers); - - mappers = tempFullNameFieldMappers.get(fieldMapper.names().fullName()); - if (mappers == null) { - mappers = new FieldMappers(fieldMapper); - } else { - mappers = mappers.concat(fieldMapper); - } - tempFullNameFieldMappers.put(fieldMapper.names().fullName(), mappers); + final ObjectObjectOpenHashMap indexAnalyzers = this.indexAnalyzer.analyzers().clone(); + final ObjectObjectOpenHashMap searchAnalyzers = this.searchAnalyzer.analyzers().clone(); + final ObjectObjectOpenHashMap searchQuoteAnalyzers = this.searchQuoteAnalyzer.analyzers().clone(); + for (FieldMapper fieldMapper : newMappers) { if (fieldMapper.indexAnalyzer() != null) { indexAnalyzers.put(fieldMapper.names().indexName(), fieldMapper.indexAnalyzer()); } @@ -88,10 +66,6 @@ public class DocumentFieldMappers implements Iterable { searchQuoteAnalyzers.put(fieldMapper.names().indexName(), fieldMapper.searchQuoteAnalyzer()); } } - this.fieldMappers = ImmutableList.copyOf(fieldMappers); - this.nameFieldMappers = ImmutableMap.copyOf(tempNameFieldMappers); - this.indexNameFieldMappers = ImmutableMap.copyOf(tempIndexNameFieldMappers); - this.fullNameFieldMappers = ImmutableMap.copyOf(tempFullNameFieldMappers); this.indexAnalyzer = new FieldNameAnalyzer(indexAnalyzers, docMapper.indexAnalyzer()); this.searchAnalyzer = new FieldNameAnalyzer(searchAnalyzers, docMapper.searchAnalyzer()); @@ -104,51 +78,31 @@ public class DocumentFieldMappers implements Iterable { } public ImmutableList mappers() { - return this.fieldMappers; + return this.fieldMappers.mappers(); } public boolean hasMapper(FieldMapper fieldMapper) { - return fieldMappers.contains(fieldMapper); + return fieldMappers.mappers().contains(fieldMapper); } public FieldMappers name(String name) { - return nameFieldMappers.get(name); + return fieldMappers.name(name); } public FieldMappers indexName(String indexName) { - return indexNameFieldMappers.get(indexName); + return fieldMappers.indexName(indexName); } public FieldMappers fullName(String fullName) { - return fullNameFieldMappers.get(fullName); + return fieldMappers.fullName(fullName); } public Set simpleMatchToIndexNames(String pattern) { - Set fields = Sets.newHashSet(); - for (FieldMapper fieldMapper : fieldMappers) { - if (Regex.simpleMatch(pattern, fieldMapper.names().fullName())) { - fields.add(fieldMapper.names().indexName()); - } else if (Regex.simpleMatch(pattern, fieldMapper.names().indexName())) { - fields.add(fieldMapper.names().indexName()); - } else if (Regex.simpleMatch(pattern, fieldMapper.names().name())) { - fields.add(fieldMapper.names().indexName()); - } - } - return fields; + return fieldMappers.simpleMatchToIndexNames(pattern); } public Set simpleMatchToFullName(String pattern) { - Set fields = Sets.newHashSet(); - for (FieldMapper fieldMapper : fieldMappers) { - if (Regex.simpleMatch(pattern, fieldMapper.names().fullName())) { - fields.add(fieldMapper.names().fullName()); - } else if (Regex.simpleMatch(pattern, fieldMapper.names().indexName())) { - fields.add(fieldMapper.names().fullName()); - } else if (Regex.simpleMatch(pattern, fieldMapper.names().name())) { - fields.add(fieldMapper.names().fullName()); - } - } - return fields; + return fieldMappers.simpleMatchToFullName(pattern); } /** @@ -156,23 +110,11 @@ public class DocumentFieldMappers implements Iterable { * by {@link #name(String)}. */ public FieldMappers smartName(String name) { - FieldMappers fieldMappers = fullName(name); - if (fieldMappers != null) { - return fieldMappers; - } - fieldMappers = indexName(name); - if (fieldMappers != null) { - return fieldMappers; - } - return name(name); + return fieldMappers.smartName(name); } public FieldMapper smartNameFieldMapper(String name) { - FieldMappers fieldMappers = smartName(name); - if (fieldMappers == null) { - return null; - } - return fieldMappers.mapper(); + return fieldMappers.smartNameFieldMapper(name); } /** @@ -202,12 +144,4 @@ public class DocumentFieldMappers implements Iterable { public Analyzer searchQuoteAnalyzer() { return this.searchQuoteAnalyzer; } - - public DocumentFieldMappers concat(DocumentMapper docMapper, FieldMapper... fieldMappers) { - return concat(docMapper, newArrayList(fieldMappers)); - } - - public DocumentFieldMappers concat(DocumentMapper docMapper, Iterable fieldMappers) { - return new DocumentFieldMappers(docMapper, Iterables.concat(this.fieldMappers, fieldMappers)); - } } diff --git a/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java b/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java index 5aba02d3352..8b17f302353 100644 --- a/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java +++ b/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java @@ -261,7 +261,7 @@ public class DocumentMapper implements ToXContent { private final NamedAnalyzer searchAnalyzer; private final NamedAnalyzer searchQuoteAnalyzer; - private volatile DocumentFieldMappers fieldMappers; + private final DocumentFieldMappers fieldMappers; private volatile ImmutableMap objectMappers = ImmutableMap.of(); @@ -325,7 +325,8 @@ public class DocumentMapper implements ToXContent { // now traverse and get all the statically defined ones rootObjectMapper.traverse(fieldMappersAgg); - this.fieldMappers = new DocumentFieldMappers(this, fieldMappersAgg.mappers); + this.fieldMappers = new DocumentFieldMappers(this); + this.fieldMappers.addNewMappers(fieldMappersAgg.mappers); final Map objectMappers = Maps.newHashMap(); rootObjectMapper.traverse(new ObjectMapperListener() { @@ -575,7 +576,7 @@ public class DocumentMapper implements ToXContent { public void addFieldMappers(FieldMapper... fieldMappers) { synchronized (mappersMutex) { - this.fieldMappers = this.fieldMappers.concat(this, fieldMappers); + this.fieldMappers.addNewMappers(Arrays.asList(fieldMappers)); } for (FieldMapperListener listener : fieldMapperListeners) { listener.fieldMappers(fieldMappers); diff --git a/src/main/java/org/elasticsearch/index/mapper/FieldMappersLookup.java b/src/main/java/org/elasticsearch/index/mapper/FieldMappersLookup.java new file mode 100644 index 00000000000..8889fc9b7aa --- /dev/null +++ b/src/main/java/org/elasticsearch/index/mapper/FieldMappersLookup.java @@ -0,0 +1,243 @@ +/* + * Licensed to ElasticSearch and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. ElasticSearch licenses this + * file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.index.mapper; + +import com.carrotsearch.hppc.ObjectObjectOpenHashMap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Sets; +import com.google.common.collect.UnmodifiableIterator; +import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.hppc.HppcMaps; +import org.elasticsearch.common.regex.Regex; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * A class that holds a map of field mappers from name, index name, and full name. + */ +public class FieldMappersLookup implements Iterable { + + private volatile ImmutableList mappers; + private volatile ObjectObjectOpenHashMap name; + private volatile ObjectObjectOpenHashMap indexName; + private volatile ObjectObjectOpenHashMap fullName; + + public FieldMappersLookup() { + this.mappers = ImmutableList.of(); + this.fullName = HppcMaps.newMap(); + this.name = HppcMaps.newMap(); + this.indexName = HppcMaps.newMap(); + } + + /** + * Adds a new set of mappers. + */ + public void addNewMappers(Iterable newMappers) { + final ObjectObjectOpenHashMap tempName = this.name.clone(); + final ObjectObjectOpenHashMap tempIndexName = this.indexName.clone(); + final ObjectObjectOpenHashMap tempFullName = this.fullName.clone(); + + for (FieldMapper fieldMapper : newMappers) { + FieldMappers mappers = tempName.get(fieldMapper.names().name()); + if (mappers == null) { + mappers = new FieldMappers(fieldMapper); + } else { + mappers = mappers.concat(fieldMapper); + } + tempName.put(fieldMapper.names().name(), mappers); + + mappers = tempIndexName.get(fieldMapper.names().indexName()); + if (mappers == null) { + mappers = new FieldMappers(fieldMapper); + } else { + mappers = mappers.concat(fieldMapper); + } + tempIndexName.put(fieldMapper.names().indexName(), mappers); + + mappers = tempFullName.get(fieldMapper.names().fullName()); + if (mappers == null) { + mappers = new FieldMappers(fieldMapper); + } else { + mappers = mappers.concat(fieldMapper); + } + tempFullName.put(fieldMapper.names().fullName(), mappers); + } + this.mappers = ImmutableList.builder().addAll(this.mappers).addAll(newMappers).build(); + this.name = tempName; + this.indexName = tempIndexName; + this.fullName = tempFullName; + } + + /** + * Removes the set of mappers. + */ + public void removeMappers(Iterable mappersToRemove) { + List tempMappers = new ArrayList(this.mappers); + ObjectObjectOpenHashMap tempName = this.name.clone(); + ObjectObjectOpenHashMap tempIndexName = this.indexName.clone(); + ObjectObjectOpenHashMap tempFullName = this.fullName.clone(); + + for (FieldMapper mapper : mappersToRemove) { + FieldMappers mappers = tempName.get(mapper.names().name()); + if (mappers != null) { + mappers = mappers.remove(mapper); + if (mappers.isEmpty()) { + tempName.remove(mapper.names().name()); + } else { + tempName.put(mapper.names().name(), mappers); + } + } + + mappers = tempIndexName.get(mapper.names().indexName()); + if (mappers != null) { + mappers = mappers.remove(mapper); + if (mappers.isEmpty()) { + tempIndexName.remove(mapper.names().indexName()); + } else { + tempIndexName.put(mapper.names().indexName(), mappers); + } + } + + mappers = tempFullName.get(mapper.names().fullName()); + if (mappers != null) { + mappers = mappers.remove(mapper); + if (mappers.isEmpty()) { + tempFullName.remove(mapper.names().fullName()); + } else { + tempFullName.put(mapper.names().fullName(), mappers); + } + } + + tempMappers.remove(mapper); + } + + + this.mappers = ImmutableList.copyOf(tempMappers); + this.name = tempName; + this.indexName = tempIndexName; + this.fullName = tempFullName; + } + + @Override + public UnmodifiableIterator iterator() { + return mappers.iterator(); + } + + /** + * The list of all mappers. + */ + public ImmutableList mappers() { + return this.mappers; + } + + /** + * Is there a mapper (based on unique {@link FieldMapper} identity)? + */ + public boolean hasMapper(FieldMapper fieldMapper) { + return mappers.contains(fieldMapper); + } + + /** + * Returns the field mappers based on the mapper name. + */ + public FieldMappers name(String name) { + return this.name.get(name); + } + + /** + * Returns the field mappers based on the mapper index name. + */ + public FieldMappers indexName(String indexName) { + return this.indexName.get(indexName); + } + + /** + * Returns the field mappers based on the mapper full name. + */ + public FieldMappers fullName(String fullName) { + return this.fullName.get(fullName); + } + + /** + * Returns a set of the index names of a simple match regex like pattern against full name, name and index name. + */ + public Set simpleMatchToIndexNames(String pattern) { + Set fields = Sets.newHashSet(); + for (FieldMapper fieldMapper : mappers) { + if (Regex.simpleMatch(pattern, fieldMapper.names().fullName())) { + fields.add(fieldMapper.names().indexName()); + } else if (Regex.simpleMatch(pattern, fieldMapper.names().indexName())) { + fields.add(fieldMapper.names().indexName()); + } else if (Regex.simpleMatch(pattern, fieldMapper.names().name())) { + fields.add(fieldMapper.names().indexName()); + } + } + return fields; + } + + /** + * Returns a set of the full names of a simple match regex like pattern against full name, name and index name. + */ + public Set simpleMatchToFullName(String pattern) { + Set fields = Sets.newHashSet(); + for (FieldMapper fieldMapper : mappers) { + if (Regex.simpleMatch(pattern, fieldMapper.names().fullName())) { + fields.add(fieldMapper.names().fullName()); + } else if (Regex.simpleMatch(pattern, fieldMapper.names().indexName())) { + fields.add(fieldMapper.names().fullName()); + } else if (Regex.simpleMatch(pattern, fieldMapper.names().name())) { + fields.add(fieldMapper.names().fullName()); + } + } + return fields; + } + + /** + * Tries to find first based on {@link #fullName(String)}, then by {@link #indexName(String)}, and last + * by {@link #name(String)}. + */ + @Nullable + public FieldMappers smartName(String name) { + FieldMappers fieldMappers = fullName(name); + if (fieldMappers != null) { + return fieldMappers; + } + fieldMappers = indexName(name); + if (fieldMappers != null) { + return fieldMappers; + } + return name(name); + } + + /** + * Tries to find first based on {@link #fullName(String)}, then by {@link #indexName(String)}, and last + * by {@link #name(String)} and return the first mapper for it (see {@link org.elasticsearch.index.mapper.FieldMappers#mapper()}). + */ + @Nullable + public FieldMapper smartNameFieldMapper(String name) { + FieldMappers fieldMappers = smartName(name); + if (fieldMappers == null) { + return null; + } + return fieldMappers.mapper(); + } +} diff --git a/src/main/java/org/elasticsearch/index/mapper/MapperService.java b/src/main/java/org/elasticsearch/index/mapper/MapperService.java index adebea41a87..687a52bbad5 100644 --- a/src/main/java/org/elasticsearch/index/mapper/MapperService.java +++ b/src/main/java/org/elasticsearch/index/mapper/MapperService.java @@ -19,6 +19,7 @@ package org.elasticsearch.index.mapper; +import com.carrotsearch.hppc.ObjectObjectOpenHashMap; import com.google.common.base.Charsets; import com.google.common.collect.*; import org.apache.lucene.analysis.Analyzer; @@ -31,7 +32,7 @@ import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.Filter; import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.Nullable; -import org.elasticsearch.common.collect.MapBuilder; +import org.elasticsearch.common.hppc.HppcMaps; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.lucene.search.AndFilter; @@ -88,10 +89,8 @@ public class MapperService extends AbstractIndexComponent implements Iterable nameFieldMappers = ImmutableMap.of(); - private volatile Map indexNameFieldMappers = ImmutableMap.of(); - private volatile Map fullNameFieldMappers = ImmutableMap.of(); - private volatile Map fullPathObjectMappers = ImmutableMap.of(); + private final FieldMappersLookup fieldMappers = new FieldMappersLookup(); + private volatile ObjectObjectOpenHashMap fullPathObjectMappers = HppcMaps.newMap(); private boolean hasNested = false; // updated dynamically to true when a nested object is added private final DocumentMapperParser documentParser; @@ -296,7 +295,7 @@ public class MapperService extends AbstractIndexComponent implements Iterable fullPathObjectMappers = newMapBuilder(this.fullPathObjectMappers); + ObjectObjectOpenHashMap fullPathObjectMappers = this.fullPathObjectMappers.clone(); for (ObjectMapper objectMapper : objectMappers) { ObjectMappers mappers = fullPathObjectMappers.get(objectMapper.fullPath()); if (mappers == null) { @@ -310,46 +309,13 @@ public class MapperService extends AbstractIndexComponent implements Iterable nameFieldMappers = newMapBuilder(this.nameFieldMappers); - MapBuilder indexNameFieldMappers = newMapBuilder(this.indexNameFieldMappers); - MapBuilder fullNameFieldMappers = newMapBuilder(this.fullNameFieldMappers); - for (FieldMapper fieldMapper : fieldMappers) { - FieldMappers mappers = nameFieldMappers.get(fieldMapper.names().name()); - if (mappers == null) { - mappers = new FieldMappers(fieldMapper); - } else { - mappers = mappers.concat(fieldMapper); - } - nameFieldMappers.put(fieldMapper.names().name(), mappers); - - - mappers = indexNameFieldMappers.get(fieldMapper.names().indexName()); - if (mappers == null) { - mappers = new FieldMappers(fieldMapper); - } else { - mappers = mappers.concat(fieldMapper); - } - indexNameFieldMappers.put(fieldMapper.names().indexName(), mappers); - - - mappers = fullNameFieldMappers.get(fieldMapper.names().fullName()); - if (mappers == null) { - mappers = new FieldMappers(fieldMapper); - } else { - mappers = mappers.concat(fieldMapper); - } - fullNameFieldMappers.put(fieldMapper.names().fullName(), mappers); - } - - this.nameFieldMappers = nameFieldMappers.map(); - this.indexNameFieldMappers = indexNameFieldMappers.map(); - this.fullNameFieldMappers = fullNameFieldMappers.map(); + this.fieldMappers.addNewMappers(Arrays.asList(fieldMappers)); } } @@ -370,47 +336,9 @@ public class MapperService extends AbstractIndexComponent implements Iterable nameFieldMappers = newMapBuilder(this.nameFieldMappers); - MapBuilder indexNameFieldMappers = newMapBuilder(this.indexNameFieldMappers); - MapBuilder fullNameFieldMappers = newMapBuilder(this.fullNameFieldMappers); + fieldMappers.removeMappers(docMapper.mappers()); - for (FieldMapper mapper : docMapper.mappers()) { - FieldMappers mappers = nameFieldMappers.get(mapper.names().name()); - if (mappers != null) { - mappers = mappers.remove(mapper); - if (mappers.isEmpty()) { - nameFieldMappers.remove(mapper.names().name()); - } else { - nameFieldMappers.put(mapper.names().name(), mappers); - } - } - - mappers = indexNameFieldMappers.get(mapper.names().indexName()); - if (mappers != null) { - mappers = mappers.remove(mapper); - if (mappers.isEmpty()) { - indexNameFieldMappers.remove(mapper.names().indexName()); - } else { - indexNameFieldMappers.put(mapper.names().indexName(), mappers); - } - } - - mappers = fullNameFieldMappers.get(mapper.names().fullName()); - if (mappers != null) { - mappers = mappers.remove(mapper); - if (mappers.isEmpty()) { - fullNameFieldMappers.remove(mapper.names().fullName()); - } else { - fullNameFieldMappers.put(mapper.names().fullName(), mappers); - } - } - } - this.nameFieldMappers = nameFieldMappers.map(); - this.indexNameFieldMappers = indexNameFieldMappers.map(); - this.fullNameFieldMappers = fullNameFieldMappers.map(); - - MapBuilder fullPathObjectMappers = newMapBuilder(this.fullPathObjectMappers); + ObjectObjectOpenHashMap fullPathObjectMappers = this.fullPathObjectMappers.clone(); for (ObjectMapper mapper : docMapper.objectMappers().values()) { ObjectMappers mappers = fullPathObjectMappers.get(mapper.fullPath()); if (mappers != null) { @@ -423,7 +351,7 @@ public class MapperService extends AbstractIndexComponent implements Iterable fields = Sets.newHashSet(); - for (Map.Entry entry : fullNameFieldMappers.entrySet()) { - if (Regex.simpleMatch(pattern, entry.getKey())) { - for (FieldMapper mapper : entry.getValue()) { - fields.add(mapper.names().indexName()); - } - } - } - for (Map.Entry entry : indexNameFieldMappers.entrySet()) { - if (Regex.simpleMatch(pattern, entry.getKey())) { - for (FieldMapper mapper : entry.getValue()) { - fields.add(mapper.names().indexName()); - } - } - } - for (Map.Entry entry : nameFieldMappers.entrySet()) { - if (Regex.simpleMatch(pattern, entry.getKey())) { - for (FieldMapper mapper : entry.getValue()) { - fields.add(mapper.names().indexName()); - } - } - } - return fields; + return fieldMappers.simpleMatchToIndexNames(pattern); } public SmartNameObjectMapper smartNameObjectMapper(String smartName, @Nullable String[] types) { @@ -1060,12 +966,12 @@ public class MapperService extends AbstractIndexComponent implements Iterable mappers = ImmutableMap.of(); + private volatile ObjectObjectOpenHashMap mappers = HppcMaps.newMap(); private final Object mutex = new Object(); @@ -303,7 +303,9 @@ public class ObjectMapper implements Mapper, AllFieldMapper.IncludeInAll { this.dynamic = dynamic; this.pathType = pathType; if (mappers != null) { - this.mappers = copyOf(mappers); + for (Map.Entry entry : mappers.entrySet()) { + this.mappers.put(entry.getKey(), entry.getValue()); + } } this.nestedTypePathAsString = "__" + fullPath; this.nestedTypePathAsBytes = new BytesRef(nestedTypePathAsString); @@ -322,9 +324,9 @@ public class ObjectMapper implements Mapper, AllFieldMapper.IncludeInAll { } this.includeInAll = includeInAll; // when called from outside, apply this on all the inner mappers - for (Mapper mapper : mappers.values()) { - if (mapper instanceof AllFieldMapper.IncludeInAll) { - ((AllFieldMapper.IncludeInAll) mapper).includeInAll(includeInAll); + for (ObjectObjectCursor cursor : mappers) { + if (cursor.value instanceof AllFieldMapper.IncludeInAll) { + ((AllFieldMapper.IncludeInAll) cursor.value).includeInAll(includeInAll); } } } @@ -335,9 +337,9 @@ public class ObjectMapper implements Mapper, AllFieldMapper.IncludeInAll { this.includeInAll = includeInAll; } // when called from outside, apply this on all the inner mappers - for (Mapper mapper : mappers.values()) { - if (mapper instanceof AllFieldMapper.IncludeInAll) { - ((AllFieldMapper.IncludeInAll) mapper).includeInAllIfNotSet(includeInAll); + for (ObjectObjectCursor cursor : mappers) { + if (cursor.value instanceof AllFieldMapper.IncludeInAll) { + ((AllFieldMapper.IncludeInAll) cursor.value).includeInAllIfNotSet(includeInAll); } } } @@ -355,23 +357,25 @@ public class ObjectMapper implements Mapper, AllFieldMapper.IncludeInAll { ((AllFieldMapper.IncludeInAll) mapper).includeInAllIfNotSet(includeInAll); } synchronized (mutex) { - mappers = newMapBuilder(mappers).put(mapper.name(), mapper).immutableMap(); + ObjectObjectOpenHashMap mappers = this.mappers.clone(); + mappers.put(mapper.name(), mapper); + this.mappers = mappers; } return this; } @Override public void traverse(FieldMapperListener fieldMapperListener) { - for (Mapper mapper : mappers.values()) { - mapper.traverse(fieldMapperListener); + for (ObjectObjectCursor cursor : mappers) { + cursor.value.traverse(fieldMapperListener); } } @Override public void traverse(ObjectMapperListener objectMapperListener) { objectMapperListener.objectMapper(this); - for (Mapper mapper : mappers.values()) { - mapper.traverse(objectMapperListener); + for (ObjectObjectCursor cursor : mappers) { + cursor.value.traverse(objectMapperListener); } } @@ -835,7 +839,8 @@ public class ObjectMapper implements Mapper, AllFieldMapper.IncludeInAll { FieldMapperListener.Aggregator newFieldMappers = new FieldMapperListener.Aggregator(); ObjectMapperListener.Aggregator newObjectMappers = new ObjectMapperListener.Aggregator(); synchronized (mutex) { - for (Mapper mergeWithMapper : mergeWithObject.mappers.values()) { + for (ObjectObjectCursor cursor : mergeWithObject.mappers) { + Mapper mergeWithMapper = cursor.value; Mapper mergeIntoMapper = mappers.get(mergeWithMapper.name()); if (mergeIntoMapper == null) { // no mapping, simply add it if not simulating @@ -882,8 +887,8 @@ public class ObjectMapper implements Mapper, AllFieldMapper.IncludeInAll { @Override public void close() { - for (Mapper mapper : mappers.values()) { - mapper.close(); + for (ObjectObjectCursor cursor : mappers) { + cursor.value.close(); } } @@ -926,7 +931,10 @@ public class ObjectMapper implements Mapper, AllFieldMapper.IncludeInAll { doXContent(builder, params); // sort the mappers so we get consistent serialization format - TreeMap sortedMappers = new TreeMap(mappers); + TreeMap sortedMappers = new TreeMap(); + for (ObjectObjectCursor cursor : mappers) { + sortedMappers.put(cursor.key, cursor.value); + } // check internal mappers first (this is only relevant for root object) for (Mapper mapper : sortedMappers.values()) {