Skip to content

Commit

Permalink
Read subobjects mapping parameter in advance
Browse files Browse the repository at this point in the history
As part of elastic#86166 we added support for a new mapping parameter called `subobjects` that
can be set to the `object` field type. Such parameter will affect not only how incoming
documents will be dinamically mapped in the future, but also how field names are treated
as part of the mappings themselves.

Mappings get parsed into a map, where keys ordering is not guaranteed. In case a mappings call
contains `subobjects` set to `false` and also sub-fields for that same object, we need to make
sure that we read the parameter in advance in order to know how to treat the sub-field and decide
whether we need to expand dots in field names or leave them as they are.
  • Loading branch information
javanna committed May 18, 2022
1 parent d6519b4 commit 78d310e
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
"Metrics indexing":
"Metrics object indexing":
- skip:
version: " - 8.2.99"
reason: added in 8.3.0
Expand All @@ -16,22 +16,69 @@
mapping:
type: object
subobjects: false
properties:
host.name:
type: keyword

- do:
index:
index: test-1
id: 1
refresh: true
body:
{ metrics.time: 10, metrics.time.max: 100, metrics.time.min: 1 }
{ metrics.host.name: localhost, metrics.host.id: 1, metrics.time: 10, metrics.time.max: 100, metrics.time.min: 1 }

- do:
field_caps:
index: test-1
fields: metrics.time*
fields: metrics*
- match: {fields.metrics\.host\.id.long.searchable: true}
- match: {fields.metrics\.host\.id.long.aggregatable: true}
- match: {fields.metrics\.host\.name.keyword.searchable: true}
- match: {fields.metrics\.host\.name.keyword.aggregatable: true}
- match: {fields.metrics\.time.long.searchable: true}
- match: {fields.metrics\.time.long.aggregatable: true}
- match: {fields.metrics\.time\.max.long.searchable: true}
- match: {fields.metrics\.time\.max.long.aggregatable: true}
- match: {fields.metrics\.time\.min.long.searchable: true}
- match: {fields.metrics\.time\.min.long.aggregatable: true}

---
"Root without subobjects":
- skip:
version: " - 8.2.99"
reason: added in 8.3.0

- do:
indices.put_template:
name: test
body:
index_patterns: test-*
mappings:
subobjects: false
properties:
host.name:
type: keyword

- do:
index:
index: test-1
id: 1
refresh: true
body:
{ host.name: localhost, host.id: 1, time: 10, time.max: 100, time.min: 1 }

- do:
field_caps:
index: test-1
fields: [host*, time*]
- match: {fields.host\.name.keyword.searchable: true}
- match: {fields.host\.name.keyword.aggregatable: true}
- match: {fields.host\.id.keyword.searchable: true}
- match: {fields.host\.id.keyword.aggregatable: true}
- match: {fields.time.long.searchable: true}
- match: {fields.time.long.aggregatable: true}
- match: {fields.time\.max.long.searchable: true}
- match: {fields.time\.max.long.aggregatable: true}
- match: {fields.time\.min.long.searchable: true}
- match: {fields.time\.min.long.aggregatable: true}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ public static class TypeParser extends ObjectMapper.TypeParser {
public Mapper.Builder parse(String name, Map<String, Object> node, MappingParserContext parserContext)
throws MapperParsingException {
NestedObjectMapper.Builder builder = new NestedObjectMapper.Builder(name, parserContext.indexVersionCreated());
parseSubobjects(node, builder);
if (builder.subobjects.explicit()) {
throw new MapperParsingException("Nested type [" + name + "] does not support [subobjects] parameter");
}
parseNested(name, node, builder);
for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<String, Object> entry = iterator.next();
Expand All @@ -67,9 +71,6 @@ public Mapper.Builder parse(String name, Map<String, Object> node, MappingParser
iterator.remove();
}
}
if (builder.subobjects.explicit()) {
throw new MapperParsingException("Nested type [" + name + "] does not support [subobjects] parameter");
}
return builder;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ public boolean supportsVersion(Version indexCreatedVersion) {
public Mapper.Builder parse(String name, Map<String, Object> node, MappingParserContext parserContext)
throws MapperParsingException {
ObjectMapper.Builder builder = new Builder(name);
parseSubobjects(node, builder);
for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<String, Object> entry = iterator.next();
String fieldName = entry.getKey();
Expand Down Expand Up @@ -219,9 +220,6 @@ protected static boolean parseObjectOrDocumentTypeProperties(
} else if (fieldName.equals("enabled")) {
builder.enabled(XContentMapValues.nodeBooleanValue(fieldNode, fieldName + ".enabled"));
return true;
} else if (fieldName.equals("subobjects")) {
builder.subobjects(XContentMapValues.nodeBooleanValue(fieldNode, fieldName + ".subobjects"));
return true;
} else if (fieldName.equals("properties")) {
if (fieldNode instanceof Collection && ((Collection) fieldNode).isEmpty()) {
// nothing to do here, empty (to support "properties: []" case)
Expand All @@ -242,6 +240,13 @@ protected static boolean parseObjectOrDocumentTypeProperties(
return false;
}

protected static void parseSubobjects(Map<String, Object> node, ObjectMapper.Builder builder) {
Object subobjectsNode = node.remove("subobjects");
if (subobjectsNode != null) {
builder.subobjects(XContentMapValues.nodeBooleanValue(subobjectsNode, "subobjects.subobjects"));
}
}

protected static void parseProperties(
ObjectMapper.Builder objBuilder,
Map<String, Object> propsNode,
Expand Down Expand Up @@ -493,6 +498,8 @@ protected void doMerge(final ObjectMapper mergeWith, MergeReason reason) {
}
if (mergedMappers != null) {
mappers = Map.copyOf(mergedMappers);
System.out.println(mappers);
Thread.dumpStack();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ static final class TypeParser extends ObjectMapper.TypeParser {
public RootObjectMapper.Builder parse(String name, Map<String, Object> node, MappingParserContext parserContext)
throws MapperParsingException {
RootObjectMapper.Builder builder = new Builder(name);
parseSubobjects(node, builder);
Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Object> entry = iterator.next();
Expand Down

0 comments on commit 78d310e

Please sign in to comment.