@Override public Mapper.Builder<?, ?> parse( String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException { ContentPath.Type pathType = null; FieldMapper.Builder mainFieldBuilder = null; List<FieldMapper.Builder> fields = null; String firstType = null; for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext(); ) { Map.Entry<String, Object> entry = iterator.next(); String fieldName = Strings.toUnderscoreCase(entry.getKey()); Object fieldNode = entry.getValue(); if (fieldName.equals("path") && parserContext.indexVersionCreated().before(Version.V_2_0_0_beta1)) { pathType = parsePathType(name, fieldNode.toString()); iterator.remove(); } else if (fieldName.equals("fields")) { Map<String, Object> fieldsNode = (Map<String, Object>) fieldNode; for (Iterator<Map.Entry<String, Object>> fieldsIterator = fieldsNode.entrySet().iterator(); fieldsIterator.hasNext(); ) { Map.Entry<String, Object> entry1 = fieldsIterator.next(); String propName = entry1.getKey(); Map<String, Object> propNode = (Map<String, Object>) entry1.getValue(); String type; Object typeNode = propNode.get("type"); if (typeNode != null) { type = typeNode.toString(); if (firstType == null) { firstType = 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 [" + fieldName + "]"); } if (propName.equals(name)) { mainFieldBuilder = (FieldMapper.Builder) typeParser.parse(propName, propNode, parserContext); fieldsIterator.remove(); } else { if (fields == null) { fields = new ArrayList<>(2); } fields.add( (FieldMapper.Builder) typeParser.parse(propName, propNode, parserContext)); fieldsIterator.remove(); } } fieldsNode.remove("type"); DocumentMapperParser.checkNoRemainingFields( fieldName, fieldsNode, parserContext.indexVersionCreated()); iterator.remove(); } } if (mainFieldBuilder == null) { if (fields == null) { // No fields at all were specified in multi_field, so lets return a non indexed string // field. return new StringFieldMapper.Builder(name).index(false); } Mapper.TypeParser typeParser = parserContext.typeParser(firstType); if (typeParser == null) { // The first multi field's type is unknown mainFieldBuilder = new StringFieldMapper.Builder(name).index(false); } else { Mapper.Builder substitute = typeParser.parse(name, Collections.<String, Object>emptyMap(), parserContext); if (substitute instanceof FieldMapper.Builder) { mainFieldBuilder = ((FieldMapper.Builder) substitute).index(false); } else { // The first multi isn't a core field type mainFieldBuilder = new StringFieldMapper.Builder(name).index(false); } } } if (fields != null && pathType != null) { for (Mapper.Builder field : fields) { mainFieldBuilder.addMultiField(field); } mainFieldBuilder.multiFieldPathType(pathType); } else if (fields != null) { for (Mapper.Builder field : fields) { mainFieldBuilder.addMultiField(field); } } else if (pathType != null) { mainFieldBuilder.multiFieldPathType(pathType); } return mainFieldBuilder; }
public static boolean parseMultiField( FieldMapper.Builder builder, String name, Mapper.TypeParser.ParserContext parserContext, String propName, Object propNode) { parserContext = parserContext.createMultiFieldContext(parserContext); if (propName.equals("path") && parserContext.indexVersionCreated().before(Version.V_2_0_0_beta1)) { builder.multiFieldPathType(parsePathType(name, propNode.toString())); return true; } else if (propName.equals("fields")) { 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 (multiFieldName.contains(".")) { throw new MapperParsingException( "Field name [" + multiFieldName + "] which is a multi field of [" + name + "] cannot contain '.'"); } if (!(multiFieldEntry.getValue() instanceof Map)) { throw new MapperParsingException( "illegal field [" + multiFieldName + "], only fields can be specified inside fields"); } @SuppressWarnings("unchecked") Map<String, Object> multiFieldNodes = (Map<String, Object>) multiFieldEntry.getValue(); String type; Object typeNode = multiFieldNodes.get("type"); if (typeNode != null) { type = typeNode.toString(); } else { throw new MapperParsingException( "no type specified for property [" + multiFieldName + "]"); } if (type.equals(ObjectMapper.CONTENT_TYPE) || type.equals(ObjectMapper.NESTED_CONTENT_TYPE)) { throw new MapperParsingException("Type [" + type + "] cannot be used in multi field"); } Mapper.TypeParser typeParser = parserContext.typeParser(type); if (typeParser == null) { throw new MapperParsingException( "no handler for type [" + type + "] declared on field [" + multiFieldName + "]"); } builder.addMultiField(typeParser.parse(multiFieldName, multiFieldNodes, parserContext)); multiFieldNodes.remove("type"); DocumentMapperParser.checkNoRemainingFields( propName, multiFieldNodes, parserContext.indexVersionCreated()); } return true; } return false; }