diff --git a/src/main/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointParser.java b/src/main/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointParser.java index 191ece83..cffcf2c5 100644 --- a/src/main/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointParser.java +++ b/src/main/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointParser.java @@ -7,6 +7,8 @@ import java.io.IOException; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; import org.opensearch.OpenSearchParseException; @@ -15,13 +17,18 @@ import org.opensearch.common.xcontent.XContentParser; import org.opensearch.common.xcontent.XContentSubParser; import org.opensearch.common.xcontent.support.MapXContentParser; +import org.opensearch.geometry.ShapeType; /** * Parse the value and set XYPoint represented as a String, Object, WKT, array. */ public class XYPointParser { + private static final String ERR_MSG_INVALID_TOKEN = "token [{}] not allowed"; + private static final String ERR_MSG_INVALID_FIELDS = "field must be either [x|y], or [type|coordinates]"; private static final String X_PARAMETER = "x"; private static final String Y_PARAMETER = "y"; + public static final String GEOJSON_TYPE = "type"; + public static final String GEOJSON_COORDS = "coordinates"; private static final String NULL_VALUE_PARAMETER = "null_value"; private static final Boolean TRUE = true; @@ -33,7 +40,7 @@ public class XYPointParser { * @return {@link XYPoint} after setting the x and y coordinates parsed from the parse * @throws OpenSearchParseException */ - public static XYPoint parseXYPoint(Object value, final boolean ignoreZValue) throws OpenSearchParseException { + public static XYPoint parseXYPoint(final Object value, final boolean ignoreZValue) throws OpenSearchParseException { Objects.requireNonNull(value, "input value which needs to be parsed should not be null"); try ( @@ -54,13 +61,13 @@ public static XYPoint parseXYPoint(Object value, final boolean ignoreZValue) thr } /** - * Parse the values to set the XYPoint which was represented as a String, Object, WKT or an array. - * + * Parse the values to set the XYPoint which was represented as a String, Object, WKT, Array, or GeoJson. * * * @param parser {@link XContentParser} to parse the value from @@ -69,103 +76,207 @@ public static XYPoint parseXYPoint(Object value, final boolean ignoreZValue) thr * @throws IOException * @throws OpenSearchParseException */ - public static XYPoint parseXYPoint(XContentParser parser, final boolean ignoreZValue) throws IOException, OpenSearchParseException { + public static XYPoint parseXYPoint(final XContentParser parser, final boolean ignoreZValue) throws IOException, + OpenSearchParseException { Objects.requireNonNull(parser, "parser should not be null"); - XYPoint point = new XYPoint(); - double x = Double.NaN; - double y = Double.NaN; - - if (parser.currentToken() == XContentParser.Token.START_OBJECT) { - try (XContentSubParser subParser = new XContentSubParser(parser)) { - while (subParser.nextToken() != XContentParser.Token.END_OBJECT) { - if (subParser.currentToken() != XContentParser.Token.FIELD_NAME) { - throw new OpenSearchParseException("token [{}] not allowed", subParser.currentToken()); - } - String field = subParser.currentName(); - if (!(X_PARAMETER.equals(field) || Y_PARAMETER.equals(field))) { - throw new OpenSearchParseException("field must be either [{}] or [{}]", X_PARAMETER, Y_PARAMETER); - } - if (X_PARAMETER.equals(field)) { - subParser.nextToken(); - switch (subParser.currentToken()) { - case VALUE_NUMBER: - case VALUE_STRING: - try { - x = subParser.doubleValue(TRUE); - } catch (NumberFormatException numberFormatException) { - throw new OpenSearchParseException("[x] must be valid double value", numberFormatException); - } - break; - default: - throw new OpenSearchParseException("[x] must be a number"); - } - } - if (Y_PARAMETER.equals(field)) { - subParser.nextToken(); - switch (subParser.currentToken()) { - case VALUE_NUMBER: - case VALUE_STRING: - try { - y = subParser.doubleValue(TRUE); - } catch (NumberFormatException numberFormatException) { - throw new OpenSearchParseException("[y] must be valid double value", numberFormatException); - } - break; - default: - throw new OpenSearchParseException("[y] must be a number"); - } - } - } + switch (parser.currentToken()) { + case START_OBJECT: + parseXYPointObject(parser, point, ignoreZValue); + break; + case START_ARRAY: + parseXYPointArray(parser, point, ignoreZValue); + break; + case VALUE_STRING: + String val = parser.text(); + point.resetFromString(val, ignoreZValue); + break; + default: + throw new OpenSearchParseException("expecting xy_point as an array, a string, or an object format"); + } + return point; + } + + /** + * Parse point in either basic object format or GeoJson format + * + * Parser is expected to be pointing the start of the object. + * ex) Parser is pointing { in {"x": 12.3, "y": 45.6} + * + * @param parser {@link XContentParser} to parse the value from + * @param point {@link XYPoint} to be returned after setting the x and y coordinates parsed from the parse + * @return {@link XYPoint} after setting the x and y coordinates parsed from the parse + * @throws IOException + */ + private static XYPoint parseXYPointObject(final XContentParser parser, final XYPoint point, final boolean ignoreZValue) + throws IOException { + try (XContentSubParser subParser = new XContentSubParser(parser)) { + if (subParser.nextToken() != XContentParser.Token.FIELD_NAME) { + throw new OpenSearchParseException(ERR_MSG_INVALID_TOKEN, subParser.currentToken()); } - if (Double.isNaN(x)) { - throw new OpenSearchParseException("field [{}] missing", X_PARAMETER); + + String field = subParser.currentName(); + if (X_PARAMETER.equals(field) || Y_PARAMETER.equals(field)) { + parseXYPointObjectBasicFields(subParser, point); + } else if (GEOJSON_TYPE.equals(field) || GEOJSON_COORDS.equals(field)) { + parseGeoJsonFields(subParser, point, ignoreZValue); + } else { + throw new OpenSearchParseException(ERR_MSG_INVALID_FIELDS); } - if (Double.isNaN(y)) { - throw new OpenSearchParseException("field [{}] missing", Y_PARAMETER); + + if (subParser.nextToken() != XContentParser.Token.END_OBJECT) { + throw new OpenSearchParseException(ERR_MSG_INVALID_FIELDS); } - return point.reset(x, y); + + return point; } + } - if (parser.currentToken() == XContentParser.Token.START_ARRAY) { - return parseXYPointArray(parser, ignoreZValue, x, y); + /** + * Parse point in basic object format + * + * Parser is expected to be pointing the first field of the object. + * ex) Parser is pointing x in {"x": 12.3, "y": 45.6} + * + * @param parser {@link XContentParser} to parse the value from + * @param point {@link XYPoint} to be returned after setting the x and y coordinates parsed from the parse + * @return {@link XYPoint} after setting the x and y coordinates parsed from the parse + * @throws IOException + */ + private static XYPoint parseXYPointObjectBasicFields(final XContentParser parser, final XYPoint point) throws IOException { + final int numberOfFields = 2; + Map data = new HashMap<>(); + for (int i = 0; i < numberOfFields; i++) { + if (i != 0) { + parser.nextToken(); + } + + if (parser.currentToken() != XContentParser.Token.FIELD_NAME) { + break; + } + + String field = parser.currentName(); + if (X_PARAMETER.equals(field) == false && Y_PARAMETER.equals(field) == false) { + throw new OpenSearchParseException(ERR_MSG_INVALID_FIELDS); + } + switch (parser.nextToken()) { + case VALUE_NUMBER: + case VALUE_STRING: + try { + data.put(field, parser.doubleValue(true)); + } catch (NumberFormatException e) { + throw new OpenSearchParseException("[{}] and [{}] must be valid double values", e, X_PARAMETER, Y_PARAMETER); + } + break; + default: + throw new OpenSearchParseException("{} must be a number", field); + } } - if (parser.currentToken() == XContentParser.Token.VALUE_STRING) { - String val = parser.text(); - return point.resetFromString(val, ignoreZValue); + if (data.get(X_PARAMETER) == null) { + throw new OpenSearchParseException("field [{}] missing", X_PARAMETER); + } + if (data.get(Y_PARAMETER) == null) { + throw new OpenSearchParseException("field [{}] missing", Y_PARAMETER); } - throw new OpenSearchParseException("Expected xy_point. But, the provided mapping is not of type xy_point"); + + return point.reset(data.get(X_PARAMETER), data.get(Y_PARAMETER)); } /** - * Parse the values to set the XYPoint which was represented as an array. + * Parse point in GeoJson format + * + * Parser is expected to be pointing the first field of the object. + * ex) Parser is pointing type in {"type": "Point", "coordinates": [12.3, 45.6]} * - * @param subParser {@link XContentParser} to parse the values from an array + * @param parser {@link XContentParser} to parse the value from + * @param point {@link XYPoint} to be returned after setting the x and y coordinates parsed from the parse * @param ignoreZValue boolean parameter which decides if third coordinate needs to be ignored or not - * @param x x coordinate that will be set by parsing the value from array - * @param y y coordinate that will be set by parsing the value from array * @return {@link XYPoint} after setting the x and y coordinates parsed from the parse * @throws IOException */ - private static XYPoint parseXYPointArray(XContentParser subParser, final boolean ignoreZValue, double x, double y) throws IOException { - XYPoint point = new XYPoint(); - int element = 0; - while (subParser.nextToken() != XContentParser.Token.END_ARRAY) { - if (subParser.currentToken() != XContentParser.Token.VALUE_NUMBER) { - throw new OpenSearchParseException("numeric value expected"); + private static XYPoint parseGeoJsonFields(final XContentParser parser, final XYPoint point, final boolean ignoreZValue) + throws IOException { + final int numberOfFields = 2; + boolean hasTypePoint = false; + boolean hasCoordinates = false; + for (int i = 0; i < numberOfFields; i++) { + if (i != 0) { + parser.nextToken(); + } + + if (parser.currentToken() != XContentParser.Token.FIELD_NAME) { + if (hasTypePoint == false) { + throw new OpenSearchParseException("field [{}] missing", GEOJSON_TYPE); + } + if (hasCoordinates == false) { + throw new OpenSearchParseException("field [{}] missing", GEOJSON_COORDS); + } } - element++; - if (element == 1) { - x = subParser.doubleValue(); - } else if (element == 2) { - y = subParser.doubleValue(); - } else if (element == 3) { - XYPoint.assertZValue(ignoreZValue, subParser.doubleValue()); + + if (GEOJSON_TYPE.equals(parser.currentName())) { + if (parser.nextToken() != XContentParser.Token.VALUE_STRING) { + throw new OpenSearchParseException("{} must be a string", GEOJSON_TYPE); + } + + // To be consistent with geo_shape parsing, ignore case here as well. + if (ShapeType.POINT.name().equalsIgnoreCase(parser.text()) == false) { + throw new OpenSearchParseException("{} must be Point", GEOJSON_TYPE); + } + hasTypePoint = true; + } else if (GEOJSON_COORDS.equals(parser.currentName())) { + if (parser.nextToken() != XContentParser.Token.START_ARRAY) { + throw new OpenSearchParseException("{} must be an array", GEOJSON_COORDS); + } + parseXYPointArray(parser, point, ignoreZValue); + hasCoordinates = true; } else { - throw new OpenSearchParseException("[xy_point] field type does not accept more than 3 dimensions"); + throw new OpenSearchParseException(ERR_MSG_INVALID_FIELDS); } } - return point.reset(x, y); + + return point; + } + + /** + * Parse point in an array format + * + * Parser is expected to be pointing the start of the array. + * ex) Parser is pointing [ in [12.3, 45.6] + * + * @param parser {@link XContentParser} to parse the value from + * @param point {@link XYPoint} to be returned after setting the x and y coordinates parsed from the parse + * @param ignoreZValue boolean parameter which decides if third coordinate needs to be ignored or not + * @return {@link XYPoint} after setting the x and y coordinates parsed from the parse + * @throws IOException + */ + private static XYPoint parseXYPointArray(final XContentParser parser, final XYPoint point, final boolean ignoreZValue) + throws IOException { + try (XContentSubParser subParser = new XContentSubParser(parser)) { + double x = Double.NaN; + double y = Double.NaN; + + int element = 0; + while (subParser.nextToken() != XContentParser.Token.END_ARRAY) { + if (parser.currentToken() != XContentParser.Token.VALUE_NUMBER) { + throw new OpenSearchParseException("numeric value expected"); + } + element++; + if (element == 1) { + x = parser.doubleValue(); + } else if (element == 2) { + y = parser.doubleValue(); + } else if (element == 3) { + XYPoint.assertZValue(ignoreZValue, parser.doubleValue()); + } else { + throw new OpenSearchParseException("[xy_point] field type does not accept more than 3 values"); + } + } + + if (element < 2) { + throw new OpenSearchParseException("[xy_point] field type should have at least two dimensions"); + } + return point.reset(x, y); + } } } diff --git a/src/test/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointFieldMapperIT.java b/src/test/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointFieldMapperIT.java index f7e4c90b..6935cc9b 100644 --- a/src/test/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointFieldMapperIT.java +++ b/src/test/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointFieldMapperIT.java @@ -19,6 +19,9 @@ public class XYPointFieldMapperIT extends GeospatialRestTestCase { private static final String FIELD_X_KEY = "x"; private static final String FIELD_Y_KEY = "y"; + private static final String FIELD_GEOJSON_TYPE_KEY = "type"; + private static final String FIELD_GEOJSON_TYPE_VALUE = "Point"; + private static final String FIELD_GEOJSON_COORDINATES_KEY = "coordinates"; public void testMappingWithXYPointField() throws Exception { String indexName = GeospatialTestHelper.randomLowerCaseString(); @@ -85,6 +88,20 @@ public void testIndexWithXYPointFieldAsObjectFormat() throws Exception { deleteIndex(indexName); } + public void testIndexWithXYPointFieldAsGeoJsonFormat() throws Exception { + String indexName = GeospatialTestHelper.randomLowerCaseString(); + String fieldName = GeospatialTestHelper.randomLowerCaseString(); + createIndex(indexName, Settings.EMPTY, Map.of(fieldName, XYPointFieldMapper.CONTENT_TYPE)); + final Point point = ShapeObjectBuilder.randomPoint(randomBoolean()); + String docID = indexDocument(indexName, getDocumentWithObjectValueForXYPoint(fieldName, point)); + assertTrue("failed to index document", getIndexDocumentCount(indexName) > 0); + final Map document = getDocument(docID, indexName); + assertNotNull("failed to get indexed document", document); + String expectedValue = String.format(Locale.ROOT, "{x=%s, y=%s}", point.getX(), point.getY()); + assertEquals("failed to index xy_point", expectedValue, document.get(fieldName).toString()); + deleteIndex(indexName); + } + private String getDocumentWithWKTValueForXYPoint(String fieldName, Geometry geometry) throws Exception { return buildContentAsString(build -> build.field(fieldName, geometry.toString())); } @@ -106,4 +123,13 @@ private String getDocumentWithObjectValueForXYPoint(String fieldName, Point poin }); } + private String getDocumentWithGeoJsonValueForXYPoint(String fieldName, Point point) throws Exception { + return buildContentAsString(build -> { + build.startObject(fieldName); + build.field(FIELD_GEOJSON_TYPE_KEY, FIELD_GEOJSON_TYPE_VALUE); + build.array(FIELD_GEOJSON_COORDINATES_KEY, new double[] { point.getX(), point.getY() }); + build.endObject(); + }); + } + } diff --git a/src/test/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointFieldMapperTests.java b/src/test/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointFieldMapperTests.java index b31faff8..37369572 100644 --- a/src/test/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointFieldMapperTests.java +++ b/src/test/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointFieldMapperTests.java @@ -29,6 +29,10 @@ public class XYPointFieldMapperTests extends FieldMapperTestCase2 builder.startObject(FIELD_NAME) + .field(FIELD_GEOJSON_TYPE_KEY, FIELD_GEOJSON_TYPE_VALUE) + .array(FIELD_GEOJSON_COORDINATES_KEY, new double[] { randomDouble(), randomDouble() }) + .endObject() + ) + ); + final IndexableField[] actualFieldValues = doc.rootDoc().getFields(FIELD_NAME); + assertNotNull("FieldValue is null", actualFieldValues); + assertEquals("mismatch in field values count", 2, actualFieldValues.length); + } + public void testIndexAsArrayMultiPoints() throws IOException { int numOfPoints = randomIntBetween(MIN_NUM_POINTS, MAX_NUM_POINTS); DocumentMapper mapper = createDocumentMapper(fieldMapping(this::minimalMapping)); @@ -228,6 +247,24 @@ public void testIndexAsWKTMultiPoints() throws IOException { assertEquals("mismatch in field values count", 2 * numOfPoints, actualFieldValues.length); } + public void testIndexAsGeoJsonMultiPoints() throws IOException { + int numOfPoints = randomIntBetween(MIN_NUM_POINTS, MAX_NUM_POINTS); + DocumentMapper mapper = createDocumentMapper(fieldMapping(this::minimalMapping)); + ParsedDocument doc = mapper.parse(source(builder -> { + builder.startArray(FIELD_NAME); + for (int i = 0; i < numOfPoints; i++) { + builder.startObject() + .field(FIELD_GEOJSON_TYPE_KEY, FIELD_GEOJSON_TYPE_VALUE) + .array(FIELD_GEOJSON_COORDINATES_KEY, new double[] { randomDouble(), randomDouble() }) + .endObject(); + } + builder.endArray(); + })); + final IndexableField[] actualFieldValues = doc.rootDoc().getFields(FIELD_NAME); + assertNotNull("FieldValue is null", actualFieldValues); + assertEquals("mismatch in field values count", 2 * numOfPoints, actualFieldValues.length); + } + public void testIgnoreZValue() throws IOException { boolean z_value = randomBoolean(); DocumentMapper mapper = createDocumentMapper( diff --git a/src/test/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointParsingTests.java b/src/test/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointParserTests.java similarity index 69% rename from src/test/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointParsingTests.java rename to src/test/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointParserTests.java index a99d6541..b0f1e2a8 100644 --- a/src/test/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointParsingTests.java +++ b/src/test/java/org/opensearch/geospatial/index/mapper/xypoint/XYPointParserTests.java @@ -5,6 +5,8 @@ package org.opensearch.geospatial.index.mapper.xypoint; +import static org.opensearch.common.xcontent.XContentFactory.jsonBuilder; + import java.io.IOException; import org.opensearch.OpenSearchParseException; @@ -14,7 +16,7 @@ import org.opensearch.common.xcontent.json.JsonXContent; import org.opensearch.test.OpenSearchTestCase; -public class XYPointParsingTests extends OpenSearchTestCase { +public class XYPointParserTests extends OpenSearchTestCase { private static final String FIELD_X_KEY = "x"; private static final String FIELD_Y_KEY = "y"; @@ -104,7 +106,7 @@ public void testInvalidField() throws IOException { OpenSearchParseException.class, () -> XYPointParser.parseXYPoint(parser, randomBoolean()) ); - assertEquals("Validation for invalid fields failed", "field must be either [x] or [y]", e.getMessage()); + assertEquals("Validation for invalid fields failed", "field must be either [x|y], or [type|coordinates]", e.getMessage()); } } @@ -120,7 +122,7 @@ public void testParsingInvalidObject() throws IOException { OpenSearchParseException.class, () -> XYPointParser.parseXYPoint(parser, randomBoolean()) ); - assertEquals("Validation failed for invalid x and y values", "[y] must be valid double value", e.getMessage()); + assertEquals("Validation failed for invalid x and y values", "[x] and [y] must be valid double values", e.getMessage()); // Skip the 'y' field and y coordinate XContentBuilder content1 = JsonXContent.contentBuilder(); @@ -183,4 +185,71 @@ private XContentParser xyAsWKT(double x, double y) throws IOException { parser.nextToken(); return parser; } + + public void testParserGeoPointGeoJson() throws IOException { + XYPoint xyPoint = new XYPoint(randomDouble(), randomDouble()); + double[] coordinates = { xyPoint.getX(), xyPoint.getY() }; + XContentBuilder json1 = jsonBuilder().startObject().field("type", "Point").array("coordinates", coordinates).endObject(); + try (XContentParser parser = createParser(json1)) { + parser.nextToken(); + XYPoint paredPoint = XYPointParser.parseXYPoint(parser, randomBoolean()); + assertEquals(xyPoint, paredPoint); + } + + XContentBuilder json2 = jsonBuilder().startObject().field("type", "PoInT").array("coordinates", coordinates).endObject(); + try (XContentParser parser = createParser(json2)) { + parser.nextToken(); + XYPoint paredPoint = XYPointParser.parseXYPoint(parser, randomBoolean()); + assertEquals(xyPoint, paredPoint); + } + } + + public void testParserGeoPointGeoJsonMissingField() throws IOException { + XYPoint xyPoint = new XYPoint(randomDouble(), randomDouble()); + double[] coordinates = { xyPoint.getX(), xyPoint.getY() }; + XContentBuilder missingType = jsonBuilder().startObject().array("coordinates", coordinates).endObject(); + expectParseException(missingType, "field [type] missing"); + + XContentBuilder missingCoordinates = jsonBuilder().startObject().field("type", "Point").endObject(); + expectParseException(missingCoordinates, "field [coordinates] missing"); + } + + public void testParserGeoPointGeoJsonUnknownField() throws IOException { + XYPoint xyPoint = new XYPoint(randomDouble(), randomDouble()); + double[] coordinates = { xyPoint.getX(), xyPoint.getY() }; + XContentBuilder unknownField = jsonBuilder().startObject() + .field("type", "Point") + .array("coordinates", coordinates) + .field("unknown", "value") + .endObject(); + expectParseException(unknownField, "field must be either [x|y], or [type|coordinates]"); + } + + public void testParserGeoPointGeoJsonInvalidValue() throws IOException { + XYPoint xyPoint = new XYPoint(randomDouble(), randomDouble()); + double[] coordinates = { xyPoint.getX(), xyPoint.getY() }; + XContentBuilder invalidGeoJsonType = jsonBuilder().startObject() + .field("type", "invalid") + .array("coordinates", coordinates) + .endObject(); + expectParseException(invalidGeoJsonType, "type must be Point"); + + String[] coordinatesInString = { String.valueOf(xyPoint.getX()), String.valueOf(xyPoint.getY()) }; + XContentBuilder invalideCoordinatesType = jsonBuilder().startObject() + .field("type", "Point") + .array("coordinates", coordinatesInString) + .endObject(); + expectParseException(invalideCoordinatesType, "numeric value expected"); + } + + private void expectParseException(XContentBuilder content, String errMsg) throws IOException { + try (XContentParser parser = createParser(content)) { + parser.nextToken(); + OpenSearchParseException ex = expectThrows( + OpenSearchParseException.class, + () -> XYPointParser.parseXYPoint(parser, randomBoolean()) + ); + assertEquals(errMsg, ex.getMessage()); + } + } } diff --git a/src/yamlRestTest/resources/rest-api-spec/test/xypoint/10_basic.yml b/src/yamlRestTest/resources/rest-api-spec/test/xypoint/10_basic.yml new file mode 100644 index 00000000..0f8c8c25 --- /dev/null +++ b/src/yamlRestTest/resources/rest-api-spec/test/xypoint/10_basic.yml @@ -0,0 +1,135 @@ +setup: + - do: + indices.create: + index: test_1 + body: + settings: + number_of_replicas: 0 + mappings: + properties: + geometry: + type: xy_point + +--- +"Single point test": + - do: + bulk: + refresh: true + body: + - index: + _index: test_1 + _id: 1 + - geometry: + x: 52.374081 + y: 4.912350 + - index: + _index: test_1 + _id: 2 + - geometry: "52.369219,4.901618" + - index: + _index: test_1 + _id: 3 + - geometry: [ 52.371667, 4.914722 ] + - index: + _index: test_1 + _id: 4 + - geometry: "POINT (52.371667 4.914722)" + - index: + _index: test_1 + _id: 5 + - geometry: + type: Point + coordinates: [ 52.371667, 4.914722 ] + + - do: + search: + index: test_1 + rest_total_hits_as_int: true + body: + query: + xy_shape: + geometry: + shape: + type: "envelope" + coordinates: [ [ 51, 5 ], [ 53, 3 ] ] + + - match: { hits.total: 5 } + + - do: + search: + index: test_1 + rest_total_hits_as_int: true + body: + query: + xy_shape: + geometry: + shape: + type: "envelope" + coordinates: [ [ 151, 15 ], [ 153, 13 ] ] + + - match: { hits.total: 0 } + +--- +"Multi points test": + - do: + bulk: + refresh: true + body: + - index: + _index: test_1 + _id: 1 + - geometry: + - {x: 52.374081, y: 4.912350} + - {x: 152.374081, y: 14.912350} + - index: + _index: test_1 + _id: 2 + - geometry: + - "52.369219,4.901618" + - "152.369219,14.901618" + - index: + _index: test_1 + _id: 3 + - geometry: + - [ 52.371667, 4.914722 ] + - [ 152.371667, 14.914722 ] + - index: + _index: test_1 + _id: 4 + - geometry: + - "POINT (52.371667 4.914722)" + - "POINT (152.371667 14.914722)" + - index: + _index: test_1 + _id: 5 + - geometry: + - {type: Point, coordinates: [ 52.371667, 4.914722 ]} + - {type: Point, coordinates: [ 152.371667, 14.914722 ]} + + - do: + search: + index: test_1 + rest_total_hits_as_int: true + body: + query: + xy_shape: + geometry: + shape: + type: "envelope" + coordinates: [ [ 51, 5 ], [ 53, 3 ] ] + + - match: { hits.total: 5 } + + - do: + search: + index: test_1 + rest_total_hits_as_int: true + body: + query: + xy_shape: + geometry: + shape: + type: "envelope" + coordinates: [ [ 151, 15 ], [ 153, 13 ] ] + + - match: { hits.total: 5 }