From 7bc18567285117d19bac6394a8e6fa60c9eda04d Mon Sep 17 00:00:00 2001 From: Heemin Kim Date: Mon, 14 Nov 2022 18:19:39 -0800 Subject: [PATCH] Revert changes in AbstractPointGeometryFieldMapper The change made in AbstractPointGeometryFieldMapper class with commit 050389736599e40c49278e900d5060f75b959282 introduced a performace degradation during point data indexing. Reverting it therefore. The change is about consolidating array format parsing code for point type in a single place to acheive following benefits. 1. Allow plugins to override array parsing logic. Plugins can add its own parsing logic for point field by providing object parser. However, it cannot override array format. Therefore, plugin have to use whatever implemented in AbstractPointGeometryFieldMapper class. 2. Enhanced code quality by removing duplicated code There is no change in functionality because 1. There is no change in functionality in OpenSearch and 2. No plugins have its own parsing logic for point data in array format yet. Signed-off-by: Heemin Kim --- .../AbstractPointGeometryFieldMapper.java | 74 ++++++------------- .../mapper/GeoPointFieldMapperTests.java | 6 -- 2 files changed, 22 insertions(+), 58 deletions(-) diff --git a/server/src/main/java/org/opensearch/index/mapper/AbstractPointGeometryFieldMapper.java b/server/src/main/java/org/opensearch/index/mapper/AbstractPointGeometryFieldMapper.java index b5db3546185ba..658bcf295262d 100644 --- a/server/src/main/java/org/opensearch/index/mapper/AbstractPointGeometryFieldMapper.java +++ b/server/src/main/java/org/opensearch/index/mapper/AbstractPointGeometryFieldMapper.java @@ -36,14 +36,11 @@ import org.opensearch.common.CheckedBiFunction; import org.opensearch.common.Explicit; import org.opensearch.common.ParseField; -import org.opensearch.common.bytes.BytesReference; +import org.opensearch.common.geo.GeoPoint; import org.opensearch.common.geo.GeometryFormat; import org.opensearch.common.geo.GeometryParser; -import org.opensearch.common.xcontent.DeprecationHandler; import org.opensearch.common.xcontent.LoggingDeprecationHandler; -import org.opensearch.common.xcontent.NamedXContentRegistry; import org.opensearch.common.xcontent.XContentBuilder; -import org.opensearch.common.xcontent.XContentFactory; import org.opensearch.common.xcontent.XContentParser; import org.opensearch.geometry.Geometry; import org.opensearch.geometry.Point; @@ -245,7 +242,6 @@ default boolean isNormalizable(double coord) { * @opensearch.internal */ public static class PointParser

extends Parser> { - private static final int MAX_NUMBER_OF_VALUES_IN_ARRAY_FORMAT = 3; /** * Note that this parser is only used for formatting values. */ @@ -285,27 +281,32 @@ private P process(P in) { @Override public List

parse(XContentParser parser) throws IOException, ParseException { + if (parser.currentToken() == XContentParser.Token.START_ARRAY) { - parser.nextToken(); - if (parser.currentToken() == XContentParser.Token.VALUE_NUMBER) { - XContentBuilder xContentBuilder = reconstructArrayXContent(parser); - try ( - XContentParser subParser = createParser( - parser.getXContentRegistry(), - parser.getDeprecationHandler(), - xContentBuilder - ); - ) { - return Collections.singletonList(process(objectParser.apply(subParser, pointSupplier.get()))); + XContentParser.Token token = parser.nextToken(); + P point = pointSupplier.get(); + ArrayList

points = new ArrayList<>(); + if (token == XContentParser.Token.VALUE_NUMBER) { + double x = parser.doubleValue(); + parser.nextToken(); + double y = parser.doubleValue(); + token = parser.nextToken(); + if (token == XContentParser.Token.VALUE_NUMBER) { + GeoPoint.assertZValue(ignoreZValue, parser.doubleValue()); + } else if (token != XContentParser.Token.END_ARRAY) { + throw new OpenSearchParseException("field type does not accept > 3 dimensions"); } + + point.resetCoords(x, y); + points.add(process(point)); } else { - ArrayList

points = new ArrayList<>(); - while (parser.currentToken() != XContentParser.Token.END_ARRAY) { - points.add(process(objectParser.apply(parser, pointSupplier.get()))); - parser.nextToken(); + while (token != XContentParser.Token.END_ARRAY) { + points.add(process(objectParser.apply(parser, point))); + point = pointSupplier.get(); + token = parser.nextToken(); } - return points; } + return points; } else if (parser.currentToken() == XContentParser.Token.VALUE_NULL) { if (nullValue == null) { return null; @@ -317,37 +318,6 @@ public List

parse(XContentParser parser) throws IOException, ParseException { } } - private XContentParser createParser( - NamedXContentRegistry namedXContentRegistry, - DeprecationHandler deprecationHandler, - XContentBuilder xContentBuilder - ) throws IOException { - XContentParser subParser = xContentBuilder.contentType() - .xContent() - .createParser(namedXContentRegistry, deprecationHandler, BytesReference.bytes(xContentBuilder).streamInput()); - subParser.nextToken(); - return subParser; - } - - private XContentBuilder reconstructArrayXContent(XContentParser parser) throws IOException { - XContentBuilder builder = XContentFactory.jsonBuilder().startArray(); - int numberOfValuesAdded = 0; - while (parser.currentToken() != XContentParser.Token.END_ARRAY) { - if (parser.currentToken() != XContentParser.Token.VALUE_NUMBER) { - throw new OpenSearchParseException("numeric value expected"); - } - builder.value(parser.doubleValue()); - parser.nextToken(); - - // Allows one more value to be added so that the error case can be handled by a parser - if (++numberOfValuesAdded > MAX_NUMBER_OF_VALUES_IN_ARRAY_FORMAT) { - break; - } - } - builder.endArray(); - return builder; - } - @Override public Object format(List

points, String format) { List result = new ArrayList<>(); diff --git a/server/src/test/java/org/opensearch/index/mapper/GeoPointFieldMapperTests.java b/server/src/test/java/org/opensearch/index/mapper/GeoPointFieldMapperTests.java index 060901a3eba38..1b4c95d9ceb8f 100644 --- a/server/src/test/java/org/opensearch/index/mapper/GeoPointFieldMapperTests.java +++ b/server/src/test/java/org/opensearch/index/mapper/GeoPointFieldMapperTests.java @@ -164,12 +164,6 @@ public void testLatLonInOneValueArray() throws Exception { assertThat(doc.rootDoc().getFields("field"), arrayWithSize(4)); } - public void testLatLonInArrayMoreThanThreeValues() throws Exception { - DocumentMapper mapper = createDocumentMapper(fieldMapping(b -> b.field("type", "geo_point").field("ignore_z_value", true))); - Exception e = expectThrows(MapperParsingException.class, () -> mapper.parse(source(b -> b.array("field", 1.2, 1.3, 1.4, 1.5)))); - assertThat(e.getCause().getMessage(), containsString("[geo_point] field type does not accept more than 3 values")); - } - public void testLonLatArray() throws Exception { DocumentMapper mapper = createDocumentMapper(fieldMapping(this::minimalMapping)); ParsedDocument doc = mapper.parse(source(b -> b.startArray("field").value(1.3).value(1.2).endArray()));