Handle properly indexing rectangles that crosses the dateline (#53810) (#53947)

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.
This commit is contained in:
Ignacio Vera 2020-03-23 09:12:03 +01:00 committed by GitHub
parent cde8725e3c
commit efd1838206
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 49 additions and 1 deletions

View File

@ -26,6 +26,7 @@ import org.elasticsearch.common.geo.GeoLineDecomposer;
import org.elasticsearch.common.geo.GeoPolygonDecomposer;
import org.elasticsearch.common.geo.GeoShapeUtils;
import org.elasticsearch.common.geo.GeoShapeType;
import org.elasticsearch.common.geo.GeoUtils;
import org.elasticsearch.geometry.Circle;
import org.elasticsearch.geometry.Geometry;
import org.elasticsearch.geometry.GeometryCollection;
@ -261,7 +262,15 @@ public final class GeoShapeIndexer implements AbstractGeometryFieldMapper.Indexe
@Override
public Void visit(Rectangle r) {
addFields(LatLonShape.createIndexableFields(name, GeoShapeUtils.toLucenePolygon(r)));
if (r.getMinLon() > r.getMaxLon()) {
Rectangle left = new Rectangle(r.getMinLon(), GeoUtils.MAX_LON, r.getMaxLat(), r.getMinLat());
addFields(LatLonShape.createIndexableFields(name, GeoShapeUtils.toLucenePolygon(left)));
Rectangle right = new Rectangle(GeoUtils.MIN_LON, r.getMaxLon(), r.getMaxLat(), r.getMinLat());
addFields(LatLonShape.createIndexableFields(name, GeoShapeUtils.toLucenePolygon(right)));
} else {
addFields(LatLonShape.createIndexableFields(name, GeoShapeUtils.toLucenePolygon(r)));
}
return null;
}

View File

@ -19,6 +19,7 @@
package org.elasticsearch.common.geo;
import org.apache.lucene.index.IndexableField;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
@ -33,6 +34,7 @@ import org.elasticsearch.geometry.MultiPoint;
import org.elasticsearch.geometry.MultiPolygon;
import org.elasticsearch.geometry.Point;
import org.elasticsearch.geometry.Polygon;
import org.elasticsearch.geometry.Rectangle;
import org.elasticsearch.index.mapper.GeoShapeIndexer;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
@ -292,6 +294,24 @@ public class GeometryIndexerTests extends ESTestCase {
assertEquals(indexed, indexer.prepareForIndexing(multiPoint));
}
public void testRectangle() {
Rectangle indexed = new Rectangle(-179, -178, 10, -10);
Geometry processed = indexer.prepareForIndexing(indexed);
assertEquals(indexed, processed);
// a rectangle is broken into two triangles
List<IndexableField> fields = indexer.indexShape(null, indexed);
assertEquals(fields.size(), 2);
indexed = new Rectangle(179, -179, 10, -10);
processed = indexer.prepareForIndexing(indexed);
assertEquals(indexed, processed);
// a rectangle crossing the dateline is broken into 4 triangles
fields = indexer.indexShape(null, indexed);
assertEquals(fields.size(), 4);
}
public void testPolygon() {
Polygon polygon = new Polygon(new LinearRing(new double[]{160, 200, 200, 160, 160}, new double[]{10, 10, 20, 20, 10}));
Geometry indexed = new MultiPolygon(Arrays.asList(

View File

@ -799,4 +799,23 @@ public class GeoShapeQueryTests extends GeoQueryTests {
assertEquals(0, response.getHits().getTotalHits().value);
}
public void testIndexRectangleSpanningDateLine() throws Exception {
String mapping = Strings.toString(createRandomMapping());
client().admin().indices().prepareCreate("test").addMapping("type1", mapping, XContentType.JSON).get();
ensureGreen();
EnvelopeBuilder envelopeBuilder = new EnvelopeBuilder(new Coordinate(178, 10), new Coordinate(-178, -10));
XContentBuilder docSource = envelopeBuilder.toXContent(jsonBuilder().startObject().field("geo"), null).endObject();
client().prepareIndex("test", "type1", "1").setSource(docSource).setRefreshPolicy(IMMEDIATE).get();
ShapeBuilder filterShape = new PointBuilder(179, 0);
GeoShapeQueryBuilder geoShapeQueryBuilder = QueryBuilders.geoShapeQuery("geo", filterShape);
geoShapeQueryBuilder.relation(ShapeRelation.INTERSECTS);
SearchResponse result = client().prepareSearch("test").setQuery(geoShapeQueryBuilder).get();
assertSearchResponse(result);
assertHitCount(result, 1);
}
}