Skip to content

Commit 856721c

Browse files
authored
Handle properly indexing rectangles that crosses the dateline (#53810)
When indexing a rectangle that crosses the dateline, we are currently not handling it properly and we index a polygon that do not cross the dateline. This changes generates two polygons wrapping the dateline.
1 parent e404249 commit 856721c

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

server/src/main/java/org/elasticsearch/index/mapper/GeoShapeIndexer.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.elasticsearch.common.geo.GeoPolygonDecomposer;
2727
import org.elasticsearch.common.geo.GeoShapeUtils;
2828
import org.elasticsearch.common.geo.GeoShapeType;
29+
import org.elasticsearch.common.geo.GeoUtils;
2930
import org.elasticsearch.geometry.Circle;
3031
import org.elasticsearch.geometry.Geometry;
3132
import org.elasticsearch.geometry.GeometryCollection;
@@ -261,7 +262,15 @@ public Void visit(Polygon polygon) {
261262

262263
@Override
263264
public Void visit(Rectangle r) {
264-
addFields(LatLonShape.createIndexableFields(name, GeoShapeUtils.toLucenePolygon(r)));
265+
if (r.getMinLon() > r.getMaxLon()) {
266+
Rectangle left = new Rectangle(r.getMinLon(), GeoUtils.MAX_LON, r.getMaxLat(), r.getMinLat());
267+
addFields(LatLonShape.createIndexableFields(name, GeoShapeUtils.toLucenePolygon(left)));
268+
Rectangle right = new Rectangle(GeoUtils.MIN_LON, r.getMaxLon(), r.getMaxLat(), r.getMinLat());
269+
addFields(LatLonShape.createIndexableFields(name, GeoShapeUtils.toLucenePolygon(right)));
270+
271+
} else {
272+
addFields(LatLonShape.createIndexableFields(name, GeoShapeUtils.toLucenePolygon(r)));
273+
}
265274
return null;
266275
}
267276

server/src/test/java/org/elasticsearch/common/geo/GeometryIndexerTests.java

+20
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.elasticsearch.common.geo;
2121

22+
import org.apache.lucene.index.IndexableField;
2223
import org.elasticsearch.common.xcontent.XContentBuilder;
2324
import org.elasticsearch.common.xcontent.XContentFactory;
2425
import org.elasticsearch.common.xcontent.XContentParser;
@@ -33,6 +34,7 @@
3334
import org.elasticsearch.geometry.MultiPolygon;
3435
import org.elasticsearch.geometry.Point;
3536
import org.elasticsearch.geometry.Polygon;
37+
import org.elasticsearch.geometry.Rectangle;
3638
import org.elasticsearch.index.mapper.GeoShapeIndexer;
3739
import org.elasticsearch.test.ESTestCase;
3840
import java.io.IOException;
@@ -292,6 +294,24 @@ public void testMultiPoint() {
292294
assertEquals(indexed, indexer.prepareForIndexing(multiPoint));
293295
}
294296

297+
public void testRectangle() {
298+
Rectangle indexed = new Rectangle(-179, -178, 10, -10);
299+
Geometry processed = indexer.prepareForIndexing(indexed);
300+
assertEquals(indexed, processed);
301+
302+
// a rectangle is broken into two triangles
303+
List<IndexableField> fields = indexer.indexShape(null, indexed);
304+
assertEquals(fields.size(), 2);
305+
306+
indexed = new Rectangle(179, -179, 10, -10);
307+
processed = indexer.prepareForIndexing(indexed);
308+
assertEquals(indexed, processed);
309+
310+
// a rectangle crossing the dateline is broken into 4 triangles
311+
fields = indexer.indexShape(null, indexed);
312+
assertEquals(fields.size(), 4);
313+
}
314+
295315
public void testPolygon() {
296316
Polygon polygon = new Polygon(new LinearRing(new double[]{160, 200, 200, 160, 160}, new double[]{10, 10, 20, 20, 10}));
297317
Geometry indexed = new MultiPolygon(Arrays.asList(

server/src/test/java/org/elasticsearch/search/geo/GeoShapeQueryTests.java

+20
Original file line numberDiff line numberDiff line change
@@ -791,4 +791,24 @@ public void testDistanceQuery() throws Exception {
791791
.get();
792792
assertEquals(0, response.getHits().getTotalHits().value);
793793
}
794+
795+
public void testIndexRectangleSpanningDateLine() throws Exception {
796+
String mapping = Strings.toString(createRandomMapping());
797+
798+
client().admin().indices().prepareCreate("test").setMapping(mapping).get();
799+
ensureGreen();
800+
801+
EnvelopeBuilder envelopeBuilder = new EnvelopeBuilder(new Coordinate(178, 10), new Coordinate(-178, -10));
802+
803+
XContentBuilder docSource = envelopeBuilder.toXContent(jsonBuilder().startObject().field("geo"), null).endObject();
804+
client().prepareIndex("test").setId("1").setSource(docSource).setRefreshPolicy(IMMEDIATE).get();
805+
806+
ShapeBuilder filterShape = new PointBuilder(179, 0);
807+
808+
GeoShapeQueryBuilder geoShapeQueryBuilder = QueryBuilders.geoShapeQuery("geo", filterShape);
809+
geoShapeQueryBuilder.relation(ShapeRelation.INTERSECTS);
810+
SearchResponse result = client().prepareSearch("test").setQuery(geoShapeQueryBuilder).get();
811+
assertSearchResponse(result);
812+
assertHitCount(result, 1);
813+
}
794814
}

0 commit comments

Comments
 (0)