From 886506067380d370163848a9c681665480a1e2e9 Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Wed, 9 Oct 2024 10:32:55 +0100 Subject: [PATCH] simplify filtering of ignored source entries --- .../mapper/CompositeSyntheticFieldLoader.java | 3 +- .../mapper/IgnoreMalformedStoredValues.java | 3 +- .../mapper/IgnoredSourceFieldMapper.java | 3 +- .../index/mapper/ObjectMapper.java | 5 +- .../index/mapper/SourceLoader.java | 1 + .../index/mapper/XContentDataHelper.java | 163 ++++++++++-------- .../mapper/IgnoredSourceFieldMapperTests.java | 62 +++++-- .../index/mapper/XContentDataHelperTests.java | 28 ++- 8 files changed, 163 insertions(+), 105 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/index/mapper/CompositeSyntheticFieldLoader.java b/server/src/main/java/org/elasticsearch/index/mapper/CompositeSyntheticFieldLoader.java index c88d8f9eeb148..2c790c01d4730 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/CompositeSyntheticFieldLoader.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/CompositeSyntheticFieldLoader.java @@ -12,7 +12,6 @@ import org.apache.lucene.index.LeafReader; import org.apache.lucene.util.BytesRef; import org.elasticsearch.xcontent.XContentBuilder; -import org.elasticsearch.xcontent.XContentParserConfiguration; import java.io.IOException; import java.util.ArrayList; @@ -170,7 +169,7 @@ public MalformedValuesLayer(String fieldName) { @Override protected void writeValue(Object value, XContentBuilder b) throws IOException { if (value instanceof BytesRef r) { - XContentDataHelper.decodeAndWrite(XContentParserConfiguration.EMPTY, b, r); + XContentDataHelper.decodeAndWrite(b, r); } else { b.value(value); } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/IgnoreMalformedStoredValues.java b/server/src/main/java/org/elasticsearch/index/mapper/IgnoreMalformedStoredValues.java index f6bad433a7a1c..8544ddd0194f3 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/IgnoreMalformedStoredValues.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/IgnoreMalformedStoredValues.java @@ -13,7 +13,6 @@ import org.apache.lucene.util.BytesRef; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.XContentParser; -import org.elasticsearch.xcontent.XContentParserConfiguration; import java.io.IOException; import java.util.List; @@ -129,7 +128,7 @@ public int count() { public void write(XContentBuilder b) throws IOException { for (Object v : values) { if (v instanceof BytesRef r) { - XContentDataHelper.decodeAndWrite(XContentParserConfiguration.EMPTY, b, r); + XContentDataHelper.decodeAndWrite(b, r); } else { b.value(v); } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/IgnoredSourceFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/IgnoredSourceFieldMapper.java index 54abfbed6ced0..296c2c5311d9a 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/IgnoredSourceFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/IgnoredSourceFieldMapper.java @@ -21,7 +21,6 @@ import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.xcontent.XContentBuilder; -import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; import java.io.IOException; @@ -283,7 +282,7 @@ public static MappedNameValue decodeAsMap(byte[] value) throws IOException { IgnoredSourceFieldMapper.NameValue nameValue = IgnoredSourceFieldMapper.decode(bytes); XContentBuilder xContentBuilder = XContentBuilder.builder(XContentDataHelper.getXContentType(nameValue.value()).xContent()); xContentBuilder.startObject().field(nameValue.name()); - XContentDataHelper.decodeAndWrite(XContentParserConfiguration.EMPTY, xContentBuilder, nameValue.value()); + XContentDataHelper.decodeAndWrite(xContentBuilder, nameValue.value()); xContentBuilder.endObject(); Tuple> result = XContentHelper.convertToMap(BytesReference.bytes(xContentBuilder), true); return new MappedNameValue(nameValue, result.v1(), result.v2()); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java index 94b87bd85b071..b44000974b7bc 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java @@ -1032,7 +1032,10 @@ public void write(XContentBuilder b) throws IOException { // If the root object mapper is disabled, it is expected to contain // the source encapsulated within a single ignored source value. assert ignoredValues.size() == 1 : ignoredValues.size(); - XContentDataHelper.decodeAndWrite(parserConfig, b, ignoredValues.get(0).value()); + var value = ignoredValues.get(0).value(); + var type = XContentDataHelper.decodeType(value); + assert type.isPresent(); + XContentDataHelper.decodeAndWriteXContent(parserConfig, b, type.get(), ignoredValues.get(0).value()); softReset(); return; } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/SourceLoader.java b/server/src/main/java/org/elasticsearch/index/mapper/SourceLoader.java index e99e2477af5e6..27b4f4eb0ae76 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/SourceLoader.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/SourceLoader.java @@ -217,6 +217,7 @@ public void write(LeafStoredFieldLoader storedFieldLoader, int docId, XContentBu IgnoredSourceFieldMapper.NameValue nameValue = IgnoredSourceFieldMapper.decode(value); if (filter != null && filter.isPathFiltered(nameValue.name(), XContentDataHelper.isEncodedObject(nameValue.value()))) { + // This path is filtered by the include/exclude rules continue; } objectsWithIgnoredFields.computeIfAbsent(nameValue.getParentFieldName(), k -> new ArrayList<>()).add(nameValue); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/XContentDataHelper.java b/server/src/main/java/org/elasticsearch/index/mapper/XContentDataHelper.java index 5db71f7493b77..407a02f932324 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/XContentDataHelper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/XContentDataHelper.java @@ -16,6 +16,7 @@ import org.elasticsearch.common.util.ByteUtils; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.core.CheckedFunction; +import org.elasticsearch.core.CheckedRunnable; import org.elasticsearch.core.Tuple; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.XContentParser; @@ -85,53 +86,48 @@ public static BytesRef voidValue() { } /** - * Decode the value, using the provided {@link XContentParserConfiguration}, in the passed {@link BytesRef} - * and add it as a value to the passed build. - * The assumption is that the passed value has encoded using the function {@link #encodeToken(XContentParser)} above. + * Decode the value in the passed {@link BytesRef} and add it as a value to the + * passed build. The assumption is that the passed value has encoded using the function + * {@link #encodeToken(XContentParser)} above. */ - static void decodeAndWrite(XContentParserConfiguration parserConfig, XContentBuilder b, BytesRef r) throws IOException { + static void decodeAndWrite(XContentBuilder b, BytesRef r) throws IOException { switch ((char) r.bytes[r.offset]) { - case BINARY_ENCODING -> TypeUtils.EMBEDDED_OBJECT.decodeAndWrite(parserConfig, b, r); + case BINARY_ENCODING -> TypeUtils.EMBEDDED_OBJECT.decodeAndWrite(b, r); case CBOR_OBJECT_ENCODING, JSON_OBJECT_ENCODING, YAML_OBJECT_ENCODING, SMILE_OBJECT_ENCODING -> { - TypeUtils.START.decodeAndWrite(parserConfig, b, r); - } - case BIG_DECIMAL_ENCODING -> TypeUtils.BIG_DECIMAL.decodeAndWrite(parserConfig, b, r); - case FALSE_ENCODING, TRUE_ENCODING -> TypeUtils.BOOLEAN.decodeAndWrite(parserConfig, b, r); - case BIG_INTEGER_ENCODING -> TypeUtils.BIG_INTEGER.decodeAndWrite(parserConfig, b, r); - case STRING_ENCODING -> TypeUtils.STRING.decodeAndWrite(parserConfig, b, r); - case INTEGER_ENCODING -> TypeUtils.INTEGER.decodeAndWrite(parserConfig, b, r); - case LONG_ENCODING -> TypeUtils.LONG.decodeAndWrite(parserConfig, b, r); - case DOUBLE_ENCODING -> TypeUtils.DOUBLE.decodeAndWrite(parserConfig, b, r); - case FLOAT_ENCODING -> TypeUtils.FLOAT.decodeAndWrite(parserConfig, b, r); - case NULL_ENCODING -> TypeUtils.NULL.decodeAndWrite(parserConfig, b, r); - case VOID_ENCODING -> TypeUtils.VOID.decodeAndWrite(parserConfig, b, r); + TypeUtils.START.decodeAndWrite(b, r); + } + case BIG_DECIMAL_ENCODING -> TypeUtils.BIG_DECIMAL.decodeAndWrite(b, r); + case FALSE_ENCODING, TRUE_ENCODING -> TypeUtils.BOOLEAN.decodeAndWrite(b, r); + case BIG_INTEGER_ENCODING -> TypeUtils.BIG_INTEGER.decodeAndWrite(b, r); + case STRING_ENCODING -> TypeUtils.STRING.decodeAndWrite(b, r); + case INTEGER_ENCODING -> TypeUtils.INTEGER.decodeAndWrite(b, r); + case LONG_ENCODING -> TypeUtils.LONG.decodeAndWrite(b, r); + case DOUBLE_ENCODING -> TypeUtils.DOUBLE.decodeAndWrite(b, r); + case FLOAT_ENCODING -> TypeUtils.FLOAT.decodeAndWrite(b, r); + case NULL_ENCODING -> TypeUtils.NULL.decodeAndWrite(b, r); + case VOID_ENCODING -> TypeUtils.VOID.decodeAndWrite(b, r); default -> throw new IllegalArgumentException("Can't decode " + r); } } /** * Determines if the given {@link BytesRef}, encoded with {@link XContentDataHelper#encodeToken(XContentParser)}, - * represents an object that can contain sub-fields. Returns {@code true} if it does. + * is an encoded object. */ static boolean isEncodedObject(BytesRef encoded) { - var type = switch ((char) encoded.bytes[encoded.offset]) { - case CBOR_OBJECT_ENCODING -> XContentType.CBOR; - case JSON_OBJECT_ENCODING -> XContentType.JSON; - case SMILE_OBJECT_ENCODING -> XContentType.SMILE; - case YAML_OBJECT_ENCODING -> XContentType.YAML; - default -> null; + return switch ((char) encoded.bytes[encoded.offset]) { + case CBOR_OBJECT_ENCODING, YAML_OBJECT_ENCODING, JSON_OBJECT_ENCODING, SMILE_OBJECT_ENCODING -> true; + default -> false; + }; + } + + static Optional decodeType(BytesRef encodedValue) { + return switch ((char) encodedValue.bytes[encodedValue.offset]) { + case CBOR_OBJECT_ENCODING, JSON_OBJECT_ENCODING, YAML_OBJECT_ENCODING, SMILE_OBJECT_ENCODING -> Optional.of( + getXContentType(encodedValue) + ); + default -> Optional.empty(); }; - if (type == null) { - return false; - } - try ( - XContentParser parser = type.xContent() - .createParser(XContentParserConfiguration.EMPTY, encoded.bytes, encoded.offset + 1, encoded.length - 1) - ) { - return parser.nextToken() == XContentParser.Token.START_OBJECT; - } catch (IOException e) { - throw new RuntimeException(e); - } } /** @@ -151,14 +147,16 @@ static void writeMerged(XContentParserConfiguration parserConfig, XContentBuilde return; } - if (encodedParts.size() == 1) { - b.field(fieldName); - XContentDataHelper.decodeAndWrite(parserConfig, b, encodedParts.get(0)); - return; - } - - b.startArray(fieldName); + boolean isArray = encodedParts.size() > 1; + // xcontent filtering can remove all values so we delay the start of the field until we have an actual value to write. + CheckedRunnable startField = () -> { + if (isArray) { + b.startArray(fieldName); + } else { + b.field(fieldName); + } + }; for (var encodedValue : encodedParts) { Optional encodedXContentType = switch ((char) encodedValue.bytes[encodedValue.offset]) { case CBOR_OBJECT_ENCODING, JSON_OBJECT_ENCODING, YAML_OBJECT_ENCODING, SMILE_OBJECT_ENCODING -> Optional.of( @@ -167,22 +165,33 @@ static void writeMerged(XContentParserConfiguration parserConfig, XContentBuilde default -> Optional.empty(); }; if (encodedXContentType.isEmpty()) { + if (startField != null) { + // first value to write + startField.run(); + startField = null; + } // This is a plain value, we can just write it - XContentDataHelper.decodeAndWrite(parserConfig, b, encodedValue); + XContentDataHelper.decodeAndWrite(b, encodedValue); } else { - // Encoded value could be an array which needs to be flattened - // since we are already inside an array. + // Encoded value could be an object or an array of objects that needs + // to be filtered or flattened. try ( XContentParser parser = encodedXContentType.get() .xContent() .createParser(parserConfig, encodedValue.bytes, encodedValue.offset + 1, encodedValue.length - 1) ) { - if (parser.currentToken() == null) { - parser.nextToken(); + if ((parser.currentToken() == null) && (parser.nextToken() == null)) { + // the entire content is filtered by include/exclude rules + continue; } - // It's an array, we will flatten it. - if (parser.currentToken() == XContentParser.Token.START_ARRAY) { + if (startField != null) { + // first value to write + startField.run(); + startField = null; + } + if (isArray && parser.currentToken() == XContentParser.Token.START_ARRAY) { + // Encoded value is an array which needs to be flattened since we are already inside an array. while (parser.nextToken() != XContentParser.Token.END_ARRAY) { b.copyCurrentStructure(parser); } @@ -193,8 +202,9 @@ static void writeMerged(XContentParserConfiguration parserConfig, XContentBuilde } } } - - b.endArray(); + if (isArray) { + b.endArray(); + } } public static boolean isDataPresent(BytesRef encoded) { @@ -319,7 +329,7 @@ byte[] encode(XContentParser parser) throws IOException { } @Override - void decodeAndWrite(XContentParserConfiguration parserConfig, XContentBuilder b, BytesRef r) throws IOException { + void decodeAndWrite(XContentBuilder b, BytesRef r) throws IOException { b.value(new BytesRef(r.bytes, r.offset + 1, r.length - 1).utf8ToString()); } }, @@ -339,7 +349,7 @@ byte[] encode(XContentParser parser) throws IOException { } @Override - void decodeAndWrite(XContentParserConfiguration parserConfig, XContentBuilder b, BytesRef r) throws IOException { + void decodeAndWrite(XContentBuilder b, BytesRef r) throws IOException { b.value(ByteUtils.readIntLE(r.bytes, 1 + r.offset)); } }, @@ -359,7 +369,7 @@ byte[] encode(XContentParser parser) throws IOException { } @Override - void decodeAndWrite(XContentParserConfiguration parserConfig, XContentBuilder b, BytesRef r) throws IOException { + void decodeAndWrite(XContentBuilder b, BytesRef r) throws IOException { b.value(ByteUtils.readLongLE(r.bytes, 1 + r.offset)); } }, @@ -379,7 +389,7 @@ byte[] encode(XContentParser parser) throws IOException { } @Override - void decodeAndWrite(XContentParserConfiguration parserConfig, XContentBuilder b, BytesRef r) throws IOException { + void decodeAndWrite(XContentBuilder b, BytesRef r) throws IOException { b.value(ByteUtils.readDoubleLE(r.bytes, 1 + r.offset)); } }, @@ -399,7 +409,7 @@ byte[] encode(XContentParser parser) throws IOException { } @Override - void decodeAndWrite(XContentParserConfiguration parserConfig, XContentBuilder b, BytesRef r) throws IOException { + void decodeAndWrite(XContentBuilder b, BytesRef r) throws IOException { b.value(ByteUtils.readFloatLE(r.bytes, 1 + r.offset)); } }, @@ -417,7 +427,7 @@ byte[] encode(XContentParser parser) throws IOException { } @Override - void decodeAndWrite(XContentParserConfiguration parserConfig, XContentBuilder b, BytesRef r) throws IOException { + void decodeAndWrite(XContentBuilder b, BytesRef r) throws IOException { b.value(new BigInteger(r.bytes, r.offset + 1, r.length - 1)); } }, @@ -435,7 +445,7 @@ byte[] encode(XContentParser parser) throws IOException { } @Override - void decodeAndWrite(XContentParserConfiguration parserConfig, XContentBuilder b, BytesRef r) throws IOException { + void decodeAndWrite(XContentBuilder b, BytesRef r) throws IOException { if (r.length < 5) { throw new IllegalArgumentException("Can't decode " + r); } @@ -457,7 +467,7 @@ byte[] encode(XContentParser parser) throws IOException { } @Override - void decodeAndWrite(XContentParserConfiguration parserConfig, XContentBuilder b, BytesRef r) throws IOException { + void decodeAndWrite(XContentBuilder b, BytesRef r) throws IOException { if (r.length != 1) { throw new IllegalArgumentException("Can't decode " + r); } @@ -479,7 +489,7 @@ byte[] encode(XContentParser parser) throws IOException { } @Override - void decodeAndWrite(XContentParserConfiguration parserConfig, XContentBuilder b, BytesRef r) throws IOException { + void decodeAndWrite(XContentBuilder b, BytesRef r) throws IOException { b.nullValue(); } }, @@ -497,7 +507,7 @@ byte[] encode(XContentParser parser) throws IOException { } @Override - void decodeAndWrite(XContentParserConfiguration parserConfig, XContentBuilder b, BytesRef r) throws IOException { + void decodeAndWrite(XContentBuilder b, BytesRef r) throws IOException { b.value(r.bytes, r.offset + 1, r.length - 1); } }, @@ -518,12 +528,12 @@ byte[] encode(XContentParser parser) throws IOException { } @Override - void decodeAndWrite(XContentParserConfiguration parserConfig, XContentBuilder b, BytesRef r) throws IOException { + void decodeAndWrite(XContentBuilder b, BytesRef r) throws IOException { switch ((char) r.bytes[r.offset]) { - case CBOR_OBJECT_ENCODING -> decodeAndWriteXContent(parserConfig, b, XContentType.CBOR, r); - case JSON_OBJECT_ENCODING -> decodeAndWriteXContent(parserConfig, b, XContentType.JSON, r); - case SMILE_OBJECT_ENCODING -> decodeAndWriteXContent(parserConfig, b, XContentType.SMILE, r); - case YAML_OBJECT_ENCODING -> decodeAndWriteXContent(parserConfig, b, XContentType.YAML, r); + case CBOR_OBJECT_ENCODING -> decodeAndWriteXContent(XContentParserConfiguration.EMPTY, b, XContentType.CBOR, r); + case JSON_OBJECT_ENCODING -> decodeAndWriteXContent(XContentParserConfiguration.EMPTY, b, XContentType.JSON, r); + case SMILE_OBJECT_ENCODING -> decodeAndWriteXContent(XContentParserConfiguration.EMPTY, b, XContentType.SMILE, r); + case YAML_OBJECT_ENCODING -> decodeAndWriteXContent(XContentParserConfiguration.EMPTY, b, XContentType.YAML, r); default -> throw new IllegalArgumentException("Can't decode " + r); } } @@ -542,7 +552,7 @@ byte[] encode(XContentParser parser) { } @Override - void decodeAndWrite(XContentParserConfiguration parserConfig, XContentBuilder b, BytesRef r) { + void decodeAndWrite(XContentBuilder b, BytesRef r) { // NOOP } }; @@ -570,7 +580,7 @@ void assertValidEncoding(byte[] encodedValue) { abstract byte[] encode(XContentParser parser) throws IOException; - abstract void decodeAndWrite(XContentParserConfiguration parserConfig, XContentBuilder b, BytesRef r) throws IOException; + abstract void decodeAndWrite(XContentBuilder b, BytesRef r) throws IOException; static byte[] encode(BigInteger n, Byte encoding) throws IOException { byte[] twosCompliment = n.toByteArray(); @@ -617,15 +627,16 @@ static byte[] encode(XContentBuilder builder) throws IOException { assert position == encoded.length; return encoded; } + } - static void decodeAndWriteXContent(XContentParserConfiguration parserConfig, XContentBuilder b, XContentType type, BytesRef r) - throws IOException { - try (XContentParser parser = type.xContent().createParser(parserConfig, r.bytes, r.offset + 1, r.length - 1)) { - if (parser.nextToken() == null) { - b.startObject().endObject(); - } else { - b.copyCurrentStructure(parser); - } + public static void decodeAndWriteXContent(XContentParserConfiguration parserConfig, XContentBuilder b, XContentType type, BytesRef r) + throws IOException { + try (XContentParser parser = type.xContent().createParser(parserConfig, r.bytes, r.offset + 1, r.length - 1)) { + if ((parser.currentToken() == null) && (parser.nextToken() == null)) { + // This can occur when all fields in a sub-object or all entries in an array of objects have been filtered out. + b.startObject().endObject(); + } else { + b.copyCurrentStructure(parser); } } } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/IgnoredSourceFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/IgnoredSourceFieldMapperTests.java index fbdd022e91a94..468397a527f56 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/IgnoredSourceFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/IgnoredSourceFieldMapperTests.java @@ -79,6 +79,34 @@ public void testIgnoredBoolean() throws IOException { ); } + public void testIgnoredBooleanArray() throws IOException { + assertEquals( + "{\"my_value\":[false,true,false]}", + getSyntheticSourceWithFieldLimit(b -> b.field("my_value", new boolean[] { false, true, false })) + ); + assertEquals( + "{\"my_value\":[false,true,false]}", + getSyntheticSourceWithFieldLimit( + new SourceFilter(new String[] { "my_value" }, null), + b -> b.array("my_value", new boolean[] { false, true, false }) + ) + ); + assertEquals( + "{}", + getSyntheticSourceWithFieldLimit( + new SourceFilter(null, new String[] { "my_value" }), + b -> b.field("my_value", new boolean[] { false, true, false }) + ) + ); + assertEquals( + "{}", + getSyntheticSourceWithFieldLimit( + new SourceFilter(new String[] { "my_value.object" }, null), + b -> b.array("my_value", new boolean[] { false, true, false }) + ) + ); + } + public void testIgnoredString() throws IOException { String value = randomAlphaOfLength(5); assertEquals("{\"my_value\":\"" + value + "\"}", getSyntheticSourceWithFieldLimit(b -> b.field("my_value", value))); @@ -197,10 +225,14 @@ public void testIgnoredObjectBoolean() throws IOException { b.startObject("my_object").field("my_value", value).endObject(); })); + assertEquals("{}", getSyntheticSourceWithFieldLimit(new SourceFilter(null, new String[] { "my_object.my_value" }), b -> { + b.startObject("my_object").field("my_value", value).endObject(); + })); + assertEquals( - "{\"my_object\":{}}", + "{\"my_object\":{\"another_value\":\"0\"}}", getSyntheticSourceWithFieldLimit(new SourceFilter(null, new String[] { "my_object.my_value" }), b -> { - b.startObject("my_object").field("my_value", value).endObject(); + b.startObject("my_object").field("my_value", value).field("another_value", "0").endObject(); }) ); } @@ -240,7 +272,7 @@ public void testIgnoredArrayOfObjects() throws IOException { ); assertEquals( - "{\"my_object\":{}}", + "{}", getSyntheticSourceWithFieldLimit( new SourceFilter(null, new String[] { "my_object.another_value", "my_object.my_value" }), b -> { @@ -252,6 +284,20 @@ public void testIgnoredArrayOfObjects() throws IOException { ) ); + assertEquals( + "{\"my_object\":[{\"another_field2\":2}]}", + getSyntheticSourceWithFieldLimit( + new SourceFilter(null, new String[] { "my_object.another_field1", "my_object.my_value" }), + b -> { + b.startArray("my_object"); + b.startObject().field("my_value", value).endObject(); + b.startObject().field("another_field1", 1).endObject(); + b.startObject().field("another_field2", 2).endObject(); + b.endArray(); + } + ) + ); + assertEquals("{}", getSyntheticSourceWithFieldLimit(new SourceFilter(null, new String[] { "my_object" }), b -> { b.startArray("my_object"); b.startObject().field("my_value", value).endObject(); @@ -271,16 +317,6 @@ public void testIgnoredArray() throws IOException { }) ); - assertEquals( - "{\"my_array\":[{\"int_value\":10},{\"int_value\":20}]}", - getSyntheticSourceWithFieldLimit(new SourceFilter(new String[] { "my_array" }, null), b -> { - b.startArray("my_array"); - b.startObject().field("int_value", 10).endObject(); - b.startObject().field("int_value", 20).endObject(); - b.endArray(); - }) - ); - assertEquals("{}", getSyntheticSourceWithFieldLimit(new SourceFilter(null, new String[] { "my_array" }), b -> { b.startArray("my_array"); b.startObject().field("int_value", 10).endObject(); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/XContentDataHelperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/XContentDataHelperTests.java index e1dc12b844609..ecf59b611080b 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/XContentDataHelperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/XContentDataHelperTests.java @@ -61,7 +61,7 @@ private String encodeAndDecodeCustom(XContentType type, Object value) throws IOE var encoded = XContentDataHelper.encodeToken(parser); assertThat(XContentDataHelper.isEncodedObject(encoded), equalTo(value instanceof Map)); var decoded = XContentFactory.jsonBuilder(); - XContentDataHelper.decodeAndWrite(XContentParserConfiguration.EMPTY, decoded, encoded); + XContentDataHelper.decodeAndWrite(decoded, encoded); return Strings.toString(decoded); } @@ -130,7 +130,7 @@ public void testEmbeddedObject() throws IOException { assertFalse(XContentDataHelper.isEncodedObject(encoded)); var decoded = XContentFactory.jsonBuilder(); - XContentDataHelper.decodeAndWrite(XContentParserConfiguration.EMPTY, decoded, encoded); + XContentDataHelper.decodeAndWrite(decoded, encoded); assertEquals("\"" + Base64.getEncoder().encodeToString(embedded.compressed()) + "\"", Strings.toString(decoded)); } @@ -139,7 +139,7 @@ public void testEmbeddedObject() throws IOException { assertTrue(XContentDataHelper.isEncodedObject(encoded)); var decoded = XContentFactory.jsonBuilder(); - XContentDataHelper.decodeAndWrite(XContentParserConfiguration.EMPTY, decoded, encoded); + XContentDataHelper.decodeAndWrite(decoded, encoded); var decodedBytes = BytesReference.bytes(builder); assertEquals(originalBytes, decodedBytes); @@ -154,12 +154,12 @@ public void testObject() throws IOException { builder.humanReadable(true); var encoded = XContentDataHelper.encodeToken(p); assertTrue(XContentDataHelper.isEncodedObject(encoded)); - XContentDataHelper.decodeAndWrite(XContentParserConfiguration.EMPTY, builder, encoded); + XContentDataHelper.decodeAndWrite(builder, encoded); assertEquals(object, Strings.toString(builder)); XContentBuilder builder2 = XContentFactory.jsonBuilder(); builder2.humanReadable(true); - XContentDataHelper.decodeAndWrite(XContentParserConfiguration.EMPTY, builder2, XContentDataHelper.encodeXContentBuilder(builder)); + XContentDataHelper.decodeAndWrite(builder2, XContentDataHelper.encodeXContentBuilder(builder)); assertEquals(object, Strings.toString(builder2)); } @@ -177,12 +177,17 @@ public void testObjectWithFilter() throws IOException { ); XContentBuilder builder = XContentFactory.jsonBuilder(); builder.humanReadable(true); - XContentDataHelper.decodeAndWrite(parserConfig, builder, XContentDataHelper.encodeToken(p)); + XContentDataHelper.decodeAndWriteXContent(parserConfig, builder, XContentType.JSON, XContentDataHelper.encodeToken(p)); assertEquals(filterObject, Strings.toString(builder)); XContentBuilder builder2 = XContentFactory.jsonBuilder(); builder2.humanReadable(true); - XContentDataHelper.decodeAndWrite(parserConfig, builder2, XContentDataHelper.encodeXContentBuilder(builder)); + XContentDataHelper.decodeAndWriteXContent( + parserConfig, + builder2, + XContentType.JSON, + XContentDataHelper.encodeXContentBuilder(builder) + ); assertEquals(filterObject, Strings.toString(builder2)); } @@ -200,12 +205,17 @@ public void testObjectWithFilterRootPath() throws IOException { ); XContentBuilder builder = XContentFactory.jsonBuilder(); builder.humanReadable(true); - XContentDataHelper.decodeAndWrite(parserConfig, builder, XContentDataHelper.encodeToken(p)); + XContentDataHelper.decodeAndWriteXContent(parserConfig, builder, XContentType.JSON, XContentDataHelper.encodeToken(p)); assertEquals(filterObject, Strings.toString(builder)); XContentBuilder builder2 = XContentFactory.jsonBuilder(); builder2.humanReadable(true); - XContentDataHelper.decodeAndWrite(parserConfig, builder2, XContentDataHelper.encodeXContentBuilder(builder)); + XContentDataHelper.decodeAndWriteXContent( + parserConfig, + builder2, + XContentType.JSON, + XContentDataHelper.encodeXContentBuilder(builder) + ); assertEquals(filterObject, Strings.toString(builder2)); }