more work on simplifying mapper parsing code

This commit is contained in:
Shay Banon 2011-08-19 01:34:22 +03:00
parent 8d2123a452
commit 5fa072263d
7 changed files with 203 additions and 118 deletions

View File

@ -35,7 +35,6 @@ import org.elasticsearch.common.compress.lzf.LZF;
import org.elasticsearch.common.io.stream.BytesStreamInput; import org.elasticsearch.common.io.stream.BytesStreamInput;
import org.elasticsearch.common.io.stream.CachedStreamInput; import org.elasticsearch.common.io.stream.CachedStreamInput;
import org.elasticsearch.common.io.stream.LZFStreamInput; import org.elasticsearch.common.io.stream.LZFStreamInput;
import org.elasticsearch.common.lucene.uid.UidField;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
@ -133,10 +132,6 @@ public class DocumentMapper implements ToXContent {
public static class Builder { public static class Builder {
private UidFieldMapper uidFieldMapper = new UidFieldMapper();
private IdFieldMapper idFieldMapper = new IdFieldMapper();
private Map<Class<? extends RootMapper>, RootMapper> rootMappers = Maps.newHashMap(); private Map<Class<? extends RootMapper>, RootMapper> rootMappers = Maps.newHashMap();
private NamedAnalyzer indexAnalyzer; private NamedAnalyzer indexAnalyzer;
@ -154,12 +149,14 @@ public class DocumentMapper implements ToXContent {
public Builder(String index, @Nullable Settings indexSettings, RootObjectMapper.Builder builder) { public Builder(String index, @Nullable Settings indexSettings, RootObjectMapper.Builder builder) {
this.index = index; this.index = index;
this.rootObjectMapper = builder.build(builderContext); this.rootObjectMapper = builder.build(builderContext);
IdFieldMapper idFieldMapper = new IdFieldMapper();
if (indexSettings != null) { if (indexSettings != null) {
String idIndexed = indexSettings.get("index.mapping._id.indexed"); String idIndexed = indexSettings.get("index.mapping._id.indexed");
if (idIndexed != null && Booleans.parseBoolean(idIndexed, false)) { if (idIndexed != null && Booleans.parseBoolean(idIndexed, false)) {
idFieldMapper = new IdFieldMapper(Field.Index.NOT_ANALYZED); idFieldMapper = new IdFieldMapper(Field.Index.NOT_ANALYZED);
} }
} }
this.rootMappers.put(IdFieldMapper.class, idFieldMapper);
// add default mappers // add default mappers
this.rootMappers.put(SizeFieldMapper.class, new SizeFieldMapper()); this.rootMappers.put(SizeFieldMapper.class, new SizeFieldMapper());
this.rootMappers.put(IndexFieldMapper.class, new IndexFieldMapper()); this.rootMappers.put(IndexFieldMapper.class, new IndexFieldMapper());
@ -169,6 +166,7 @@ public class DocumentMapper implements ToXContent {
this.rootMappers.put(AnalyzerMapper.class, new AnalyzerMapper()); this.rootMappers.put(AnalyzerMapper.class, new AnalyzerMapper());
this.rootMappers.put(BoostFieldMapper.class, new BoostFieldMapper()); this.rootMappers.put(BoostFieldMapper.class, new BoostFieldMapper());
this.rootMappers.put(RoutingFieldMapper.class, new RoutingFieldMapper()); this.rootMappers.put(RoutingFieldMapper.class, new RoutingFieldMapper());
this.rootMappers.put(UidFieldMapper.class, new UidFieldMapper());
// don't add parent field, by default its "null" // don't add parent field, by default its "null"
} }
@ -183,16 +181,6 @@ public class DocumentMapper implements ToXContent {
return this; return this;
} }
public Builder idField(IdFieldMapper.Builder builder) {
this.idFieldMapper = builder.build(builderContext);
return this;
}
public Builder uidField(UidFieldMapper.Builder builder) {
this.uidFieldMapper = builder.build(builderContext);
return this;
}
public Builder indexAnalyzer(NamedAnalyzer indexAnalyzer) { public Builder indexAnalyzer(NamedAnalyzer indexAnalyzer) {
this.indexAnalyzer = indexAnalyzer; this.indexAnalyzer = indexAnalyzer;
return this; return this;
@ -213,7 +201,7 @@ public class DocumentMapper implements ToXContent {
public DocumentMapper build(DocumentMapperParser docMapperParser) { public DocumentMapper build(DocumentMapperParser docMapperParser) {
Preconditions.checkNotNull(rootObjectMapper, "Mapper builder must have the root object mapper set"); Preconditions.checkNotNull(rootObjectMapper, "Mapper builder must have the root object mapper set");
return new DocumentMapper(index, docMapperParser, rootObjectMapper, meta, uidFieldMapper, idFieldMapper, return new DocumentMapper(index, docMapperParser, rootObjectMapper, meta,
indexAnalyzer, searchAnalyzer, indexAnalyzer, searchAnalyzer,
rootMappers); rootMappers);
} }
@ -236,10 +224,6 @@ public class DocumentMapper implements ToXContent {
private volatile CompressedString mappingSource; private volatile CompressedString mappingSource;
private final UidFieldMapper uidFieldMapper;
private final IdFieldMapper idFieldMapper;
private final RootObjectMapper rootObjectMapper; private final RootObjectMapper rootObjectMapper;
private final ImmutableMap<Class<? extends RootMapper>, RootMapper> rootMappers; private final ImmutableMap<Class<? extends RootMapper>, RootMapper> rootMappers;
@ -267,8 +251,6 @@ public class DocumentMapper implements ToXContent {
public DocumentMapper(String index, DocumentMapperParser docMapperParser, public DocumentMapper(String index, DocumentMapperParser docMapperParser,
RootObjectMapper rootObjectMapper, RootObjectMapper rootObjectMapper,
ImmutableMap<String, Object> meta, ImmutableMap<String, Object> meta,
UidFieldMapper uidFieldMapper,
IdFieldMapper idFieldMapper,
NamedAnalyzer indexAnalyzer, NamedAnalyzer searchAnalyzer, NamedAnalyzer indexAnalyzer, NamedAnalyzer searchAnalyzer,
Map<Class<? extends RootMapper>, RootMapper> rootMappers) { Map<Class<? extends RootMapper>, RootMapper> rootMappers) {
this.index = index; this.index = index;
@ -276,8 +258,6 @@ public class DocumentMapper implements ToXContent {
this.docMapperParser = docMapperParser; this.docMapperParser = docMapperParser;
this.meta = meta; this.meta = meta;
this.rootObjectMapper = rootObjectMapper; this.rootObjectMapper = rootObjectMapper;
this.uidFieldMapper = uidFieldMapper;
this.idFieldMapper = idFieldMapper;
this.rootMappers = ImmutableMap.copyOf(rootMappers); this.rootMappers = ImmutableMap.copyOf(rootMappers);
this.rootMappersOrdered = rootMappers.values().toArray(new RootMapper[rootMappers.values().size()]); this.rootMappersOrdered = rootMappers.values().toArray(new RootMapper[rootMappers.values().size()]);
@ -294,7 +274,6 @@ public class DocumentMapper implements ToXContent {
this.typeFilter = typeMapper().fieldFilter(type); this.typeFilter = typeMapper().fieldFilter(type);
rootObjectMapper.putMapper(idFieldMapper);
if (rootMapper(ParentFieldMapper.class) != null) { if (rootMapper(ParentFieldMapper.class) != null) {
// mark the routing field mapper as required // mark the routing field mapper as required
rootMapper(RoutingFieldMapper.class).markAsRequired(); rootMapper(RoutingFieldMapper.class).markAsRequired();
@ -311,8 +290,6 @@ public class DocumentMapper implements ToXContent {
} }
} }
// add the basic ones
tempFieldMappers.add(uidFieldMapper);
// now traverse and get all the statically defined ones // now traverse and get all the statically defined ones
rootObjectMapper.traverse(new FieldMapperListener() { rootObjectMapper.traverse(new FieldMapperListener() {
@Override public void fieldMapper(FieldMapper fieldMapper) { @Override public void fieldMapper(FieldMapper fieldMapper) {
@ -355,7 +332,7 @@ public class DocumentMapper implements ToXContent {
} }
public UidFieldMapper uidMapper() { public UidFieldMapper uidMapper() {
return this.uidFieldMapper; return rootMapper(UidFieldMapper.class);
} }
@SuppressWarnings({"unchecked"}) public <T extends RootMapper> T rootMapper(Class<T> type) { @SuppressWarnings({"unchecked"}) public <T extends RootMapper> T rootMapper(Class<T> type) {
@ -473,12 +450,6 @@ public class DocumentMapper implements ToXContent {
rootMapper.preParse(context); rootMapper.preParse(context);
} }
// set the id if we have it so we can validate it later on, also, add the uid if we can
if (source.id() != null) {
context.id(source.id());
uidFieldMapper.parse(context);
}
if (!emptyDoc) { if (!emptyDoc) {
rootObjectMapper.parse(context); rootObjectMapper.parse(context);
} }
@ -487,37 +458,6 @@ public class DocumentMapper implements ToXContent {
parser.nextToken(); parser.nextToken();
} }
// if we did not get the id, we need to parse the uid into the document now, after it was added
if (source.id() == null) {
if (context.id() == null) {
if (!source.flyweight()) {
throw new MapperParsingException("No id found while parsing the content source");
}
} else {
uidFieldMapper.parse(context);
if (context.docs().size() > 1) {
UidField uidField = (UidField) context.doc().getFieldable(UidFieldMapper.NAME);
assert uidField != null;
// we need to go over the docs and add it...
for (int i = 1; i < context.docs().size(); i++) {
// we don't need to add it as a full uid field in nested docs, since we don't need versioning
context.docs().get(i).add(new Field(UidFieldMapper.NAME, uidField.uid(), Field.Store.NO, Field.Index.NOT_ANALYZED));
}
}
}
}
if (context.parsedIdState() != ParseContext.ParsedIdState.PARSED) {
if (context.id() == null) {
if (!source.flyweight()) {
throw new MapperParsingException("No id mapping with [_id] found in the content, and not explicitly set");
}
} else {
// mark it as external, so we can parse it
context.parsedId(ParseContext.ParsedIdState.EXTERNAL);
idFieldMapper.parse(context);
}
}
for (RootMapper rootMapper : rootMappersOrdered) { for (RootMapper rootMapper : rootMappersOrdered) {
rootMapper.postParse(context); rootMapper.postParse(context);
} }
@ -556,7 +496,6 @@ public class DocumentMapper implements ToXContent {
public void addFieldMapperListener(FieldMapperListener fieldMapperListener, boolean includeExisting) { public void addFieldMapperListener(FieldMapperListener fieldMapperListener, boolean includeExisting) {
fieldMapperListeners.add(fieldMapperListener); fieldMapperListeners.add(fieldMapperListener);
if (includeExisting) { if (includeExisting) {
fieldMapperListener.fieldMapper(uidFieldMapper);
for (RootMapper rootMapper : rootMappersOrdered) { for (RootMapper rootMapper : rootMappersOrdered) {
if (!rootMapper.includeInObject() && rootMapper instanceof FieldMapper) { if (!rootMapper.includeInObject() && rootMapper instanceof FieldMapper) {
fieldMapperListener.fieldMapper((FieldMapper) rootMapper); fieldMapperListener.fieldMapper((FieldMapper) rootMapper);
@ -624,7 +563,6 @@ public class DocumentMapper implements ToXContent {
public void close() { public void close() {
cache.remove(); cache.remove();
rootObjectMapper.close(); rootObjectMapper.close();
idFieldMapper.close();
for (RootMapper rootMapper : rootMappersOrdered) { for (RootMapper rootMapper : rootMappersOrdered) {
rootMapper.close(); rootMapper.close();
} }

View File

@ -46,7 +46,6 @@ import java.io.IOException;
import java.util.Map; import java.util.Map;
import static org.elasticsearch.index.mapper.MapperBuilders.*; import static org.elasticsearch.index.mapper.MapperBuilders.*;
import static org.elasticsearch.index.mapper.core.TypeParsers.*;
/** /**
* @author kimchy (shay.banon) * @author kimchy (shay.banon)
@ -97,6 +96,8 @@ public class DocumentMapperParser extends AbstractIndexComponent {
.put(BoostFieldMapper.NAME, new BoostFieldMapper.TypeParser()) .put(BoostFieldMapper.NAME, new BoostFieldMapper.TypeParser())
.put(ParentFieldMapper.NAME, new ParentFieldMapper.TypeParser()) .put(ParentFieldMapper.NAME, new ParentFieldMapper.TypeParser())
.put(RoutingFieldMapper.NAME, new RoutingFieldMapper.TypeParser()) .put(RoutingFieldMapper.NAME, new RoutingFieldMapper.TypeParser())
.put(UidFieldMapper.NAME, new UidFieldMapper.TypeParser())
.put(IdFieldMapper.NAME, new IdFieldMapper.TypeParser())
.immutableMap(); .immutableMap();
} }
@ -161,11 +162,7 @@ public class DocumentMapperParser extends AbstractIndexComponent {
String fieldName = Strings.toUnderscoreCase(entry.getKey()); String fieldName = Strings.toUnderscoreCase(entry.getKey());
Object fieldNode = entry.getValue(); Object fieldNode = entry.getValue();
if (IdFieldMapper.CONTENT_TYPE.equals(fieldName) || "idField".equals(fieldName)) { if ("index_analyzer".equals(fieldName)) {
docBuilder.idField(parseIdField((Map<String, Object>) fieldNode, parserContext));
} else if (UidFieldMapper.CONTENT_TYPE.equals(fieldName) || "uidField".equals(fieldName)) {
docBuilder.uidField(parseUidField((Map<String, Object>) fieldNode, parserContext));
} else if ("index_analyzer".equals(fieldName)) {
docBuilder.indexAnalyzer(analysisService.analyzer(fieldNode.toString())); docBuilder.indexAnalyzer(analysisService.analyzer(fieldNode.toString()));
} else if ("search_analyzer".equals(fieldName)) { } else if ("search_analyzer".equals(fieldName)) {
docBuilder.searchAnalyzer(analysisService.analyzer(fieldNode.toString())); docBuilder.searchAnalyzer(analysisService.analyzer(fieldNode.toString()));
@ -199,17 +196,6 @@ public class DocumentMapperParser extends AbstractIndexComponent {
return documentMapper; return documentMapper;
} }
private UidFieldMapper.Builder parseUidField(Map<String, Object> uidNode, Mapper.TypeParser.ParserContext parserContext) {
UidFieldMapper.Builder builder = uid();
return builder;
}
private IdFieldMapper.Builder parseIdField(Map<String, Object> idNode, Mapper.TypeParser.ParserContext parserContext) {
IdFieldMapper.Builder builder = id();
parseField(builder, builder.name, idNode, parserContext);
return builder;
}
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
private Tuple<String, Map<String, Object>> extractMapping(String type, String source) throws MapperParsingException { private Tuple<String, Map<String, Object>> extractMapping(String type, String source) throws MapperParsingException {
Map<String, Object> root; Map<String, Object> root;

View File

@ -67,8 +67,6 @@ public class ParseContext {
private Map<String, String> ignoredValues = new HashMap<String, String>(); private Map<String, String> ignoredValues = new HashMap<String, String>();
private ParsedIdState parsedIdState;
private boolean mappersAdded = false; private boolean mappersAdded = false;
private boolean externalValueSet; private boolean externalValueSet;
@ -99,7 +97,6 @@ public class ParseContext {
this.sourceToParse = source; this.sourceToParse = source;
this.source = source == null ? null : sourceToParse.source(); this.source = source == null ? null : sourceToParse.source();
this.path.reset(); this.path.reset();
this.parsedIdState = ParsedIdState.NO;
this.mappersAdded = false; this.mappersAdded = false;
this.listener = listener == null ? DocumentMapper.ParseListener.EMPTY : listener; this.listener = listener == null ? DocumentMapper.ParseListener.EMPTY : listener;
this.allEntries = new AllEntries(); this.allEntries = new AllEntries();
@ -193,14 +190,6 @@ public class ParseContext {
return id; return id;
} }
public void parsedId(ParsedIdState parsedIdState) {
this.parsedIdState = parsedIdState;
}
public ParsedIdState parsedIdState() {
return this.parsedIdState;
}
public void ignoredValue(String indexName, String value) { public void ignoredValue(String indexName, String value) {
ignoredValues.put(indexName, value); ignoredValues.put(indexName, value);
} }
@ -273,10 +262,4 @@ public class ParseContext {
stringBuilder.setLength(0); stringBuilder.setLength(0);
return this.stringBuilder; return this.stringBuilder;
} }
public static enum ParsedIdState {
NO,
PARSED,
EXTERNAL
}
} }

View File

@ -24,20 +24,26 @@ import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable; import org.apache.lucene.document.Fieldable;
import org.elasticsearch.common.lucene.Lucene; import org.elasticsearch.common.lucene.Lucene;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.mapper.InternalMapper; import org.elasticsearch.index.mapper.InternalMapper;
import org.elasticsearch.index.mapper.Mapper; import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperParsingException; import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MergeContext; import org.elasticsearch.index.mapper.MergeContext;
import org.elasticsearch.index.mapper.MergeMappingException; import org.elasticsearch.index.mapper.MergeMappingException;
import org.elasticsearch.index.mapper.ParseContext; import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.RootMapper;
import org.elasticsearch.index.mapper.core.AbstractFieldMapper; import org.elasticsearch.index.mapper.core.AbstractFieldMapper;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
import static org.elasticsearch.index.mapper.MapperBuilders.*;
import static org.elasticsearch.index.mapper.core.TypeParsers.*;
/** /**
* @author kimchy (shay.banon) * @author kimchy (shay.banon)
*/ */
public class IdFieldMapper extends AbstractFieldMapper<String> implements InternalMapper { public class IdFieldMapper extends AbstractFieldMapper<String> implements InternalMapper, RootMapper {
public static final String NAME = "_id"; public static final String NAME = "_id";
@ -68,6 +74,14 @@ public class IdFieldMapper extends AbstractFieldMapper<String> implements Intern
} }
} }
public static class TypeParser implements Mapper.TypeParser {
@Override public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
IdFieldMapper.Builder builder = id();
parseField(builder, builder.name, node, parserContext);
return builder;
}
}
public IdFieldMapper() { public IdFieldMapper() {
this(Defaults.NAME, Defaults.INDEX_NAME, Defaults.INDEX); this(Defaults.NAME, Defaults.INDEX_NAME, Defaults.INDEX);
} }
@ -108,28 +122,50 @@ public class IdFieldMapper extends AbstractFieldMapper<String> implements Intern
return value; return value;
} }
@Override public void preParse(ParseContext context) throws IOException {
if (context.sourceToParse().id() != null) {
context.id(context.sourceToParse().id());
super.parse(context);
}
}
@Override public void postParse(ParseContext context) throws IOException {
if (context.id() == null && !context.sourceToParse().flyweight()) {
throw new MapperParsingException("No id found while parsing the content source");
}
// it either get built in the preParse phase, or get parsed...
}
@Override public void parse(ParseContext context) throws IOException {
super.parse(context);
}
@Override public void validate(ParseContext context) throws MapperParsingException {
}
@Override public boolean includeInObject() {
return true;
}
@Override protected Field parseCreateField(ParseContext context) throws IOException { @Override protected Field parseCreateField(ParseContext context) throws IOException {
if (context.parsedIdState() == ParseContext.ParsedIdState.NO) { XContentParser parser = context.parser();
String id = context.parser().text(); if (parser.currentName() != null && parser.currentName().equals(Defaults.NAME) && parser.currentToken().isValue()) {
// we are in the parse Phase
String id = parser.text();
if (context.id() != null && !context.id().equals(id)) { if (context.id() != null && !context.id().equals(id)) {
throw new MapperParsingException("Provided id [" + context.id() + "] does not match the content one [" + id + "]"); throw new MapperParsingException("Provided id [" + context.id() + "] does not match the content one [" + id + "]");
} }
context.id(id); context.id(id);
context.parsedId(ParseContext.ParsedIdState.PARSED);
if (index == Field.Index.NO && store == Field.Store.NO) {
return null;
}
return new Field(names.indexName(), false, context.id(), store, index, termVector);
} else if (context.parsedIdState() == ParseContext.ParsedIdState.EXTERNAL) {
if (context.id() == null) {
throw new MapperParsingException("No id mapping with [" + names.name() + "] found in the content, and not explicitly set");
}
if (index == Field.Index.NO && store == Field.Store.NO) { if (index == Field.Index.NO && store == Field.Store.NO) {
return null; return null;
} }
return new Field(names.indexName(), false, context.id(), store, index, termVector); return new Field(names.indexName(), false, context.id(), store, index, termVector);
} else { } else {
throw new MapperParsingException("Illegal parsed id state"); // we are in the pre/post parse phase
if (index == Field.Index.NO && store == Field.Store.NO) {
return null;
}
return new Field(names.indexName(), false, context.id(), store, index, termVector);
} }
} }

View File

@ -31,15 +31,19 @@ import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MergeContext; import org.elasticsearch.index.mapper.MergeContext;
import org.elasticsearch.index.mapper.MergeMappingException; import org.elasticsearch.index.mapper.MergeMappingException;
import org.elasticsearch.index.mapper.ParseContext; import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.RootMapper;
import org.elasticsearch.index.mapper.Uid; import org.elasticsearch.index.mapper.Uid;
import org.elasticsearch.index.mapper.core.AbstractFieldMapper; import org.elasticsearch.index.mapper.core.AbstractFieldMapper;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
import static org.elasticsearch.index.mapper.MapperBuilders.*;
/** /**
* @author kimchy (shay.banon) * @author kimchy (shay.banon)
*/ */
public class UidFieldMapper extends AbstractFieldMapper<Uid> implements InternalMapper { public class UidFieldMapper extends AbstractFieldMapper<Uid> implements InternalMapper, RootMapper {
public static final String NAME = "_uid"; public static final String NAME = "_uid";
@ -68,6 +72,12 @@ public class UidFieldMapper extends AbstractFieldMapper<Uid> implements Internal
} }
} }
public static class TypeParser implements Mapper.TypeParser {
@Override public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
return uid();
}
}
private ThreadLocal<UidField> fieldCache = new ThreadLocal<UidField>() { private ThreadLocal<UidField> fieldCache = new ThreadLocal<UidField>() {
@Override protected UidField initialValue() { @Override protected UidField initialValue() {
return new UidField(names().indexName(), "", 0); return new UidField(names().indexName(), "", 0);
@ -87,10 +97,48 @@ public class UidFieldMapper extends AbstractFieldMapper<Uid> implements Internal
Defaults.OMIT_NORMS, Defaults.OMIT_TERM_FREQ_AND_POSITIONS, Lucene.KEYWORD_ANALYZER, Lucene.KEYWORD_ANALYZER); Defaults.OMIT_NORMS, Defaults.OMIT_TERM_FREQ_AND_POSITIONS, Lucene.KEYWORD_ANALYZER, Lucene.KEYWORD_ANALYZER);
} }
@Override protected Fieldable parseCreateField(ParseContext context) throws IOException { @Override public void preParse(ParseContext context) throws IOException {
if (context.id() == null) { // if we have the id provided, fill it, and parse now
if (context.sourceToParse().id() != null) {
context.id(context.sourceToParse().id());
super.parse(context);
}
}
@Override public void postParse(ParseContext context) throws IOException {
if (context.id() == null && !context.sourceToParse().flyweight()) {
throw new MapperParsingException("No id found while parsing the content source"); throw new MapperParsingException("No id found while parsing the content source");
} }
// if we did not have the id as part of the sourceToParse, then we need to parse it here
// it would have been filled in the _id parse phase
if (context.sourceToParse().id() == null) {
super.parse(context);
// since we did not have the uid in the pre phase, we did not add it automatically to the nested docs
// as they were created we need to make sure we add it to all the nested docs...
if (context.docs().size() > 1) {
UidField uidField = (UidField) context.rootDoc().getFieldable(UidFieldMapper.NAME);
assert uidField != null;
// we need to go over the docs and add it...
for (int i = 1; i < context.docs().size(); i++) {
// we don't need to add it as a full uid field in nested docs, since we don't need versioning
context.docs().get(i).add(new Field(UidFieldMapper.NAME, uidField.uid(), Field.Store.NO, Field.Index.NOT_ANALYZED));
}
}
}
}
@Override public void parse(ParseContext context) throws IOException {
// nothing to do here, we either do it in post parse, or in pre parse.
}
@Override public void validate(ParseContext context) throws MapperParsingException {
}
@Override public boolean includeInObject() {
return false;
}
@Override protected Fieldable parseCreateField(ParseContext context) throws IOException {
context.uid(Uid.createUid(context.stringBuilder(), context.type(), context.id())); context.uid(Uid.createUid(context.stringBuilder(), context.type(), context.id()));
// so, caching uid stream and field is fine // so, caching uid stream and field is fine
// since we don't do any mapping parsing without immediate indexing // since we don't do any mapping parsing without immediate indexing

View File

@ -389,7 +389,7 @@ public class ObjectMapper implements Mapper, AllFieldMapper.IncludeInAll {
if (nested.isNested()) { if (nested.isNested()) {
Document nestedDoc = new Document(); Document nestedDoc = new Document();
// pre add the uid field if possible (id was already provided) // pre add the uid field if possible (id was already provided)
Fieldable uidField = (Fieldable) context.doc().getFieldable(UidFieldMapper.NAME); Fieldable uidField = context.doc().getFieldable(UidFieldMapper.NAME);
if (uidField != null) { if (uidField != null) {
// we don't need to add it as a full uid field in nested docs, since we don't need versioning // we don't need to add it as a full uid field in nested docs, since we don't need versioning
// we also rely on this for UidField#loadVersion // we also rely on this for UidField#loadVersion

View File

@ -0,0 +1,94 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.id;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MapperTests;
import org.elasticsearch.index.mapper.ParsedDocument;
import org.elasticsearch.index.mapper.internal.IdFieldMapper;
import org.elasticsearch.index.mapper.internal.UidFieldMapper;
import org.testng.annotations.Test;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
/**
*/
@Test
public class IdMappingTests {
@Test public void simpleIdTests() throws Exception {
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.endObject().endObject().string();
DocumentMapper docMapper = MapperTests.newParser().parse(mapping);
ParsedDocument doc = docMapper.parse("type", "1", XContentFactory.jsonBuilder()
.startObject()
.endObject()
.copiedBytes());
assertThat(doc.rootDoc().get(UidFieldMapper.NAME), notNullValue());
assertThat(doc.rootDoc().get(IdFieldMapper.NAME), nullValue());
try {
docMapper.parse("type", null, XContentFactory.jsonBuilder()
.startObject()
.endObject()
.copiedBytes());
assert false;
} catch (MapperParsingException e) {
}
doc = docMapper.parse("type", null, XContentFactory.jsonBuilder()
.startObject()
.field("_id", 1)
.endObject()
.copiedBytes());
assertThat(doc.rootDoc().get(UidFieldMapper.NAME), notNullValue());
assertThat(doc.rootDoc().get(IdFieldMapper.NAME), nullValue());
}
@Test public void testIdIndexed() throws Exception {
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_id").field("index", "not_analyzed").endObject()
.endObject().endObject().string();
DocumentMapper docMapper = MapperTests.newParser().parse(mapping);
ParsedDocument doc = docMapper.parse("type", "1", XContentFactory.jsonBuilder()
.startObject()
.endObject()
.copiedBytes());
assertThat(doc.rootDoc().get(UidFieldMapper.NAME), notNullValue());
assertThat(doc.rootDoc().get(IdFieldMapper.NAME), notNullValue());
doc = docMapper.parse("type", null, XContentFactory.jsonBuilder()
.startObject()
.field("_id", 1)
.endObject()
.copiedBytes());
assertThat(doc.rootDoc().get(UidFieldMapper.NAME), notNullValue());
assertThat(doc.rootDoc().get(IdFieldMapper.NAME), notNullValue());
}
}