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;
  }
Ejemplo n.º 4
0
  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;
  }