more refactoring to generalize root level field mappers
This commit is contained in:
parent
821c3524a2
commit
a9bc775213
|
@ -48,10 +48,7 @@ import org.elasticsearch.index.mapper.object.ObjectMapper;
|
|||
import org.elasticsearch.index.mapper.object.RootObjectMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
@ -140,13 +137,7 @@ public class DocumentMapper implements ToXContent {
|
|||
|
||||
private IdFieldMapper idFieldMapper = new IdFieldMapper();
|
||||
|
||||
private RoutingFieldMapper routingFieldMapper = new RoutingFieldMapper();
|
||||
|
||||
private BoostFieldMapper boostFieldMapper = new BoostFieldMapper();
|
||||
|
||||
private ParentFieldMapper parentFieldMapper = null;
|
||||
|
||||
private Map<String, RootMapper> rootMappers = new HashMap<String, RootMapper>();
|
||||
private Map<Class<? extends RootMapper>, RootMapper> rootMappers = Maps.newHashMap();
|
||||
|
||||
private NamedAnalyzer indexAnalyzer;
|
||||
|
||||
|
@ -170,12 +161,15 @@ public class DocumentMapper implements ToXContent {
|
|||
}
|
||||
}
|
||||
// add default mappers
|
||||
this.rootMappers.put(SizeFieldMapper.NAME, new SizeFieldMapper());
|
||||
this.rootMappers.put(IndexFieldMapper.NAME, new IndexFieldMapper());
|
||||
this.rootMappers.put(SourceFieldMapper.NAME, new SourceFieldMapper());
|
||||
this.rootMappers.put(TypeFieldMapper.NAME, new TypeFieldMapper());
|
||||
this.rootMappers.put(AllFieldMapper.NAME, new AllFieldMapper());
|
||||
this.rootMappers.put(AnalyzerMapper.NAME, new AnalyzerMapper());
|
||||
this.rootMappers.put(SizeFieldMapper.class, new SizeFieldMapper());
|
||||
this.rootMappers.put(IndexFieldMapper.class, new IndexFieldMapper());
|
||||
this.rootMappers.put(SourceFieldMapper.class, new SourceFieldMapper());
|
||||
this.rootMappers.put(TypeFieldMapper.class, new TypeFieldMapper());
|
||||
this.rootMappers.put(AllFieldMapper.class, new AllFieldMapper());
|
||||
this.rootMappers.put(AnalyzerMapper.class, new AnalyzerMapper());
|
||||
this.rootMappers.put(BoostFieldMapper.class, new BoostFieldMapper());
|
||||
this.rootMappers.put(RoutingFieldMapper.class, new RoutingFieldMapper());
|
||||
// don't add parent field, by default its "null"
|
||||
}
|
||||
|
||||
public Builder meta(ImmutableMap<String, Object> meta) {
|
||||
|
@ -184,7 +178,8 @@ public class DocumentMapper implements ToXContent {
|
|||
}
|
||||
|
||||
public Builder put(RootMapper.Builder mapper) {
|
||||
rootMappers.put(mapper.name(), (RootMapper) mapper.build(builderContext));
|
||||
RootMapper rootMapper = (RootMapper) mapper.build(builderContext);
|
||||
rootMappers.put(rootMapper.getClass(), rootMapper);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -198,21 +193,6 @@ public class DocumentMapper implements ToXContent {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder routingField(RoutingFieldMapper.Builder builder) {
|
||||
this.routingFieldMapper = builder.build(builderContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder parentFiled(ParentFieldMapper.Builder builder) {
|
||||
this.parentFieldMapper = builder.build(builderContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder boostField(BoostFieldMapper.Builder builder) {
|
||||
this.boostFieldMapper = builder.build(builderContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder indexAnalyzer(NamedAnalyzer indexAnalyzer) {
|
||||
this.indexAnalyzer = indexAnalyzer;
|
||||
return this;
|
||||
|
@ -234,7 +214,7 @@ public class DocumentMapper implements ToXContent {
|
|||
public DocumentMapper build(DocumentMapperParser docMapperParser) {
|
||||
Preconditions.checkNotNull(rootObjectMapper, "Mapper builder must have the root object mapper set");
|
||||
return new DocumentMapper(index, docMapperParser, rootObjectMapper, meta, uidFieldMapper, idFieldMapper,
|
||||
parentFieldMapper, routingFieldMapper, indexAnalyzer, searchAnalyzer, boostFieldMapper,
|
||||
indexAnalyzer, searchAnalyzer,
|
||||
rootMappers);
|
||||
}
|
||||
}
|
||||
|
@ -260,15 +240,9 @@ public class DocumentMapper implements ToXContent {
|
|||
|
||||
private final IdFieldMapper idFieldMapper;
|
||||
|
||||
private final RoutingFieldMapper routingFieldMapper;
|
||||
|
||||
private final ParentFieldMapper parentFieldMapper;
|
||||
|
||||
private final BoostFieldMapper boostFieldMapper;
|
||||
|
||||
private final RootObjectMapper rootObjectMapper;
|
||||
|
||||
private final ImmutableMap<String, RootMapper> rootMappers;
|
||||
private final ImmutableMap<Class<? extends RootMapper>, RootMapper> rootMappers;
|
||||
private final RootMapper[] rootMappersOrdered;
|
||||
private final RootMapper[] rootMappersNotIncludedInObject;
|
||||
|
||||
|
@ -295,11 +269,8 @@ public class DocumentMapper implements ToXContent {
|
|||
ImmutableMap<String, Object> meta,
|
||||
UidFieldMapper uidFieldMapper,
|
||||
IdFieldMapper idFieldMapper,
|
||||
@Nullable ParentFieldMapper parentFieldMapper,
|
||||
RoutingFieldMapper routingFieldMapper,
|
||||
NamedAnalyzer indexAnalyzer, NamedAnalyzer searchAnalyzer,
|
||||
@Nullable BoostFieldMapper boostFieldMapper,
|
||||
Map<String, RootMapper> rootMappers) {
|
||||
Map<Class<? extends RootMapper>, RootMapper> rootMappers) {
|
||||
this.index = index;
|
||||
this.type = rootObjectMapper.name();
|
||||
this.docMapperParser = docMapperParser;
|
||||
|
@ -307,9 +278,6 @@ public class DocumentMapper implements ToXContent {
|
|||
this.rootObjectMapper = rootObjectMapper;
|
||||
this.uidFieldMapper = uidFieldMapper;
|
||||
this.idFieldMapper = idFieldMapper;
|
||||
this.parentFieldMapper = parentFieldMapper;
|
||||
this.routingFieldMapper = routingFieldMapper;
|
||||
this.boostFieldMapper = boostFieldMapper;
|
||||
|
||||
this.rootMappers = ImmutableMap.copyOf(rootMappers);
|
||||
this.rootMappersOrdered = rootMappers.values().toArray(new RootMapper[rootMappers.values().size()]);
|
||||
|
@ -327,15 +295,10 @@ public class DocumentMapper implements ToXContent {
|
|||
this.typeFilter = typeMapper().fieldFilter(type);
|
||||
|
||||
rootObjectMapper.putMapper(idFieldMapper);
|
||||
if (boostFieldMapper != null) {
|
||||
rootObjectMapper.putMapper(boostFieldMapper);
|
||||
if (rootMapper(ParentFieldMapper.class) != null) {
|
||||
// mark the routing field mapper as required
|
||||
rootMapper(RoutingFieldMapper.class).markAsRequired();
|
||||
}
|
||||
if (parentFieldMapper != null) {
|
||||
rootObjectMapper.putMapper(parentFieldMapper);
|
||||
// also, mark the routing as required!
|
||||
routingFieldMapper.markAsRequired();
|
||||
}
|
||||
rootObjectMapper.putMapper(routingFieldMapper);
|
||||
|
||||
final List<FieldMapper> tempFieldMappers = newArrayList();
|
||||
for (RootMapper rootMapper : rootMappersOrdered) {
|
||||
|
@ -395,28 +358,28 @@ public class DocumentMapper implements ToXContent {
|
|||
return this.uidFieldMapper;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"}) public <T extends RootMapper> T rootMapper(String name) {
|
||||
return (T) rootMappers.get(name);
|
||||
@SuppressWarnings({"unchecked"}) public <T extends RootMapper> T rootMapper(Class<T> type) {
|
||||
return (T) rootMappers.get(type);
|
||||
}
|
||||
|
||||
public TypeFieldMapper typeMapper() {
|
||||
return rootMapper(TypeFieldMapper.NAME);
|
||||
return rootMapper(TypeFieldMapper.class);
|
||||
}
|
||||
|
||||
public SourceFieldMapper sourceMapper() {
|
||||
return rootMapper(SourceFieldMapper.NAME);
|
||||
return rootMapper(SourceFieldMapper.class);
|
||||
}
|
||||
|
||||
public AllFieldMapper allFieldMapper() {
|
||||
return rootMapper(AllFieldMapper.NAME);
|
||||
return rootMapper(AllFieldMapper.class);
|
||||
}
|
||||
|
||||
public RoutingFieldMapper routingFieldMapper() {
|
||||
return this.routingFieldMapper;
|
||||
return rootMapper(RoutingFieldMapper.class);
|
||||
}
|
||||
|
||||
public ParentFieldMapper parentFieldMapper() {
|
||||
return this.parentFieldMapper;
|
||||
return rootMapper(ParentFieldMapper.class);
|
||||
}
|
||||
|
||||
public Analyzer indexAnalyzer() {
|
||||
|
@ -515,10 +478,6 @@ public class DocumentMapper implements ToXContent {
|
|||
context.id(source.id());
|
||||
uidFieldMapper.parse(context);
|
||||
}
|
||||
if (source.routing() != null) {
|
||||
context.externalValue(source.routing());
|
||||
routingFieldMapper.parse(context);
|
||||
}
|
||||
|
||||
if (!emptyDoc) {
|
||||
rootObjectMapper.parse(context);
|
||||
|
@ -563,17 +522,9 @@ public class DocumentMapper implements ToXContent {
|
|||
rootMapper.postParse(context);
|
||||
}
|
||||
|
||||
if (parentFieldMapper != null) {
|
||||
parentFieldMapper.parse(context);
|
||||
}
|
||||
|
||||
|
||||
for (RootMapper rootMapper : rootMappersOrdered) {
|
||||
rootMapper.validate(context);
|
||||
}
|
||||
|
||||
// validate aggregated mappers (TODO: need to be added as a phase to any field mapper)
|
||||
routingFieldMapper.validate(context);
|
||||
} catch (IOException e) {
|
||||
throw new MapperParsingException("Failed to parse", e);
|
||||
} finally {
|
||||
|
@ -638,7 +589,7 @@ public class DocumentMapper implements ToXContent {
|
|||
MergeContext mergeContext = new MergeContext(this, mergeFlags);
|
||||
rootObjectMapper.merge(mergeWith.rootObjectMapper, mergeContext);
|
||||
|
||||
for (Map.Entry<String, RootMapper> entry : rootMappers.entrySet()) {
|
||||
for (Map.Entry<Class<? extends RootMapper>, RootMapper> entry : rootMappers.entrySet()) {
|
||||
// root mappers included in root object will get merge in the rootObjectMapper
|
||||
if (entry.getValue().includeInObject()) {
|
||||
continue;
|
||||
|
@ -680,8 +631,6 @@ public class DocumentMapper implements ToXContent {
|
|||
}
|
||||
|
||||
@Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
List<Mapper> additional = new ArrayList<Mapper>();
|
||||
additional.addAll(Arrays.asList(rootMappersNotIncludedInObject));
|
||||
rootObjectMapper.toXContent(builder, params, new ToXContent() {
|
||||
@Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
if (indexAnalyzer != null && searchAnalyzer != null && indexAnalyzer.name().equals(searchAnalyzer.name()) && !indexAnalyzer.name().startsWith("_")) {
|
||||
|
@ -709,7 +658,7 @@ public class DocumentMapper implements ToXContent {
|
|||
}
|
||||
// no need to pass here id and boost, since they are added to the root object mapper
|
||||
// in the constructor
|
||||
}, additional.toArray(new Mapper[additional.size()]));
|
||||
}, rootMappersNotIncludedInObject);
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@ import org.elasticsearch.index.settings.IndexSettings;
|
|||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.support.XContentMapValues.*;
|
||||
import static org.elasticsearch.index.mapper.MapperBuilders.*;
|
||||
import static org.elasticsearch.index.mapper.core.TypeParsers.*;
|
||||
|
||||
|
@ -95,6 +94,9 @@ public class DocumentMapperParser extends AbstractIndexComponent {
|
|||
.put(TypeFieldMapper.NAME, new TypeFieldMapper.TypeParser())
|
||||
.put(AllFieldMapper.NAME, new AllFieldMapper.TypeParser())
|
||||
.put(AnalyzerMapper.NAME, new AnalyzerMapper.TypeParser())
|
||||
.put(BoostFieldMapper.NAME, new BoostFieldMapper.TypeParser())
|
||||
.put(ParentFieldMapper.NAME, new ParentFieldMapper.TypeParser())
|
||||
.put(RoutingFieldMapper.NAME, new RoutingFieldMapper.TypeParser())
|
||||
.immutableMap();
|
||||
}
|
||||
|
||||
|
@ -163,12 +165,6 @@ public class DocumentMapperParser extends AbstractIndexComponent {
|
|||
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 (RoutingFieldMapper.CONTENT_TYPE.equals(fieldName)) {
|
||||
docBuilder.routingField(parseRoutingField((Map<String, Object>) fieldNode, parserContext));
|
||||
} else if (ParentFieldMapper.CONTENT_TYPE.equals(fieldName)) {
|
||||
docBuilder.parentFiled(parseParentField((Map<String, Object>) fieldNode, parserContext));
|
||||
} else if (BoostFieldMapper.CONTENT_TYPE.equals(fieldName) || "boostField".equals(fieldName)) {
|
||||
docBuilder.boostField(parseBoostField((Map<String, Object>) fieldNode, parserContext));
|
||||
} else if ("index_analyzer".equals(fieldName)) {
|
||||
docBuilder.indexAnalyzer(analysisService.analyzer(fieldNode.toString()));
|
||||
} else if ("search_analyzer".equals(fieldName)) {
|
||||
|
@ -208,54 +204,12 @@ public class DocumentMapperParser extends AbstractIndexComponent {
|
|||
return builder;
|
||||
}
|
||||
|
||||
private BoostFieldMapper.Builder parseBoostField(Map<String, Object> boostNode, Mapper.TypeParser.ParserContext parserContext) {
|
||||
String name = boostNode.get("name") == null ? BoostFieldMapper.Defaults.NAME : boostNode.get("name").toString();
|
||||
BoostFieldMapper.Builder builder = boost(name);
|
||||
parseNumberField(builder, name, boostNode, parserContext);
|
||||
for (Map.Entry<String, Object> entry : boostNode.entrySet()) {
|
||||
String propName = Strings.toUnderscoreCase(entry.getKey());
|
||||
Object propNode = entry.getValue();
|
||||
if (propName.equals("null_value")) {
|
||||
builder.nullValue(nodeFloatValue(propNode));
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// NOTE, we also parse this in MappingMetaData
|
||||
private RoutingFieldMapper.Builder parseRoutingField(Map<String, Object> routingNode, Mapper.TypeParser.ParserContext parserContext) {
|
||||
RoutingFieldMapper.Builder builder = routing();
|
||||
parseField(builder, builder.name, routingNode, parserContext);
|
||||
for (Map.Entry<String, Object> entry : routingNode.entrySet()) {
|
||||
String fieldName = Strings.toUnderscoreCase(entry.getKey());
|
||||
Object fieldNode = entry.getValue();
|
||||
if (fieldName.equals("required")) {
|
||||
builder.required(nodeBooleanValue(fieldNode));
|
||||
} else if (fieldName.equals("path")) {
|
||||
builder.path(fieldNode.toString());
|
||||
}
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
private ParentFieldMapper.Builder parseParentField(Map<String, Object> parentNode, Mapper.TypeParser.ParserContext parserContext) {
|
||||
ParentFieldMapper.Builder builder = new ParentFieldMapper.Builder();
|
||||
for (Map.Entry<String, Object> entry : parentNode.entrySet()) {
|
||||
String fieldName = Strings.toUnderscoreCase(entry.getKey());
|
||||
Object fieldNode = entry.getValue();
|
||||
if (fieldName.equals("type")) {
|
||||
builder.type(fieldNode.toString());
|
||||
}
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private Tuple<String, Map<String, Object>> extractMapping(String type, String source) throws MapperParsingException {
|
||||
Map<String, Object> root;
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.apache.lucene.search.NumericRangeQuery;
|
|||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.util.NumericUtils;
|
||||
import org.elasticsearch.common.Numbers;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.analysis.NamedAnalyzer;
|
||||
|
@ -35,21 +36,29 @@ import org.elasticsearch.index.cache.field.data.FieldDataCache;
|
|||
import org.elasticsearch.index.field.data.FieldDataType;
|
||||
import org.elasticsearch.index.mapper.InternalMapper;
|
||||
import org.elasticsearch.index.mapper.Mapper;
|
||||
import org.elasticsearch.index.mapper.MapperBuilders;
|
||||
import org.elasticsearch.index.mapper.MapperParsingException;
|
||||
import org.elasticsearch.index.mapper.MergeContext;
|
||||
import org.elasticsearch.index.mapper.MergeMappingException;
|
||||
import org.elasticsearch.index.mapper.ParseContext;
|
||||
import org.elasticsearch.index.mapper.RootMapper;
|
||||
import org.elasticsearch.index.mapper.core.FloatFieldMapper;
|
||||
import org.elasticsearch.index.mapper.core.NumberFieldMapper;
|
||||
import org.elasticsearch.index.search.NumericRangeFieldDataFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.support.XContentMapValues.*;
|
||||
import static org.elasticsearch.index.mapper.core.TypeParsers.*;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class BoostFieldMapper extends NumberFieldMapper<Float> implements InternalMapper {
|
||||
public class BoostFieldMapper extends NumberFieldMapper<Float> implements InternalMapper, RootMapper {
|
||||
|
||||
public static final String CONTENT_TYPE = "_boost";
|
||||
public static final String NAME = "_boost";
|
||||
|
||||
public static class Defaults extends NumberFieldMapper.Defaults {
|
||||
public static final String NAME = "_boost";
|
||||
|
@ -80,6 +89,21 @@ public class BoostFieldMapper extends NumberFieldMapper<Float> implements Intern
|
|||
}
|
||||
}
|
||||
|
||||
public static class TypeParser implements Mapper.TypeParser {
|
||||
@Override public Mapper.Builder parse(String fieldName, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
|
||||
String name = node.get("name") == null ? BoostFieldMapper.Defaults.NAME : node.get("name").toString();
|
||||
BoostFieldMapper.Builder builder = MapperBuilders.boost(name);
|
||||
parseNumberField(builder, name, node, parserContext);
|
||||
for (Map.Entry<String, Object> entry : node.entrySet()) {
|
||||
String propName = Strings.toUnderscoreCase(entry.getKey());
|
||||
Object propNode = entry.getValue();
|
||||
if (propName.equals("null_value")) {
|
||||
builder.nullValue(nodeFloatValue(propNode));
|
||||
}
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
private final Float nullValue;
|
||||
|
||||
|
@ -160,6 +184,19 @@ public class BoostFieldMapper extends NumberFieldMapper<Float> implements Intern
|
|||
includeLower, includeUpper);
|
||||
}
|
||||
|
||||
@Override public void preParse(ParseContext context) throws IOException {
|
||||
}
|
||||
|
||||
@Override public void postParse(ParseContext context) throws IOException {
|
||||
}
|
||||
|
||||
@Override public void validate(ParseContext context) throws MapperParsingException {
|
||||
}
|
||||
|
||||
@Override public boolean includeInObject() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public void parse(ParseContext context) throws IOException {
|
||||
// we override parse since we want to handle cases where it is not indexed and not stored (the default)
|
||||
float value = parseFloatValue(context);
|
||||
|
|
|
@ -22,6 +22,7 @@ package org.elasticsearch.index.mapper.internal;
|
|||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.document.Fieldable;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.lucene.Lucene;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.index.mapper.InternalMapper;
|
||||
|
@ -30,15 +31,17 @@ import org.elasticsearch.index.mapper.MapperParsingException;
|
|||
import org.elasticsearch.index.mapper.MergeContext;
|
||||
import org.elasticsearch.index.mapper.MergeMappingException;
|
||||
import org.elasticsearch.index.mapper.ParseContext;
|
||||
import org.elasticsearch.index.mapper.RootMapper;
|
||||
import org.elasticsearch.index.mapper.Uid;
|
||||
import org.elasticsearch.index.mapper.core.AbstractFieldMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class ParentFieldMapper extends AbstractFieldMapper<Uid> implements InternalMapper {
|
||||
public class ParentFieldMapper extends AbstractFieldMapper<Uid> implements InternalMapper, RootMapper {
|
||||
|
||||
public static final String NAME = "_parent";
|
||||
|
||||
|
@ -75,6 +78,20 @@ public class ParentFieldMapper extends AbstractFieldMapper<Uid> implements Inter
|
|||
}
|
||||
}
|
||||
|
||||
public static class TypeParser implements Mapper.TypeParser {
|
||||
@Override public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
|
||||
ParentFieldMapper.Builder builder = new ParentFieldMapper.Builder();
|
||||
for (Map.Entry<String, Object> entry : node.entrySet()) {
|
||||
String fieldName = Strings.toUnderscoreCase(entry.getKey());
|
||||
Object fieldNode = entry.getValue();
|
||||
if (fieldName.equals("type")) {
|
||||
builder.type(fieldNode.toString());
|
||||
}
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
private final String type;
|
||||
|
||||
protected ParentFieldMapper(String name, String indexName, String type) {
|
||||
|
@ -87,6 +104,20 @@ public class ParentFieldMapper extends AbstractFieldMapper<Uid> implements Inter
|
|||
return type;
|
||||
}
|
||||
|
||||
@Override public void preParse(ParseContext context) throws IOException {
|
||||
}
|
||||
|
||||
@Override public void postParse(ParseContext context) throws IOException {
|
||||
parse(context);
|
||||
}
|
||||
|
||||
@Override public void validate(ParseContext context) throws MapperParsingException {
|
||||
}
|
||||
|
||||
@Override public boolean includeInObject() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override protected Field parseCreateField(ParseContext context) throws IOException {
|
||||
if (context.parser().currentName() != null && context.parser().currentName().equals(Defaults.NAME)) {
|
||||
// we are in the parsing of _parent phase
|
||||
|
|
|
@ -22,6 +22,7 @@ package org.elasticsearch.index.mapper.internal;
|
|||
import org.apache.lucene.document.Document;
|
||||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.document.Fieldable;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.lucene.Lucene;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.index.mapper.InternalMapper;
|
||||
|
@ -30,15 +31,22 @@ import org.elasticsearch.index.mapper.MapperParsingException;
|
|||
import org.elasticsearch.index.mapper.MergeContext;
|
||||
import org.elasticsearch.index.mapper.MergeMappingException;
|
||||
import org.elasticsearch.index.mapper.ParseContext;
|
||||
import org.elasticsearch.index.mapper.RootMapper;
|
||||
import org.elasticsearch.index.mapper.core.AbstractFieldMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.support.XContentMapValues.*;
|
||||
import static org.elasticsearch.index.mapper.MapperBuilders.*;
|
||||
import static org.elasticsearch.index.mapper.core.TypeParsers.*;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class RoutingFieldMapper extends AbstractFieldMapper<String> implements InternalMapper {
|
||||
public class RoutingFieldMapper extends AbstractFieldMapper<String> implements InternalMapper, RootMapper {
|
||||
|
||||
public static final String NAME = "_routing";
|
||||
public static final String CONTENT_TYPE = "_routing";
|
||||
|
||||
public static class Defaults extends AbstractFieldMapper.Defaults {
|
||||
|
@ -78,6 +86,24 @@ public class RoutingFieldMapper extends AbstractFieldMapper<String> implements I
|
|||
}
|
||||
}
|
||||
|
||||
public static class TypeParser implements Mapper.TypeParser {
|
||||
@Override public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
|
||||
RoutingFieldMapper.Builder builder = routing();
|
||||
parseField(builder, builder.name, node, parserContext);
|
||||
for (Map.Entry<String, Object> entry : node.entrySet()) {
|
||||
String fieldName = Strings.toUnderscoreCase(entry.getKey());
|
||||
Object fieldNode = entry.getValue();
|
||||
if (fieldName.equals("required")) {
|
||||
builder.required(nodeBooleanValue(fieldNode));
|
||||
} else if (fieldName.equals("path")) {
|
||||
builder.path(fieldNode.toString());
|
||||
}
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean required;
|
||||
|
||||
private final String path;
|
||||
|
@ -126,7 +152,7 @@ public class RoutingFieldMapper extends AbstractFieldMapper<String> implements I
|
|||
return value;
|
||||
}
|
||||
|
||||
public void validate(ParseContext context) throws MapperParsingException {
|
||||
@Override public void validate(ParseContext context) throws MapperParsingException {
|
||||
String routing = context.sourceToParse().routing();
|
||||
if (path != null && routing != null) {
|
||||
// we have a path, check if we can validate we have the same routing value as the one in the doc...
|
||||
|
@ -140,9 +166,26 @@ public class RoutingFieldMapper extends AbstractFieldMapper<String> implements I
|
|||
}
|
||||
}
|
||||
|
||||
@Override public void preParse(ParseContext context) throws IOException {
|
||||
super.parse(context);
|
||||
}
|
||||
|
||||
@Override public void postParse(ParseContext context) throws IOException {
|
||||
}
|
||||
|
||||
@Override public void parse(ParseContext context) throws IOException {
|
||||
// no need ot parse here, we either get the routing in the sourceToParse
|
||||
// or we don't have routing, if we get it in sourceToParse, we process it in preParse
|
||||
// which will always be called
|
||||
}
|
||||
|
||||
@Override public boolean includeInObject() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override protected Field parseCreateField(ParseContext context) throws IOException {
|
||||
if (context.externalValueSet()) {
|
||||
String routing = (String) context.externalValue();
|
||||
if (context.sourceToParse().routing() != null) {
|
||||
String routing = context.sourceToParse().routing();
|
||||
if (routing != null) {
|
||||
if (!indexed() && !stored()) {
|
||||
context.ignoredValue(names.indexName(), routing);
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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.boost;
|
||||
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.index.mapper.DocumentMapper;
|
||||
import org.elasticsearch.index.mapper.MapperTests;
|
||||
import org.elasticsearch.index.mapper.ParsedDocument;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
/**
|
||||
*/
|
||||
@Test
|
||||
public class BoostMappingTests {
|
||||
|
||||
@Test public void testDefaultMapping() throws Exception {
|
||||
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type").endObject().endObject().string();
|
||||
|
||||
DocumentMapper mapper = MapperTests.newParser().parse(mapping);
|
||||
|
||||
ParsedDocument doc = mapper.parse("type", "1", XContentFactory.jsonBuilder().startObject()
|
||||
.field("_boost", 2.0f)
|
||||
.endObject().copiedBytes());
|
||||
assertThat(doc.rootDoc().getBoost(), equalTo(2.0f));
|
||||
}
|
||||
|
||||
@Test public void testCustomName() throws Exception {
|
||||
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
|
||||
.startObject("_boost").field("name", "custom_boost").endObject()
|
||||
.endObject().endObject().string();
|
||||
|
||||
DocumentMapper mapper = MapperTests.newParser().parse(mapping);
|
||||
|
||||
ParsedDocument doc = mapper.parse("type", "1", XContentFactory.jsonBuilder().startObject()
|
||||
.field("_boost", 2.0f)
|
||||
.endObject().copiedBytes());
|
||||
assertThat(doc.rootDoc().getBoost(), equalTo(1.0f));
|
||||
|
||||
doc = mapper.parse("type", "1", XContentFactory.jsonBuilder().startObject()
|
||||
.field("custom_boost", 2.0f)
|
||||
.endObject().copiedBytes());
|
||||
assertThat(doc.rootDoc().getBoost(), equalTo(2.0f));
|
||||
}
|
||||
}
|
|
@ -40,7 +40,7 @@ public class IndexTypeMapperTests {
|
|||
.startObject("_index").field("enabled", true).field("store", "yes").endObject()
|
||||
.endObject().endObject().string();
|
||||
DocumentMapper docMapper = MapperTests.newParser().parse(mapping);
|
||||
IndexFieldMapper indexMapper = docMapper.rootMapper(IndexFieldMapper.NAME);
|
||||
IndexFieldMapper indexMapper = docMapper.rootMapper(IndexFieldMapper.class);
|
||||
assertThat(indexMapper.enabled(), equalTo(true));
|
||||
assertThat(indexMapper.store(), equalTo(Field.Store.YES));
|
||||
assertThat(docMapper.mappers().indexName("_index").mapper(), instanceOf(IndexFieldMapper.class));
|
||||
|
@ -60,7 +60,7 @@ public class IndexTypeMapperTests {
|
|||
.startObject("_index").field("enabled", false).field("store", "yes").endObject()
|
||||
.endObject().endObject().string();
|
||||
DocumentMapper docMapper = MapperTests.newParser().parse(mapping);
|
||||
IndexFieldMapper indexMapper = docMapper.rootMapper(IndexFieldMapper.NAME);
|
||||
IndexFieldMapper indexMapper = docMapper.rootMapper(IndexFieldMapper.class);
|
||||
assertThat(indexMapper.enabled(), equalTo(false));
|
||||
assertThat(indexMapper.store(), equalTo(Field.Store.YES));
|
||||
|
||||
|
@ -78,7 +78,7 @@ public class IndexTypeMapperTests {
|
|||
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
|
||||
.endObject().endObject().string();
|
||||
DocumentMapper docMapper = MapperTests.newParser().parse(mapping);
|
||||
IndexFieldMapper indexMapper = docMapper.rootMapper(IndexFieldMapper.NAME);
|
||||
IndexFieldMapper indexMapper = docMapper.rootMapper(IndexFieldMapper.class);
|
||||
assertThat(indexMapper.enabled(), equalTo(false));
|
||||
assertThat(indexMapper.store(), equalTo(Field.Store.NO));
|
||||
|
||||
|
|
|
@ -35,6 +35,22 @@ import static org.hamcrest.Matchers.*;
|
|||
*/
|
||||
public class ParentMappingTests {
|
||||
|
||||
@Test public void parentNotMapped() throws Exception {
|
||||
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
|
||||
.endObject().endObject().string();
|
||||
DocumentMapper docMapper = MapperTests.newParser().parse(mapping);
|
||||
|
||||
ParsedDocument doc = docMapper.parse(SourceToParse.source(XContentFactory.jsonBuilder()
|
||||
.startObject()
|
||||
.field("_parent", "1122")
|
||||
.field("x_field", "x_value")
|
||||
.endObject()
|
||||
.copiedBytes()).type("type").id("1"));
|
||||
|
||||
// no _parent mapping, used as a simple field
|
||||
assertThat(doc.rootDoc().get("_parent"), equalTo("1122"));
|
||||
}
|
||||
|
||||
@Test public void parentSetInDocNotExternally() throws Exception {
|
||||
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
|
||||
.startObject("_parent").field("type", "p_type").endObject()
|
||||
|
|
Loading…
Reference in New Issue