@Override public Y build(BuilderContext context) { ContentPath.Type origPathType = context.path().pathType(); context.path().pathType(pathType); context.path().add(name); Map<String, Mapper> mappers = new HashMap<>(); for (Mapper.Builder builder : mappersBuilders) { Mapper mapper = builder.build(context); mappers.put(mapper.simpleName(), mapper); } context.path().pathType(origPathType); context.path().remove(); ObjectMapper objectMapper = createMapper( name, context.path().fullPathAsText(name), enabled, nested, dynamic, pathType, mappers, context.indexSettings()); objectMapper.includeInAllIfNotSet(includeInAll); return (Y) objectMapper; }
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); } }
/** Resolves the closest inherited {@link ObjectMapper} that is nested. */ public ObjectMapper resolveClosestNestedObjectMapper(String fieldName) { int indexOf = fieldName.lastIndexOf('.'); if (indexOf == -1) { return null; } else { do { String objectPath = fieldName.substring(0, indexOf); ObjectMappers objectMappers = objectMapper(objectPath); if (objectMappers == null) { return null; } if (objectMappers.hasNested()) { for (ObjectMapper objectMapper : objectMappers) { if (objectMapper.nested().isNested()) { return objectMapper; } } } indexOf = objectPath.lastIndexOf('.'); } while (indexOf != -1); } return null; }
/** Build a mapping update with the provided sub mapping update. */ public ObjectMapper mappingUpdate(Mapper mapper) { ObjectMapper mappingUpdate = clone(); // reset the sub mappers mappingUpdate.mappers = new CopyOnWriteHashMap<>(); mappingUpdate.putMapper(mapper); return mappingUpdate; }
private void removeObjectFieldMappers(DocumentMapper docMapper) { // we need to remove those mappers for (FieldMapper mapper : docMapper.mappers()) { FieldMappers mappers = nameFieldMappers.get(mapper.names().name()); if (mappers != null) { mappers = mappers.remove(mapper); if (mappers.isEmpty()) { nameFieldMappers = newMapBuilder(nameFieldMappers).remove(mapper.names().name()).immutableMap(); } else { nameFieldMappers = newMapBuilder(nameFieldMappers).put(mapper.names().name(), mappers).immutableMap(); } } mappers = indexNameFieldMappers.get(mapper.names().indexName()); if (mappers != null) { mappers = mappers.remove(mapper); if (mappers.isEmpty()) { indexNameFieldMappers = newMapBuilder(indexNameFieldMappers) .remove(mapper.names().indexName()) .immutableMap(); } else { indexNameFieldMappers = newMapBuilder(indexNameFieldMappers) .put(mapper.names().indexName(), mappers) .immutableMap(); } } mappers = fullNameFieldMappers.get(mapper.names().fullName()); if (mappers != null) { mappers = mappers.remove(mapper); if (mappers.isEmpty()) { fullNameFieldMappers = newMapBuilder(fullNameFieldMappers).remove(mapper.names().fullName()).immutableMap(); } else { fullNameFieldMappers = newMapBuilder(fullNameFieldMappers) .put(mapper.names().fullName(), mappers) .immutableMap(); } } } for (ObjectMapper mapper : docMapper.objectMappers().values()) { ObjectMappers mappers = objectMappers.get(mapper.fullPath()); if (mappers != null) { mappers = mappers.remove(mapper); if (mappers.isEmpty()) { objectMappers = newMapBuilder(objectMappers).remove(mapper.fullPath()).immutableMap(); } else { objectMappers = newMapBuilder(objectMappers).put(mapper.fullPath(), mappers).immutableMap(); } } } }
private void removeObjectAndFieldMappers(DocumentMapper docMapper) { // we need to remove those mappers MapBuilder<String, FieldMappers> nameFieldMappers = newMapBuilder(this.nameFieldMappers); MapBuilder<String, FieldMappers> indexNameFieldMappers = newMapBuilder(this.indexNameFieldMappers); MapBuilder<String, FieldMappers> fullNameFieldMappers = newMapBuilder(this.fullNameFieldMappers); for (FieldMapper mapper : docMapper.mappers()) { FieldMappers mappers = nameFieldMappers.get(mapper.names().name()); if (mappers != null) { mappers = mappers.remove(mapper); if (mappers.isEmpty()) { nameFieldMappers.remove(mapper.names().name()); } else { nameFieldMappers.put(mapper.names().name(), mappers); } } mappers = indexNameFieldMappers.get(mapper.names().indexName()); if (mappers != null) { mappers = mappers.remove(mapper); if (mappers.isEmpty()) { indexNameFieldMappers.remove(mapper.names().indexName()); } else { indexNameFieldMappers.put(mapper.names().indexName(), mappers); } } mappers = fullNameFieldMappers.get(mapper.names().fullName()); if (mappers != null) { mappers = mappers.remove(mapper); if (mappers.isEmpty()) { fullNameFieldMappers.remove(mapper.names().fullName()); } else { fullNameFieldMappers.put(mapper.names().fullName(), mappers); } } } this.nameFieldMappers = nameFieldMappers.map(); this.indexNameFieldMappers = indexNameFieldMappers.map(); this.fullNameFieldMappers = fullNameFieldMappers.map(); MapBuilder<String, ObjectMappers> fullPathObjectMappers = newMapBuilder(this.fullPathObjectMappers); for (ObjectMapper mapper : docMapper.objectMappers().values()) { ObjectMappers mappers = fullPathObjectMappers.get(mapper.fullPath()); if (mappers != null) { mappers = mappers.remove(mapper); if (mappers.isEmpty()) { fullPathObjectMappers.remove(mapper.fullPath()); } else { fullPathObjectMappers.put(mapper.fullPath(), mappers); } } } this.fullPathObjectMappers = fullPathObjectMappers.map(); }
// TODO: We should add: ObjectMapper#getParentObjectMapper() public ObjectMapper findParentObjectMapper(ObjectMapper objectMapper) { int indexOfLastDot = objectMapper.fullPath().lastIndexOf('.'); if (indexOfLastDot != -1) { String parentNestObjectPath = objectMapper.fullPath().substring(0, indexOfLastDot); return objectMappers().get(parentNestObjectPath); } else { return null; } }
private static void parseNullValue(ParseContext context, ObjectMapper parentMapper, String lastFieldName) throws IOException { // we can only handle null values if we have mappings for them Mapper mapper = parentMapper.getMapper(lastFieldName); if (mapper != null) { // TODO: passing null to an object seems bogus? parseObjectOrField(context, mapper); } else if (parentMapper.dynamic() == ObjectMapper.Dynamic.STRICT) { throw new StrictDynamicMappingException(parentMapper.fullPath(), lastFieldName); } }
private void setPathLevel() { ObjectMapper objectMapper = parseContext.nestedScope().getObjectMapper(); if (objectMapper == null) { parentFilter = parseContext.fixedBitSetFilter(NonNestedDocsFilter.INSTANCE); } else { parentFilter = parseContext.fixedBitSetFilter(objectMapper.nestedTypeFilter()); } childFilter = parseContext.fixedBitSetFilter(nestedObjectMapper.nestedTypeFilter()); parentObjectMapper = parseContext.nestedScope().nextLevel(nestedObjectMapper); }
private static ObjectMapper parseDynamicValue(final ParseContext context, ObjectMapper parentMapper, String currentFieldName, XContentParser.Token token) throws IOException { ObjectMapper.Dynamic dynamic = parentMapper.dynamic(); if (dynamic == null) { dynamic = dynamicOrDefault(context.root().dynamic()); } if (dynamic == ObjectMapper.Dynamic.STRICT) { throw new StrictDynamicMappingException(parentMapper.fullPath(), currentFieldName); } if (dynamic == ObjectMapper.Dynamic.FALSE) { return null; } final Mapper.BuilderContext builderContext = new Mapper.BuilderContext(context.indexSettings(), context.path()); final MappedFieldType existingFieldType = context.mapperService().fullName(context.path().fullPathAsText(currentFieldName)); Mapper.Builder builder = null; if (existingFieldType != null) { // create a builder of the same type builder = createBuilderFromFieldType(context, existingFieldType, currentFieldName); if (builder != null) { // best-effort to not introduce a conflict if (builder instanceof StringFieldMapper.Builder) { StringFieldMapper.Builder stringBuilder = (StringFieldMapper.Builder) builder; stringBuilder.fieldDataSettings(existingFieldType.fieldDataType().getSettings()); stringBuilder.store(existingFieldType.stored()); stringBuilder.indexOptions(existingFieldType.indexOptions()); stringBuilder.tokenized(existingFieldType.tokenized()); stringBuilder.omitNorms(existingFieldType.omitNorms()); stringBuilder.docValues(existingFieldType.hasDocValues()); stringBuilder.indexAnalyzer(existingFieldType.indexAnalyzer()); stringBuilder.searchAnalyzer(existingFieldType.searchAnalyzer()); } else if (builder instanceof NumberFieldMapper.Builder) { NumberFieldMapper.Builder<?,?> numberBuilder = (NumberFieldMapper.Builder<?, ?>) builder; numberBuilder.fieldDataSettings(existingFieldType.fieldDataType().getSettings()); numberBuilder.store(existingFieldType.stored()); numberBuilder.indexOptions(existingFieldType.indexOptions()); numberBuilder.tokenized(existingFieldType.tokenized()); numberBuilder.omitNorms(existingFieldType.omitNorms()); numberBuilder.docValues(existingFieldType.hasDocValues()); numberBuilder.precisionStep(existingFieldType.numericPrecisionStep()); } } } if (builder == null) { builder = createBuilderFromDynamicValue(context, token, currentFieldName); } Mapper mapper = builder.build(builderContext); mapper = parseAndMergeUpdate(mapper, context); ObjectMapper update = null; if (mapper != null) { update = parentMapper.mappingUpdate(mapper); } return update; }
protected void addMappers( Collection<ObjectMapper> objectMappers, Collection<FieldMapper> fieldMappers) { assert mappingLock.isWriteLockedByCurrentThread(); ImmutableOpenMap.Builder<String, ObjectMapper> fullPathObjectMappers = ImmutableOpenMap.builder(this.fullPathObjectMappers); for (ObjectMapper objectMapper : objectMappers) { fullPathObjectMappers.put(objectMapper.fullPath(), objectMapper); if (objectMapper.nested().isNested()) { hasNested = true; } } this.fullPathObjectMappers = fullPathObjectMappers.build(); this.fieldTypes = this.fieldTypes.copyAndAddAll(fieldMappers); }
private void checkFieldUniqueness( String type, Collection<ObjectMapper> objectMappers, Collection<FieldMapper> fieldMappers) { assert Thread.holdsLock(this); // first check within mapping final Set<String> objectFullNames = new HashSet<>(); for (ObjectMapper objectMapper : objectMappers) { final String fullPath = objectMapper.fullPath(); if (objectFullNames.add(fullPath) == false) { throw new IllegalArgumentException( "Object mapper [" + fullPath + "] is defined twice in mapping for type [" + type + "]"); } } final Set<String> fieldNames = new HashSet<>(); for (FieldMapper fieldMapper : fieldMappers) { final String name = fieldMapper.name(); if (objectFullNames.contains(name)) { throw new IllegalArgumentException( "Field [" + name + "] is defined both as an object and a field in [" + type + "]"); } else if (fieldNames.add(name) == false) { throw new IllegalArgumentException( "Field [" + name + "] is defined twice in [" + type + "]"); } } // then check other types for (String fieldName : fieldNames) { if (fullPathObjectMappers.containsKey(fieldName)) { throw new IllegalArgumentException( "[" + fieldName + "] is defined as a field in mapping [" + type + "] but this name is already used for an object in other types"); } } for (String objectPath : objectFullNames) { if (fieldTypes.get(objectPath) != null) { throw new IllegalArgumentException( "[" + objectPath + "] is defined as an object in mapping [" + type + "] but this name is already used for a field in other types"); } } }
@Override public void objectMapper(ObjectMapper objectMapper) { ObjectMappers mappers = objectMappers.get(objectMapper.fullPath()); if (mappers == null) { mappers = new ObjectMappers(objectMapper); } else { mappers = mappers.concat(objectMapper); } objectMappers = newMapBuilder(objectMappers).put(objectMapper.fullPath(), mappers).immutableMap(); // update the hasNested flag if (objectMapper.nested().isNested()) { hasNested = true; } }
private void addObjectMappers(ObjectMapper... objectMappers) { synchronized (mutex) { MapBuilder<String, ObjectMapper> builder = MapBuilder.newMapBuilder(this.objectMappers); for (ObjectMapper objectMapper : objectMappers) { builder.put(objectMapper.fullPath(), objectMapper); if (objectMapper.nested().isNested()) { hasNestedObjects = true; } } this.objectMappers = builder.immutableMap(); } for (ObjectMapperListener objectMapperListener : objectMapperListeners) { objectMapperListener.objectMappers(objectMappers); } }
private static ObjectMapper parseArray( ParseContext context, ObjectMapper parentMapper, String lastFieldName) throws IOException { String arrayFieldName = lastFieldName; Mapper mapper = parentMapper.getMapper(lastFieldName); if (mapper != null) { // There is a concrete mapper for this field already. Need to check if the mapper // expects an array, if so we pass the context straight to the mapper and if not // we serialize the array components if (mapper instanceof ArrayValueMapperParser) { final Mapper subUpdate = parseObjectOrField(context, mapper); if (subUpdate != null) { // propagate the mapping update return parentMapper.mappingUpdate(subUpdate); } else { return null; } } else { return parseNonDynamicArray(context, parentMapper, lastFieldName, arrayFieldName); } } else { ObjectMapper.Dynamic dynamic = parentMapper.dynamic(); if (dynamic == null) { dynamic = dynamicOrDefault(context.root().dynamic()); } if (dynamic == ObjectMapper.Dynamic.STRICT) { throw new StrictDynamicMappingException(parentMapper.fullPath(), arrayFieldName); } else if (dynamic == ObjectMapper.Dynamic.TRUE) { Mapper.Builder builder = context.root().findTemplateBuilder(context, arrayFieldName, "object"); if (builder == null) { return parseNonDynamicArray(context, parentMapper, lastFieldName, arrayFieldName); } Mapper.BuilderContext builderContext = new Mapper.BuilderContext(context.indexSettings(), context.path()); mapper = builder.build(builderContext); if (mapper != null && mapper instanceof ArrayValueMapperParser) { context.path().add(arrayFieldName); mapper = parseAndMergeUpdate(mapper, context); return parentMapper.mappingUpdate(mapper); } else { return parseNonDynamicArray(context, parentMapper, lastFieldName, arrayFieldName); } } else { return parseNonDynamicArray(context, parentMapper, lastFieldName, arrayFieldName); } } }
private void checkObjectsCompatibility( String type, Collection<ObjectMapper> objectMappers, Collection<FieldMapper> fieldMappers, boolean updateAllTypes) { assert Thread.holdsLock(this); for (ObjectMapper newObjectMapper : objectMappers) { ObjectMapper existingObjectMapper = fullPathObjectMappers.get(newObjectMapper.fullPath()); if (existingObjectMapper != null) { // simulate a merge and ignore the result, we are just interested // in exceptions here existingObjectMapper.merge(newObjectMapper, updateAllTypes); } } }
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 void checkNestedFieldsLimit(Map<String, ObjectMapper> fullPathObjectMappers) { long allowedNestedFields = indexSettings.getValue(INDEX_MAPPING_NESTED_FIELDS_LIMIT_SETTING); long actualNestedFields = 0; for (ObjectMapper objectMapper : fullPathObjectMappers.values()) { if (objectMapper.nested().isNested()) { actualNestedFields++; } } if (actualNestedFields > allowedNestedFields) { throw new IllegalArgumentException( "Limit of nested fields [" + allowedNestedFields + "] in index [" + index().getName() + "] has been exceeded"); } }
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; }
/** Creates an copy of the current field with given field name and boost */ private static void parseCopy(String field, ParseContext context) throws IOException { FieldMapper fieldMapper = context.docMapper().mappers().getMapper(field); if (fieldMapper != null) { fieldMapper.parse(context); } else { // The path of the dest field might be completely different from the current one so we need to reset it context = context.overridePath(new ContentPath(0)); ObjectMapper mapper = context.root(); String objectPath = ""; String fieldPath = field; int posDot = field.lastIndexOf('.'); if (posDot > 0) { objectPath = field.substring(0, posDot); context.path().add(objectPath); mapper = context.docMapper().objectMappers().get(objectPath); fieldPath = field.substring(posDot + 1); } if (mapper == null) { //TODO: Create an object dynamically? throw new MapperParsingException("attempt to copy value to non-existing object [" + field + "]"); } ObjectMapper update = parseDynamicValue(context, mapper, fieldPath, context.parser().currentToken()); assert update != null; // we are parsing a dynamic value so we necessarily created a new mapping // propagate the update to the root while (objectPath.length() > 0) { String parentPath = ""; ObjectMapper parent = context.root(); posDot = objectPath.lastIndexOf('.'); if (posDot > 0) { parentPath = objectPath.substring(0, posDot); parent = context.docMapper().objectMappers().get(parentPath); } if (parent == null) { throw new IllegalStateException("[" + objectPath + "] has no parent for path [" + parentPath + "]"); } update = parent.mappingUpdate(update); objectPath = parentPath; } context.addDynamicMappingsUpdate(update); } }
private void addObjectMappers(ObjectMapper[] objectMappers) { synchronized (mutex) { MapBuilder<String, ObjectMappers> fullPathObjectMappers = newMapBuilder(this.fullPathObjectMappers); for (ObjectMapper objectMapper : objectMappers) { ObjectMappers mappers = fullPathObjectMappers.get(objectMapper.fullPath()); if (mappers == null) { mappers = new ObjectMappers(objectMapper); } else { mappers = mappers.concat(objectMapper); } fullPathObjectMappers.put(objectMapper.fullPath(), mappers); // update the hasNested flag if (objectMapper.nested().isNested()) { hasNested = true; } } this.fullPathObjectMappers = fullPathObjectMappers.map(); } }
private void addMappers( Collection<ObjectMapper> objectMappers, Collection<FieldMapper> fieldMappers) { assert mappingLock.isWriteLockedByCurrentThread(); // first ensure we don't have any incompatible new fields mapperService.checkNewMappersCompatibility(objectMappers, fieldMappers, true); // update mappers for this document type MapBuilder<String, ObjectMapper> builder = MapBuilder.newMapBuilder(this.objectMappers); for (ObjectMapper objectMapper : objectMappers) { builder.put(objectMapper.fullPath(), objectMapper); if (objectMapper.nested().isNested()) { hasNestedObjects = true; } } this.objectMappers = builder.immutableMap(); this.fieldMappers = this.fieldMappers.copyAndAllAll(fieldMappers); // finally update for the entire index mapperService.addMappers(objectMappers, fieldMappers); }
private void removeObjectAndFieldMappers(DocumentMapper docMapper) { synchronized (mappersMutex) { fieldMappers.removeMappers(docMapper.mappers()); ImmutableOpenMap.Builder<String, ObjectMappers> fullPathObjectMappers = ImmutableOpenMap.builder(this.fullPathObjectMappers); for (ObjectMapper mapper : docMapper.objectMappers().values()) { ObjectMappers mappers = fullPathObjectMappers.get(mapper.fullPath()); if (mappers != null) { mappers = mappers.remove(mapper); if (mappers.isEmpty()) { fullPathObjectMappers.remove(mapper.fullPath()); } else { fullPathObjectMappers.put(mapper.fullPath(), mappers); } } } this.fullPathObjectMappers = fullPathObjectMappers.build(); } }
protected void checkNewMappersCompatibility( Collection<ObjectMapper> newObjectMappers, Collection<FieldMapper> newFieldMappers, boolean updateAllTypes) { assert mappingLock.isWriteLockedByCurrentThread(); for (ObjectMapper newObjectMapper : newObjectMappers) { ObjectMapper existingObjectMapper = fullPathObjectMappers.get(newObjectMapper.fullPath()); if (existingObjectMapper != null) { MergeResult result = new MergeResult(true, updateAllTypes); existingObjectMapper.merge(newObjectMapper, result); if (result.hasConflicts()) { throw new IllegalArgumentException( "Mapper for [" + newObjectMapper.fullPath() + "] conflicts with existing mapping in other types" + Arrays.toString(result.buildConflicts())); } } } fieldTypes.checkCompatibility(newFieldMappers, updateAllTypes); }
/** * Returns the best nested {@link ObjectMapper} instances that is in the scope of the specified * nested docId. */ public ObjectMapper findNestedObjectMapper( int nestedDocId, SearchContext sc, LeafReaderContext context) throws IOException { ObjectMapper nestedObjectMapper = null; for (ObjectMapper objectMapper : objectMappers().values()) { if (!objectMapper.nested().isNested()) { continue; } Filter filter = objectMapper.nestedTypeFilter(); if (filter == null) { continue; } // We can pass down 'null' as acceptedDocs, because nestedDocId is a doc to be fetched and // therefor is guaranteed to be a live doc. DocIdSet nestedTypeSet = filter.getDocIdSet(context, null); if (nestedTypeSet == null) { continue; } DocIdSetIterator iterator = nestedTypeSet.iterator(); if (iterator == null) { continue; } if (iterator.advance(nestedDocId) == nestedDocId) { if (nestedObjectMapper == null) { nestedObjectMapper = objectMapper; } else { if (nestedObjectMapper.fullPath().length() < objectMapper.fullPath().length()) { nestedObjectMapper = objectMapper; } } } } return nestedObjectMapper; }
@Override public TopDocs topDocs(SearchContext context, FetchSubPhase.HitContext hitContext) throws IOException { Filter rawParentFilter; if (parentObjectMapper == null) { rawParentFilter = NonNestedDocsFilter.INSTANCE; } else { rawParentFilter = parentObjectMapper.nestedTypeFilter(); } FixedBitSetFilter parentFilter = context.fixedBitSetFilterCache().getFixedBitSetFilter(rawParentFilter); Filter childFilter = context.filterCache().cache(childObjectMapper.nestedTypeFilter()); Query q = new XFilteredQuery( query, new NestedChildrenFilter(parentFilter, childFilter, hitContext)); if (size() == 0) { TotalHitCountCollector collector = new TotalHitCountCollector(); context.searcher().search(q, collector); return new TopDocs(collector.getTotalHits(), Lucene.EMPTY_SCORE_DOCS, 0); } else { int topN = from() + size(); TopDocsCollector topDocsCollector; if (sort() != null) { try { topDocsCollector = TopFieldCollector.create(sort(), topN, true, trackScores(), trackScores(), true); } catch (IOException e) { throw ExceptionsHelper.convertToElastic(e); } } else { topDocsCollector = TopScoreDocCollector.create(topN, true); } context.searcher().search(q, topDocsCollector); return topDocsCollector.topDocs(from(), size()); } }
public void setPath(String path) { this.path = path; MapperService.SmartNameObjectMapper smart = parseContext.smartObjectMapper(path); if (smart == null) { throw new QueryParsingException( parseContext.index(), "[nested] failed to find nested object under path [" + path + "]"); } childDocumentMapper = smart.docMapper(); nestedObjectMapper = smart.mapper(); if (nestedObjectMapper == null) { throw new QueryParsingException( parseContext.index(), "[nested] failed to find nested object under path [" + path + "]"); } if (!nestedObjectMapper.nested().isNested()) { throw new QueryParsingException( parseContext.index(), "[nested] nested object under path [" + path + "] is not of nested type"); } }
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; }
public DocumentMapper( String index, @Nullable Settings indexSettings, DocumentMapperParser docMapperParser, RootObjectMapper rootObjectMapper, ImmutableMap<String, Object> meta, NamedAnalyzer indexAnalyzer, NamedAnalyzer searchAnalyzer, NamedAnalyzer searchQuoteAnalyzer, Map<Class<? extends RootMapper>, RootMapper> rootMappers) { this.index = index; this.indexSettings = indexSettings; this.type = rootObjectMapper.name(); this.docMapperParser = docMapperParser; this.meta = meta; this.rootObjectMapper = rootObjectMapper; this.rootMappers = ImmutableMap.copyOf(rootMappers); this.rootMappersOrdered = rootMappers.values().toArray(new RootMapper[rootMappers.values().size()]); List<RootMapper> rootMappersNotIncludedInObjectLst = newArrayList(); for (RootMapper rootMapper : rootMappersOrdered) { if (!rootMapper.includeInObject()) { rootMappersNotIncludedInObjectLst.add(rootMapper); } } this.rootMappersNotIncludedInObject = rootMappersNotIncludedInObjectLst.toArray( new RootMapper[rootMappersNotIncludedInObjectLst.size()]); this.indexAnalyzer = indexAnalyzer; this.searchAnalyzer = searchAnalyzer; this.searchQuoteAnalyzer = searchQuoteAnalyzer != null ? searchQuoteAnalyzer : searchAnalyzer; this.typeFilter = typeMapper().termFilter(type, null); if (rootMapper(ParentFieldMapper.class) != null) { // mark the routing field mapper as required rootMapper(RoutingFieldMapper.class).markAsRequired(); } FieldMapperListener.Aggregator fieldMappersAgg = new FieldMapperListener.Aggregator(); for (RootMapper rootMapper : rootMappersOrdered) { if (rootMapper.includeInObject()) { rootObjectMapper.putMapper(rootMapper); } else { if (rootMapper instanceof FieldMapper) { fieldMappersAgg.mappers.add((FieldMapper) rootMapper); } } } // now traverse and get all the statically defined ones rootObjectMapper.traverse(fieldMappersAgg); this.fieldMappers = new DocumentFieldMappers(this, fieldMappersAgg.mappers); final Map<String, ObjectMapper> objectMappers = Maps.newHashMap(); rootObjectMapper.traverse( new ObjectMapperListener() { @Override public void objectMapper(ObjectMapper objectMapper) { objectMappers.put(objectMapper.fullPath(), objectMapper); } }); this.objectMappers = ImmutableMap.copyOf(objectMappers); for (ObjectMapper objectMapper : objectMappers.values()) { if (objectMapper.nested().isNested()) { hasNestedObjects = true; } } refreshSource(); }
private synchronized DocumentMapper merge( DocumentMapper mapper, MergeReason reason, boolean updateAllTypes) { if (mapper.type().length() == 0) { throw new InvalidTypeNameException("mapping type name is empty"); } if (mapper.type().length() > 255) { throw new InvalidTypeNameException( "mapping type name [" + mapper.type() + "] is too long; limit is length 255 but was [" + mapper.type().length() + "]"); } if (mapper.type().charAt(0) == '_') { throw new InvalidTypeNameException( "mapping type name [" + mapper.type() + "] can't start with '_'"); } if (mapper.type().contains("#")) { throw new InvalidTypeNameException( "mapping type name [" + mapper.type() + "] should not include '#' in it"); } if (mapper.type().contains(",")) { throw new InvalidTypeNameException( "mapping type name [" + mapper.type() + "] should not include ',' in it"); } if (mapper.type().equals(mapper.parentFieldMapper().type())) { throw new IllegalArgumentException("The [_parent.type] option can't point to the same type"); } if (typeNameStartsWithIllegalDot(mapper)) { throw new IllegalArgumentException( "mapping type name [" + mapper.type() + "] must not start with a '.'"); } // 1. compute the merged DocumentMapper DocumentMapper oldMapper = mappers.get(mapper.type()); DocumentMapper newMapper; if (oldMapper != null) { newMapper = oldMapper.merge(mapper.mapping(), updateAllTypes); } else { newMapper = mapper; } // 2. check basic sanity of the new mapping List<ObjectMapper> objectMappers = new ArrayList<>(); List<FieldMapper> fieldMappers = new ArrayList<>(); Collections.addAll(fieldMappers, newMapper.mapping().metadataMappers); MapperUtils.collect(newMapper.mapping().root(), objectMappers, fieldMappers); checkFieldUniqueness(newMapper.type(), objectMappers, fieldMappers); checkObjectsCompatibility(newMapper.type(), objectMappers, fieldMappers, updateAllTypes); // 3. update lookup data-structures // this will in particular make sure that the merged fields are compatible with other types FieldTypeLookup fieldTypes = this.fieldTypes.copyAndAddAll(newMapper.type(), fieldMappers, updateAllTypes); boolean hasNested = this.hasNested; Map<String, ObjectMapper> fullPathObjectMappers = new HashMap<>(this.fullPathObjectMappers); for (ObjectMapper objectMapper : objectMappers) { fullPathObjectMappers.put(objectMapper.fullPath(), objectMapper); if (objectMapper.nested().isNested()) { hasNested = true; } } fullPathObjectMappers = Collections.unmodifiableMap(fullPathObjectMappers); if (reason == MergeReason.MAPPING_UPDATE) { // this check will only be performed on the master node when there is // a call to the update mapping API. For all other cases like // the master node restoring mappings from disk or data nodes // deserializing cluster state that was sent by the master node, // this check will be skipped. checkNestedFieldsLimit(fullPathObjectMappers); checkTotalFieldsLimit(objectMappers.size() + fieldMappers.size()); checkDepthLimit(fullPathObjectMappers.keySet()); checkPercolatorFieldLimit(fieldTypes); } Set<String> parentTypes = this.parentTypes; if (oldMapper == null && newMapper.parentFieldMapper().active()) { parentTypes = new HashSet<>(parentTypes.size() + 1); parentTypes.addAll(this.parentTypes); parentTypes.add(mapper.parentFieldMapper().type()); parentTypes = Collections.unmodifiableSet(parentTypes); } Map<String, DocumentMapper> mappers = new HashMap<>(this.mappers); mappers.put(newMapper.type(), newMapper); for (Map.Entry<String, DocumentMapper> entry : mappers.entrySet()) { if (entry.getKey().equals(DEFAULT_MAPPING)) { continue; } DocumentMapper m = entry.getValue(); // apply changes to the field types back m = m.updateFieldType(fieldTypes.fullNameToFieldType); entry.setValue(m); } mappers = Collections.unmodifiableMap(mappers); // 4. commit the change this.mappers = mappers; this.fieldTypes = fieldTypes; this.hasNested = hasNested; this.fullPathObjectMappers = fullPathObjectMappers; this.parentTypes = parentTypes; assert assertSerialization(newMapper); assert assertMappersShareSameFieldType(); return newMapper; }