private static ObjectMapper parseValue( final ParseContext context, ObjectMapper parentMapper, String currentFieldName, XContentParser.Token token) throws IOException { if (currentFieldName == null) { throw new MapperParsingException( "object mapping [" + parentMapper.name() + "] trying to serialize a value with no field associated with it, current value [" + context.parser().textOrNull() + "]"); } Mapper mapper = parentMapper.getMapper(currentFieldName); if (mapper != null) { Mapper subUpdate = parseObjectOrField(context, mapper); if (subUpdate == null) { return null; } return parentMapper.mappingUpdate(subUpdate); } else { return parseDynamicValue(context, parentMapper, currentFieldName, token); } }
private static ObjectMapper parseNonDynamicArray( ParseContext context, ObjectMapper mapper, String lastFieldName, String arrayFieldName) throws IOException { XContentParser parser = context.parser(); XContentParser.Token token; while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { if (token == XContentParser.Token.START_OBJECT) { return parseObject(context, mapper, lastFieldName); } else if (token == XContentParser.Token.START_ARRAY) { return parseArray(context, mapper, lastFieldName); } else if (token == XContentParser.Token.FIELD_NAME) { lastFieldName = parser.currentName(); } else if (token == XContentParser.Token.VALUE_NULL) { parseNullValue(context, mapper, lastFieldName); } else if (token == null) { throw new MapperParsingException( "object mapping for [" + mapper.name() + "] with array for [" + arrayFieldName + "] tried to parse as array, but got EOF, is there a mismatch in types for the same field?"); } else { return parseValue(context, mapper, lastFieldName, token); } } return null; }
private static ObjectMapper parseObject( final ParseContext context, ObjectMapper mapper, String currentFieldName) throws IOException { if (currentFieldName == null) { throw new MapperParsingException( "object mapping [" + mapper.name() + "] trying to serialize an object with no field associated with it, current value [" + context.parser().textOrNull() + "]"); } context.path().add(currentFieldName); ObjectMapper update = null; Mapper objectMapper = mapper.getMapper(currentFieldName); if (objectMapper != null) { final Mapper subUpdate = parseObjectOrField(context, objectMapper); if (subUpdate != null) { // propagate mapping update update = mapper.mappingUpdate(subUpdate); } } else { ObjectMapper.Dynamic dynamic = mapper.dynamic(); if (dynamic == null) { dynamic = dynamicOrDefault(context.root().dynamic()); } if (dynamic == ObjectMapper.Dynamic.STRICT) { throw new StrictDynamicMappingException(mapper.fullPath(), currentFieldName); } else if (dynamic == ObjectMapper.Dynamic.TRUE) { // remove the current field name from path, since template search and the object builder add // it as well... context.path().remove(); Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "object"); if (builder == null) { builder = MapperBuilders.object(currentFieldName).enabled(true); // if this is a non root object, then explicitly set the dynamic behavior if set if (!(mapper instanceof RootObjectMapper) && mapper.dynamic() != ObjectMapper.Defaults.DYNAMIC) { ((ObjectMapper.Builder) builder).dynamic(mapper.dynamic()); } } Mapper.BuilderContext builderContext = new Mapper.BuilderContext(context.indexSettings(), context.path()); objectMapper = builder.build(builderContext); context.path().add(currentFieldName); update = mapper.mappingUpdate(parseAndMergeUpdate(objectMapper, context)); } else { // not dynamic, read everything up to end object context.parser().skipChildren(); } } context.path().remove(); return update; }
private InternalSearchHit.InternalNestedIdentity getInternalNestedIdentity( SearchContext context, int nestedSubDocId, LeafReaderContext subReaderContext, DocumentMapper documentMapper, ObjectMapper nestedObjectMapper) throws IOException { int currentParent = nestedSubDocId; ObjectMapper nestedParentObjectMapper; StringBuilder field = new StringBuilder(); ObjectMapper current = nestedObjectMapper; InternalSearchHit.InternalNestedIdentity nestedIdentity = null; do { Filter parentFilter; nestedParentObjectMapper = documentMapper.findParentObjectMapper(current); if (field.length() != 0) { field.insert(0, '.'); } field.insert(0, current.name()); if (nestedParentObjectMapper != null) { if (nestedParentObjectMapper.nested().isNested() == false) { current = nestedParentObjectMapper; continue; } parentFilter = nestedParentObjectMapper.nestedTypeFilter(); } else { parentFilter = Queries.newNonNestedFilter(); } Filter childFilter = nestedObjectMapper.nestedTypeFilter(); if (childFilter == null) { current = nestedParentObjectMapper; continue; } // We can pass down 'null' as acceptedDocs, because we're fetching matched docId that matched // in the query phase. DocIdSet childDocSet = childFilter.getDocIdSet(subReaderContext, null); if (childDocSet == null) { current = nestedParentObjectMapper; continue; } DocIdSetIterator childIter = childDocSet.iterator(); if (childIter == null) { current = nestedParentObjectMapper; continue; } BitDocIdSet parentBitSet = context .bitsetFilterCache() .getBitDocIdSetFilter(parentFilter) .getDocIdSet(subReaderContext); BitSet parentBits = parentBitSet.bits(); int offset = 0; int nextParent = parentBits.nextSetBit(currentParent); for (int docId = childIter.advance(currentParent + 1); docId < nextParent && docId != DocIdSetIterator.NO_MORE_DOCS; docId = childIter.nextDoc()) { offset++; } currentParent = nextParent; current = nestedObjectMapper = nestedParentObjectMapper; nestedIdentity = new InternalSearchHit.InternalNestedIdentity(field.toString(), offset, nestedIdentity); field = new StringBuilder(); } while (current != null); return nestedIdentity; }
static ObjectMapper parseObject(ParseContext context, ObjectMapper mapper, boolean atRoot) throws IOException { if (mapper.isEnabled() == false) { context.parser().skipChildren(); return null; } XContentParser parser = context.parser(); String currentFieldName = parser.currentName(); if (atRoot && MapperService.isMetadataField(currentFieldName) && Version.indexCreated(context.indexSettings()).onOrAfter(Version.V_2_0_0_beta1)) { throw new MapperParsingException( "Field [" + currentFieldName + "] is a metadata field and cannot be added inside a document. Use the index API request parameters."); } XContentParser.Token token = parser.currentToken(); if (token == XContentParser.Token.VALUE_NULL) { // the object is null ("obj1" : null), simply bail return null; } if (token.isValue()) { throw new MapperParsingException( "object mapping for [" + mapper.name() + "] tried to parse field [" + currentFieldName + "] as object, but found a concrete value"); } ObjectMapper.Nested nested = mapper.nested(); if (nested.isNested()) { context = context.createNestedContext(mapper.fullPath()); ParseContext.Document nestedDoc = context.doc(); ParseContext.Document parentDoc = nestedDoc.getParent(); // pre add the uid field if possible (id was already provided) IndexableField uidField = parentDoc.getField(UidFieldMapper.NAME); 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 also rely on this for UidField#loadVersion // this is a deeply nested field nestedDoc.add( new Field( UidFieldMapper.NAME, uidField.stringValue(), UidFieldMapper.Defaults.NESTED_FIELD_TYPE)); } // the type of the nested doc starts with __, so we can identify that its a nested one in // filters // note, we don't prefix it with the type of the doc since it allows us to execute a nested // query // across types (for example, with similar nested objects) nestedDoc.add( new Field( TypeFieldMapper.NAME, mapper.nestedTypePathAsString(), TypeFieldMapper.Defaults.FIELD_TYPE)); } // if we are at the end of the previous object, advance if (token == XContentParser.Token.END_OBJECT) { token = parser.nextToken(); } if (token == XContentParser.Token.START_OBJECT) { // if we are just starting an OBJECT, advance, this is the object we are parsing, we need the // name first token = parser.nextToken(); } ObjectMapper update = null; while (token != XContentParser.Token.END_OBJECT) { ObjectMapper newUpdate = null; if (token == XContentParser.Token.START_OBJECT) { newUpdate = parseObject(context, mapper, currentFieldName); } else if (token == XContentParser.Token.START_ARRAY) { newUpdate = parseArray(context, mapper, currentFieldName); } else if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); } else if (token == XContentParser.Token.VALUE_NULL) { parseNullValue(context, mapper, currentFieldName); } else if (token == null) { throw new MapperParsingException( "object mapping for [" + mapper.name() + "] tried to parse field [" + currentFieldName + "] as object, but got EOF, has a concrete value been provided to it?"); } else if (token.isValue()) { newUpdate = parseValue(context, mapper, currentFieldName, token); } token = parser.nextToken(); if (newUpdate != null) { if (update == null) { update = newUpdate; } else { update = update.merge(newUpdate, false); } } } // restore the enable path flag if (nested.isNested()) { ParseContext.Document nestedDoc = context.doc(); ParseContext.Document parentDoc = nestedDoc.getParent(); if (nested.isIncludeInParent()) { for (IndexableField field : nestedDoc.getFields()) { if (field.name().equals(UidFieldMapper.NAME) || field.name().equals(TypeFieldMapper.NAME)) { continue; } else { parentDoc.add(field); } } } if (nested.isIncludeInRoot()) { ParseContext.Document rootDoc = context.rootDoc(); // don't add it twice, if its included in parent, and we are handling the master doc... if (!nested.isIncludeInParent() || parentDoc != rootDoc) { for (IndexableField field : nestedDoc.getFields()) { if (field.name().equals(UidFieldMapper.NAME) || field.name().equals(TypeFieldMapper.NAME)) { continue; } else { rootDoc.add(field); } } } } } return update; }