GeoBoundingBoxQueryBuilder should fail when topLeft and bottomRight are the same coordinate

This commit is contained in:
Nicholas Knize 2016-05-31 14:17:01 -05:00
parent ee193f7697
commit f77f79c24a
4 changed files with 42 additions and 4 deletions

View File

@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import org.apache.lucene.spatial.geopoint.document.GeoPointField; import org.apache.lucene.spatial.geopoint.document.GeoPointField;
import org.apache.lucene.geo.Rectangle;
import org.apache.lucene.util.BitUtil; import org.apache.lucene.util.BitUtil;
/** /**
@ -176,6 +177,26 @@ public class GeoHashUtils {
return BASE_32[((x & 1) + ((y & 1) * 2) + ((x & 2) * 2) + ((y & 2) * 4) + ((x & 4) * 4)) % 32]; return BASE_32[((x & 1) + ((y & 1) * 2) + ((x & 2) * 2) + ((y & 2) * 4) + ((x & 4) * 4)) % 32];
} }
/**
* Computes the bounding box coordinates from a given geohash
*
* @param geohash Geohash of the defined cell
* @return GeoRect rectangle defining the bounding box
*/
public static Rectangle bbox(final String geohash) {
// bottom left is the coordinate
GeoPoint bottomLeft = GeoPoint.fromGeohash(geohash);
long ghLong = longEncode(geohash);
// shift away the level
ghLong >>>= 4;
// deinterleave and add 1 to lat and lon to get topRight
long lat = BitUtil.deinterleave(ghLong >>> 1) + 1;
long lon = BitUtil.deinterleave(ghLong) + 1;
GeoPoint topRight = GeoPoint.fromGeohash(BitUtil.interleave((int)lon, (int)lat) << 4 | geohash.length());
return new Rectangle(bottomLeft.lat(), topRight.lat(), bottomLeft.lon(), topRight.lon());
}
/** /**
* Calculate all neighbors of a given geohash cell. * Calculate all neighbors of a given geohash cell.
* *

View File

@ -19,6 +19,7 @@
package org.elasticsearch.index.query; package org.elasticsearch.index.query;
import org.apache.lucene.geo.Rectangle;
import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.spatial.geopoint.document.GeoPointField; import org.apache.lucene.spatial.geopoint.document.GeoPointField;
@ -28,6 +29,7 @@ import org.elasticsearch.Version;
import org.elasticsearch.common.Numbers; import org.elasticsearch.common.Numbers;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.geo.GeoHashUtils;
import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.geo.GeoUtils; import org.elasticsearch.common.geo.GeoUtils;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
@ -155,7 +157,13 @@ public class GeoBoundingBoxQueryBuilder extends AbstractQueryBuilder<GeoBounding
if (top < bottom) { if (top < bottom) {
throw new IllegalArgumentException("top is below bottom corner: " + throw new IllegalArgumentException("top is below bottom corner: " +
top + " vs. " + bottom); top + " vs. " + bottom);
} } else if (top == bottom) {
throw new IllegalArgumentException("top cannot be the same as bottom: " +
top + " == " + bottom);
} else if (left == right) {
throw new IllegalArgumentException("left cannot be the same as right: " +
left + " == " + right);
}
// we do not check longitudes as the query generation code can deal with flipped left/right values // we do not check longitudes as the query generation code can deal with flipped left/right values
} }
@ -174,6 +182,16 @@ public class GeoBoundingBoxQueryBuilder extends AbstractQueryBuilder<GeoBounding
return setCorners(topLeft.getLat(), topLeft.getLon(), bottomRight.getLat(), bottomRight.getLon()); return setCorners(topLeft.getLat(), topLeft.getLon(), bottomRight.getLat(), bottomRight.getLon());
} }
/**
* Adds points from a single geohash.
* @param geohash The geohash for computing the bounding box.
*/
public GeoBoundingBoxQueryBuilder setCorners(final String geohash) {
// get the bounding box of the geohash and set topLeft and bottomRight
Rectangle ghBBox = GeoHashUtils.bbox(geohash);
return setCorners(new GeoPoint(ghBBox.maxLat, ghBBox.minLon), new GeoPoint(ghBBox.minLat, ghBBox.maxLon));
}
/** /**
* Adds points. * Adds points.
* @param topLeft topLeft point to add as geohash. * @param topLeft topLeft point to add as geohash.

View File

@ -349,7 +349,7 @@ public class GeoBoundingBoxQueryBuilderTests extends AbstractQueryTestCase<GeoBo
@Override @Override
public void fillIn(double coordinate, GeoBoundingBoxQueryBuilder qb) { public void fillIn(double coordinate, GeoBoundingBoxQueryBuilder qb) {
qb.setCorners(qb.topLeft().getLat(), qb.topLeft().getLon(), qb.topLeft().getLat(), coordinate); qb.setCorners(qb.topLeft().getLat(), qb.topLeft().getLon(), qb.bottomRight().getLat(), coordinate);
} }
} }

View File

@ -21,7 +21,6 @@ package org.elasticsearch.search.aggregations.bucket;
import com.carrotsearch.hppc.ObjectIntHashMap; import com.carrotsearch.hppc.ObjectIntHashMap;
import com.carrotsearch.hppc.ObjectIntMap; import com.carrotsearch.hppc.ObjectIntMap;
import com.carrotsearch.hppc.cursors.ObjectIntCursor; import com.carrotsearch.hppc.cursors.ObjectIntCursor;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
@ -202,7 +201,7 @@ public class GeoHashGridIT extends ESIntegTestCase {
public void testFiltered() throws Exception { public void testFiltered() throws Exception {
GeoBoundingBoxQueryBuilder bbox = new GeoBoundingBoxQueryBuilder("location"); GeoBoundingBoxQueryBuilder bbox = new GeoBoundingBoxQueryBuilder("location");
bbox.setCorners(smallestGeoHash, smallestGeoHash).queryName("bbox"); bbox.setCorners(smallestGeoHash).queryName("bbox");
for (int precision = 1; precision <= PRECISION; precision++) { for (int precision = 1; precision <= PRECISION; precision++) {
SearchResponse response = client().prepareSearch("idx") SearchResponse response = client().prepareSearch("idx")
.addAggregation( .addAggregation(