Mappings: Added support for empty field arrays

Close #7271
This commit is contained in:
Cristiano Fontes 2014-08-26 12:16:50 +08:00 committed by Adrien Grand
parent b6cdb1d8fb
commit ee46c3cd3f
3 changed files with 134 additions and 22 deletions

View File

@ -249,8 +249,18 @@ public class TypeParsers {
if (propName.equals("path")) {
builder.multiFieldPathType(parsePathType(name, propNode.toString()));
} else if (propName.equals("fields")) {
@SuppressWarnings("unchecked")
Map<String, Object> multiFieldsPropNodes = (Map<String, Object>) propNode;
final Map<String, Object> multiFieldsPropNodes;
if (propNode instanceof List && ((List<?>) propNode).isEmpty()) {
multiFieldsPropNodes = Collections.emptyMap();
} else if (propNode instanceof Map) {
multiFieldsPropNodes = (Map<String, Object>) propNode;
} else {
throw new MapperParsingException("Expected map for property [fields] on field [" + propNode + "] or " +
"[" + propName + "] but got a " + propNode.getClass());
}
for (Map.Entry<String, Object> multiFieldEntry : multiFieldsPropNodes.entrySet()) {
String multiFieldName = multiFieldEntry.getKey();
if (!(multiFieldEntry.getValue() instanceof Map)) {

View File

@ -259,31 +259,38 @@ public class ObjectMapper implements Mapper, AllFieldMapper.IncludeInAll {
protected static void parseProperties(ObjectMapper.Builder objBuilder, Map<String, Object> propsNode, ParserContext parserContext) {
for (Map.Entry<String, Object> entry : propsNode.entrySet()) {
String propName = entry.getKey();
Map<String, Object> propNode = (Map<String, Object>) entry.getValue();
//Should accept empty arrays, as a work around for when the user can't provide an empty Map. (PHP for example)
boolean isEmptyList = entry.getValue() instanceof List && ((List<?>) entry.getValue()).isEmpty();
String type;
Object typeNode = propNode.get("type");
if (typeNode != null) {
type = typeNode.toString();
} else {
// lets see if we can derive this...
if (propNode.get("properties") != null) {
type = ObjectMapper.CONTENT_TYPE;
} else if (propNode.size() == 1 && propNode.get("enabled") != null) {
// if there is a single property with the enabled flag on it, make it an object
// (usually, setting enabled to false to not index any type, including core values, which
// non enabled object type supports).
type = ObjectMapper.CONTENT_TYPE;
if (entry.getValue() instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> propNode = (Map<String, Object>) entry.getValue();
String type;
Object typeNode = propNode.get("type");
if (typeNode != null) {
type = typeNode.toString();
} else {
throw new MapperParsingException("No type specified for property [" + propName + "]");
// lets see if we can derive this...
if (propNode.get("properties") != null) {
type = ObjectMapper.CONTENT_TYPE;
} else if (propNode.size() == 1 && propNode.get("enabled") != null) {
// if there is a single property with the enabled flag on it, make it an object
// (usually, setting enabled to false to not index any type, including core values, which
// non enabled object type supports).
type = ObjectMapper.CONTENT_TYPE;
} else {
throw new MapperParsingException("No type specified for property [" + propName + "]");
}
}
}
Mapper.TypeParser typeParser = parserContext.typeParser(type);
if (typeParser == null) {
throw new MapperParsingException("No handler for type [" + type + "] declared on field [" + propName + "]");
Mapper.TypeParser typeParser = parserContext.typeParser(type);
if (typeParser == null) {
throw new MapperParsingException("No handler for type [" + type + "] declared on field [" + propName + "]");
}
objBuilder.add(typeParser.parse(propName, propNode, parserContext));
} else if (!isEmptyList) {
throw new MapperParsingException("Expected map for property [fields] on field [" + propName + "] but got a " + propName.getClass());
}
objBuilder.add(typeParser.parse(propName, propNode, parserContext));
}
}

View File

@ -63,4 +63,99 @@ public class SimpleObjectMappingTests extends ElasticsearchSingleNodeTest {
.endObject().endObject().string();
createIndex("test").mapperService().documentMapperParser().parse(mapping);
}
@Test
public void emptyFieldsArrayMultiFieldsTest() throws Exception {
String mapping = XContentFactory.jsonBuilder()
.startObject()
.startObject("tweet")
.startObject("properties")
.startObject("name")
.field("type", "string")
.field("index", "analyzed")
.startArray("fields")
.endArray()
.endObject()
.endObject()
.endObject()
.endObject()
.string();
createIndex("test").mapperService().documentMapperParser().parse(mapping);
}
@Test(expected = MapperParsingException.class)
public void fieldsArrayMultiFieldsShouldThrowExceptionTest() throws Exception {
String mapping = XContentFactory.jsonBuilder()
.startObject()
.startObject("tweet")
.startObject("properties")
.startObject("name")
.field("type", "string")
.field("index", "analyzed")
.startArray("fields")
.field("test", "string")
.field("test2", "string")
.endArray()
.endObject()
.endObject()
.endObject()
.endObject()
.string();
createIndex("test").mapperService().documentMapperParser().parse(mapping);
}
@Test
public void emptyFieldsArrayTest() throws Exception {
String mapping = XContentFactory.jsonBuilder()
.startObject()
.startObject("tweet")
.startObject("properties")
.startArray("fields")
.endArray()
.endObject()
.endObject()
.endObject()
.string();
createIndex("test").mapperService().documentMapperParser().parse(mapping);
}
@Test(expected = MapperParsingException.class)
public void fieldsWithFilledArrayShouldThrowExceptionTest() throws Exception {
String mapping = XContentFactory.jsonBuilder()
.startObject()
.startObject("tweet")
.startObject("properties")
.startArray("fields")
.field("test", "string")
.field("test2", "string")
.endArray()
.endObject()
.endObject()
.endObject()
.string();
createIndex("test").mapperService().documentMapperParser().parse(mapping);
}
@Test
public void fieldPropertiesArrayTest() throws Exception {
String mapping = XContentFactory.jsonBuilder()
.startObject()
.startObject("tweet")
.startObject("properties")
.startObject("name")
.field("type", "string")
.field("index", "analyzed")
.startObject("fields")
.startObject("raw")
.field("type", "string")
.field("index","not_analyzed")
.endObject()
.endObject()
.endObject()
.endObject()
.endObject()
.endObject()
.string();
createIndex("test").mapperService().documentMapperParser().parse(mapping);
}
}