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
This commit is contained in:
Shay Banon 2013-10-31 03:11:04 +01:00
parent f01d3a18ad
commit 5cd56e5cea
6 changed files with 329 additions and 239 deletions

View File

@ -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<String, Analyzer> analyzers;
private final ObjectObjectOpenHashMap<String, Analyzer> analyzers;
private final Analyzer defaultAnalyzer;
public FieldNameAnalyzer(Map<String, Analyzer> analyzers, Analyzer defaultAnalyzer) {
this.analyzers = ImmutableMap.copyOf(analyzers);
public FieldNameAnalyzer(ObjectObjectOpenHashMap<String, Analyzer> analyzers, Analyzer defaultAnalyzer) {
this.analyzers = analyzers;
this.defaultAnalyzer = defaultAnalyzer;
}
public ImmutableMap<String, Analyzer> analyzers() {
public ObjectObjectOpenHashMap<String, Analyzer> analyzers() {
return analyzers;
}

View File

@ -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<FieldMapper> {
private final ImmutableList<FieldMapper> fieldMappers;
private final Map<String, FieldMappers> fullNameFieldMappers;
private final Map<String, FieldMappers> nameFieldMappers;
private final Map<String, FieldMappers> 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<FieldMapper> fieldMappers) {
final Map<String, FieldMappers> tempNameFieldMappers = newHashMap();
final Map<String, FieldMappers> tempIndexNameFieldMappers = newHashMap();
final Map<String, FieldMappers> tempFullNameFieldMappers = newHashMap();
public DocumentFieldMappers(DocumentMapper docMapper) {
this.docMapper = docMapper;
this.fieldMappers = new FieldMappersLookup();
this.indexAnalyzer = new FieldNameAnalyzer(HppcMaps.<String, Analyzer>newMap(), docMapper.indexAnalyzer());
this.searchAnalyzer = new FieldNameAnalyzer(HppcMaps.<String, Analyzer>newMap(), docMapper.searchAnalyzer());
this.searchQuoteAnalyzer = new FieldNameAnalyzer(HppcMaps.<String, Analyzer>newMap(), docMapper.searchQuotedAnalyzer());
}
final Map<String, Analyzer> indexAnalyzers = newHashMap();
final Map<String, Analyzer> searchAnalyzers = newHashMap();
final Map<String, Analyzer> searchQuoteAnalyzers = newHashMap();
public void addNewMappers(Iterable<FieldMapper> 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<String, Analyzer> indexAnalyzers = this.indexAnalyzer.analyzers().clone();
final ObjectObjectOpenHashMap<String, Analyzer> searchAnalyzers = this.searchAnalyzer.analyzers().clone();
final ObjectObjectOpenHashMap<String, Analyzer> 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<FieldMapper> {
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<FieldMapper> {
}
public ImmutableList<FieldMapper> 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<String> simpleMatchToIndexNames(String pattern) {
Set<String> 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<String> simpleMatchToFullName(String pattern) {
Set<String> 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<FieldMapper> {
* 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<FieldMapper> {
public Analyzer searchQuoteAnalyzer() {
return this.searchQuoteAnalyzer;
}
public DocumentFieldMappers concat(DocumentMapper docMapper, FieldMapper... fieldMappers) {
return concat(docMapper, newArrayList(fieldMappers));
}
public DocumentFieldMappers concat(DocumentMapper docMapper, Iterable<FieldMapper> fieldMappers) {
return new DocumentFieldMappers(docMapper, Iterables.concat(this.fieldMappers, fieldMappers));
}
}

View File

@ -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<String, ObjectMapper> 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<String, ObjectMapper> 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);

View File

@ -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<FieldMapper> {
private volatile ImmutableList<FieldMapper> mappers;
private volatile ObjectObjectOpenHashMap<String, FieldMappers> name;
private volatile ObjectObjectOpenHashMap<String, FieldMappers> indexName;
private volatile ObjectObjectOpenHashMap<String, FieldMappers> 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<FieldMapper> newMappers) {
final ObjectObjectOpenHashMap<String, FieldMappers> tempName = this.name.clone();
final ObjectObjectOpenHashMap<String, FieldMappers> tempIndexName = this.indexName.clone();
final ObjectObjectOpenHashMap<String, FieldMappers> 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.<FieldMapper>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<FieldMapper> mappersToRemove) {
List<FieldMapper> tempMappers = new ArrayList<FieldMapper>(this.mappers);
ObjectObjectOpenHashMap<String, FieldMappers> tempName = this.name.clone();
ObjectObjectOpenHashMap<String, FieldMappers> tempIndexName = this.indexName.clone();
ObjectObjectOpenHashMap<String, FieldMappers> 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<FieldMapper> iterator() {
return mappers.iterator();
}
/**
* The list of all mappers.
*/
public ImmutableList<FieldMapper> 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<String> simpleMatchToIndexNames(String pattern) {
Set<String> 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<String> simpleMatchToFullName(String pattern) {
Set<String> 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();
}
}

View File

@ -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<Do
private final Object typeMutex = new Object();
private final Object mappersMutex = new Object();
private volatile Map<String, FieldMappers> nameFieldMappers = ImmutableMap.of();
private volatile Map<String, FieldMappers> indexNameFieldMappers = ImmutableMap.of();
private volatile Map<String, FieldMappers> fullNameFieldMappers = ImmutableMap.of();
private volatile Map<String, ObjectMappers> fullPathObjectMappers = ImmutableMap.of();
private final FieldMappersLookup fieldMappers = new FieldMappersLookup();
private volatile ObjectObjectOpenHashMap<String, ObjectMappers> 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<Do
private void addObjectMappers(ObjectMapper[] objectMappers) {
synchronized (mappersMutex) {
MapBuilder<String, ObjectMappers> fullPathObjectMappers = newMapBuilder(this.fullPathObjectMappers);
ObjectObjectOpenHashMap<String, ObjectMappers> 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<Do
hasNested = true;
}
}
this.fullPathObjectMappers = fullPathObjectMappers.map();
this.fullPathObjectMappers = fullPathObjectMappers;
}
}
private void addFieldMappers(FieldMapper[] fieldMappers) {
synchronized (mappersMutex) {
MapBuilder<String, FieldMappers> nameFieldMappers = newMapBuilder(this.nameFieldMappers);
MapBuilder<String, FieldMappers> indexNameFieldMappers = newMapBuilder(this.indexNameFieldMappers);
MapBuilder<String, FieldMappers> 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<Do
private void removeObjectAndFieldMappers(DocumentMapper docMapper) {
synchronized (mappersMutex) {
// we need to remove those mappers
MapBuilder<String, FieldMappers> nameFieldMappers = newMapBuilder(this.nameFieldMappers);
MapBuilder<String, FieldMappers> indexNameFieldMappers = newMapBuilder(this.indexNameFieldMappers);
MapBuilder<String, FieldMappers> 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<String, ObjectMappers> fullPathObjectMappers = newMapBuilder(this.fullPathObjectMappers);
ObjectObjectOpenHashMap<String, ObjectMappers> 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<Do
}
}
this.fullPathObjectMappers = fullPathObjectMappers.map();
this.fullPathObjectMappers = fullPathObjectMappers;
}
}
@ -566,7 +494,7 @@ public class MapperService extends AbstractIndexComponent implements Iterable<Do
* @return All the {@link FieldMappers} for across all {@link DocumentMapper}s
*/
public FieldMappers name(String name) {
return nameFieldMappers.get(name);
return fieldMappers.name(name);
}
/**
@ -577,7 +505,7 @@ public class MapperService extends AbstractIndexComponent implements Iterable<Do
* @return All the {@link FieldMappers} across all {@link DocumentMapper}s for the given indexName.
*/
public FieldMappers indexName(String indexName) {
return indexNameFieldMappers.get(indexName);
return fieldMappers.indexName(indexName);
}
/**
@ -588,7 +516,7 @@ public class MapperService extends AbstractIndexComponent implements Iterable<Do
* @return All teh {@link FieldMappers} across all the {@link DocumentMapper}s for the given fullName.
*/
public FieldMappers fullName(String fullName) {
return fullNameFieldMappers.get(fullName);
return fieldMappers.fullName(fullName);
}
/**
@ -644,29 +572,7 @@ public class MapperService extends AbstractIndexComponent implements Iterable<Do
return typedFields;
}
}
Set<String> fields = Sets.newHashSet();
for (Map.Entry<String, FieldMappers> entry : fullNameFieldMappers.entrySet()) {
if (Regex.simpleMatch(pattern, entry.getKey())) {
for (FieldMapper mapper : entry.getValue()) {
fields.add(mapper.names().indexName());
}
}
}
for (Map.Entry<String, FieldMappers> entry : indexNameFieldMappers.entrySet()) {
if (Regex.simpleMatch(pattern, entry.getKey())) {
for (FieldMapper mapper : entry.getValue()) {
fields.add(mapper.names().indexName());
}
}
}
for (Map.Entry<String, FieldMappers> 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<Do
return possibleDocMapper.mappers().searchAnalyzer();
}
}
FieldMappers mappers = fullNameFieldMappers.get(fieldName);
FieldMappers mappers = fieldMappers.fullName(fieldName);
if (mappers != null && mappers.mapper() != null && mappers.mapper().searchAnalyzer() != null) {
return mappers.mapper().searchAnalyzer();
}
mappers = indexNameFieldMappers.get(fieldName);
mappers = fieldMappers.indexName(fieldName);
if (mappers != null && mappers.mapper() != null && mappers.mapper().searchAnalyzer() != null) {
return mappers.mapper().searchAnalyzer();
}
@ -1096,12 +1002,12 @@ public class MapperService extends AbstractIndexComponent implements Iterable<Do
return possibleDocMapper.mappers().searchQuoteAnalyzer();
}
}
FieldMappers mappers = fullNameFieldMappers.get(fieldName);
FieldMappers mappers = fieldMappers.fullName(fieldName);
if (mappers != null && mappers.mapper() != null && mappers.mapper().searchQuoteAnalyzer() != null) {
return mappers.mapper().searchQuoteAnalyzer();
}
mappers = indexNameFieldMappers.get(fieldName);
mappers = fieldMappers.indexName(fieldName);
if (mappers != null && mappers.mapper() != null && mappers.mapper().searchQuoteAnalyzer() != null) {
return mappers.mapper().searchQuoteAnalyzer();
}

View File

@ -19,7 +19,8 @@
package org.elasticsearch.index.mapper.object;
import com.google.common.collect.ImmutableMap;
import com.carrotsearch.hppc.ObjectObjectOpenHashMap;
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexableField;
@ -29,6 +30,7 @@ import org.apache.lucene.search.Filter;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.ElasticSearchIllegalStateException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.hppc.HppcMaps;
import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
@ -42,9 +44,7 @@ import org.elasticsearch.index.mapper.multifield.MultiFieldMapper;
import java.io.IOException;
import java.util.*;
import static com.google.common.collect.ImmutableMap.copyOf;
import static com.google.common.collect.Lists.newArrayList;
import static org.elasticsearch.common.collect.MapBuilder.newMapBuilder;
import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeBooleanValue;
import static org.elasticsearch.index.mapper.MapperBuilders.*;
import static org.elasticsearch.index.mapper.core.TypeParsers.parsePathType;
@ -291,7 +291,7 @@ public class ObjectMapper implements Mapper, AllFieldMapper.IncludeInAll {
private Boolean includeInAll;
private volatile ImmutableMap<String, Mapper> mappers = ImmutableMap.of();
private volatile ObjectObjectOpenHashMap<String, Mapper> 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<String, Mapper> 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<String, Mapper> 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<String, Mapper> 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<String, Mapper> 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<String, Mapper> 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<String, Mapper> 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<String, Mapper> 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<String, Mapper> 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<String, Mapper> sortedMappers = new TreeMap<String, Mapper>(mappers);
TreeMap<String, Mapper> sortedMappers = new TreeMap<String, Mapper>();
for (ObjectObjectCursor<String, Mapper> cursor : mappers) {
sortedMappers.put(cursor.key, cursor.value);
}
// check internal mappers first (this is only relevant for root object)
for (Mapper mapper : sortedMappers.values()) {