Add support for Lucene 5.4 GeoPoint queries
This commit adds query support for Lucene 5.4 GeoPointField type along with backward compatibility for (soon to be) "legacy" geo_point indexes.
This commit is contained in:
parent
10f9de4d5f
commit
86ae08fa88
|
@ -66,6 +66,19 @@ public class GeoUtils {
|
|||
/** Earth ellipsoid polar distance in meters */
|
||||
public static final double EARTH_POLAR_DISTANCE = Math.PI * EARTH_SEMI_MINOR_AXIS;
|
||||
|
||||
/** Returns the maximum distance/radius from the point 'center' before overlapping */
|
||||
public static double maxRadialDistance(GeoPoint center) {
|
||||
return SloppyMath.haversin(center.lat(), center.lon(), center.lat(), (180.0 + center.lon()) % 360)*1000.0;
|
||||
}
|
||||
|
||||
/** Returns the minimum between the provided distance 'initialRadius' and the
|
||||
* maximum distance/radius from the point 'center' before overlapping
|
||||
**/
|
||||
public static double maxRadialDistance(GeoPoint center, double initialRadius) {
|
||||
final double maxRadius = maxRadialDistance(center);
|
||||
return Math.min(initialRadius, maxRadius);
|
||||
}
|
||||
|
||||
/** Returns true if latitude is actually a valid latitude value.*/
|
||||
public static boolean isValidLatitude(double latitude) {
|
||||
if (Double.isNaN(latitude) || Double.isInfinite(latitude) || latitude < GeoUtils.MIN_LAT || latitude > GeoUtils.MAX_LAT) {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.search.GeoPointInBBoxQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.Numbers;
|
||||
|
@ -263,21 +264,26 @@ public class GeoBoundingBoxQueryBuilder extends AbstractQueryBuilder<GeoBounding
|
|||
}
|
||||
GeoPointFieldMapper.GeoPointFieldType geoFieldType = ((GeoPointFieldMapper.GeoPointFieldType) fieldType);
|
||||
|
||||
Query result;
|
||||
// norelease cut over to .before(Version.2_2_0) once GeoPointFieldV2 is fully merged
|
||||
if (context.indexVersionCreated().after(Version.CURRENT)) {
|
||||
return new GeoPointInBBoxQuery(fieldType.names().fullName(), topLeft.lon(), bottomRight.lat(), bottomRight.lon(), topLeft.lat());
|
||||
}
|
||||
|
||||
Query query;
|
||||
switch(type) {
|
||||
case INDEXED:
|
||||
result = IndexedGeoBoundingBoxQuery.create(luceneTopLeft, luceneBottomRight, geoFieldType);
|
||||
query = IndexedGeoBoundingBoxQuery.create(luceneTopLeft, luceneBottomRight, geoFieldType);
|
||||
break;
|
||||
case MEMORY:
|
||||
IndexGeoPointFieldData indexFieldData = context.getForField(fieldType);
|
||||
result = new InMemoryGeoBoundingBoxQuery(luceneTopLeft, luceneBottomRight, indexFieldData);
|
||||
query = new InMemoryGeoBoundingBoxQuery(luceneTopLeft, luceneBottomRight, indexFieldData);
|
||||
break;
|
||||
default:
|
||||
// Someone extended the type enum w/o adjusting this switch statement.
|
||||
throw new IllegalStateException("geo bounding box type [" + type + "] not supported.");
|
||||
}
|
||||
|
||||
return result;
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.search.GeoPointDistanceQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.Strings;
|
||||
|
@ -221,11 +222,16 @@ public class GeoDistanceQueryBuilder extends AbstractQueryBuilder<GeoDistanceQue
|
|||
if (!(fieldType instanceof GeoPointFieldMapper.GeoPointFieldType)) {
|
||||
throw new QueryShardException(shardContext, "field [" + fieldName + "] is not a geo_point field");
|
||||
}
|
||||
GeoPointFieldMapper.GeoPointFieldType geoFieldType = ((GeoPointFieldMapper.GeoPointFieldType) fieldType);
|
||||
|
||||
IndexGeoPointFieldData indexFieldData = shardContext.getForField(fieldType);
|
||||
Query query = new GeoDistanceRangeQuery(center, null, normDistance, true, false, geoDistance, geoFieldType, indexFieldData, optimizeBbox);
|
||||
return query;
|
||||
// norelease cut over to .before(Version.2_2_0) once GeoPointFieldV2 is fully merged
|
||||
if (shardContext.indexVersionCreated().onOrBefore(Version.CURRENT)) {
|
||||
GeoPointFieldMapper.GeoPointFieldType geoFieldType = ((GeoPointFieldMapper.GeoPointFieldType) fieldType);
|
||||
IndexGeoPointFieldData indexFieldData = shardContext.getForField(fieldType);
|
||||
return new GeoDistanceRangeQuery(center, null, normDistance, true, false, geoDistance, geoFieldType, indexFieldData, optimizeBbox);
|
||||
}
|
||||
|
||||
normDistance = GeoUtils.maxRadialDistance(center, normDistance);
|
||||
return new GeoPointDistanceQuery(fieldType.names().fullName(), center.lon(), center.lat(), normDistance);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.search.GeoPointDistanceRangeQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.Strings;
|
||||
|
@ -38,6 +39,8 @@ import java.io.IOException;
|
|||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.apache.lucene.util.GeoUtils.TOLERANCE;
|
||||
|
||||
public class GeoDistanceRangeQueryBuilder extends AbstractQueryBuilder<GeoDistanceRangeQueryBuilder> {
|
||||
|
||||
public static final String NAME = "geo_distance_range";
|
||||
|
@ -235,7 +238,10 @@ public class GeoDistanceRangeQueryBuilder extends AbstractQueryBuilder<GeoDistan
|
|||
fromValue = DistanceUnit.parse((String) from, unit, DistanceUnit.DEFAULT);
|
||||
}
|
||||
fromValue = geoDistance.normalize(fromValue, DistanceUnit.DEFAULT);
|
||||
} else {
|
||||
fromValue = new Double(0);
|
||||
}
|
||||
|
||||
if (to != null) {
|
||||
if (to instanceof Number) {
|
||||
toValue = unit.toMeters(((Number) to).doubleValue());
|
||||
|
@ -243,6 +249,8 @@ public class GeoDistanceRangeQueryBuilder extends AbstractQueryBuilder<GeoDistan
|
|||
toValue = DistanceUnit.parse((String) to, unit, DistanceUnit.DEFAULT);
|
||||
}
|
||||
toValue = geoDistance.normalize(toValue, DistanceUnit.DEFAULT);
|
||||
} else {
|
||||
toValue = GeoUtils.maxRadialDistance(point);
|
||||
}
|
||||
|
||||
MappedFieldType fieldType = context.fieldMapper(fieldName);
|
||||
|
@ -252,11 +260,18 @@ public class GeoDistanceRangeQueryBuilder extends AbstractQueryBuilder<GeoDistan
|
|||
if (!(fieldType instanceof GeoPointFieldMapper.GeoPointFieldType)) {
|
||||
throw new QueryShardException(context, "field [" + fieldName + "] is not a geo_point field");
|
||||
}
|
||||
GeoPointFieldMapper.GeoPointFieldType geoFieldType = ((GeoPointFieldMapper.GeoPointFieldType) fieldType);
|
||||
|
||||
IndexGeoPointFieldData indexFieldData = context.getForField(fieldType);
|
||||
return new GeoDistanceRangeQuery(point, fromValue, toValue, includeLower, includeUpper, geoDistance, geoFieldType,
|
||||
indexFieldData, optimizeBbox);
|
||||
// norelease cut over to .before(Version.2_2_0) once GeoPointFieldV2 is fully merged
|
||||
if (context.indexVersionCreated().onOrBefore(Version.CURRENT)) {
|
||||
GeoPointFieldMapper.GeoPointFieldType geoFieldType = ((GeoPointFieldMapper.GeoPointFieldType) fieldType);
|
||||
IndexGeoPointFieldData indexFieldData = context.getForField(fieldType);
|
||||
return new GeoDistanceRangeQuery(point, fromValue, toValue, includeLower, includeUpper, geoDistance, geoFieldType,
|
||||
indexFieldData, optimizeBbox);
|
||||
}
|
||||
|
||||
return new GeoPointDistanceRangeQuery(fieldType.names().fullName(), point.lon(), point.lat(),
|
||||
(includeLower) ? fromValue : fromValue + TOLERANCE,
|
||||
(includeUpper) ? toValue : toValue - TOLERANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.search.GeoPointInPolygonQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.Strings;
|
||||
|
@ -104,6 +105,7 @@ public class GeoPolygonQueryBuilder extends AbstractQueryBuilder<GeoPolygonQuery
|
|||
for (GeoPoint geoPoint : this.shell) {
|
||||
shell.add(new GeoPoint(geoPoint));
|
||||
}
|
||||
final int shellSize = shell.size();
|
||||
|
||||
final boolean indexCreatedBeforeV2_0 = context.indexVersionCreated().before(Version.V_2_0_0);
|
||||
// validation was not available prior to 2.x, so to support bwc
|
||||
|
@ -135,8 +137,21 @@ public class GeoPolygonQueryBuilder extends AbstractQueryBuilder<GeoPolygonQuery
|
|||
throw new QueryShardException(context, "field [" + fieldName + "] is not a geo_point field");
|
||||
}
|
||||
|
||||
IndexGeoPointFieldData indexFieldData = context.getForField(fieldType);
|
||||
return new GeoPolygonQuery(indexFieldData, shell.toArray(new GeoPoint[shell.size()]));
|
||||
// norelease cut over to .before(Version.2_2_0) once GeoPointFieldV2 is fully merged
|
||||
if (context.indexVersionCreated().onOrBefore(Version.CURRENT)) {
|
||||
IndexGeoPointFieldData indexFieldData = context.getForField(fieldType);
|
||||
return new GeoPolygonQuery(indexFieldData, shell.toArray(new GeoPoint[shellSize]));
|
||||
}
|
||||
|
||||
double[] lats = new double[shellSize];
|
||||
double[] lons = new double[shellSize];
|
||||
GeoPoint p;
|
||||
for (int i=0; i<shellSize; ++i) {
|
||||
p = new GeoPoint(shell.get(i));
|
||||
lats[i] = p.lat();
|
||||
lons[i] = p.lon();
|
||||
}
|
||||
return new GeoPointInPolygonQuery(fieldType.names().fullName(), lons, lats);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -22,14 +22,14 @@ package org.elasticsearch.index.query;
|
|||
import com.spatial4j.core.io.GeohashUtils;
|
||||
import com.spatial4j.core.shape.Rectangle;
|
||||
|
||||
import org.apache.lucene.search.BooleanClause;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.ConstantScoreQuery;
|
||||
import org.apache.lucene.search.NumericRangeQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.*;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.geo.GeoUtils;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.index.search.geo.InMemoryGeoBoundingBoxQuery;
|
||||
import org.elasticsearch.test.VersionUtils;
|
||||
import org.elasticsearch.test.geo.RandomShapeGenerator;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -423,11 +423,21 @@ public class GeoBoundingBoxQueryBuilderTests extends AbstractQueryTestCase<GeoBo
|
|||
|
||||
private void assertGeoBoundingBoxQuery(String query) throws IOException {
|
||||
Query parsedQuery = parseQuery(query).toQuery(createShardContext());
|
||||
InMemoryGeoBoundingBoxQuery filter = (InMemoryGeoBoundingBoxQuery) parsedQuery;
|
||||
assertThat(filter.fieldName(), equalTo(GEO_POINT_FIELD_NAME));
|
||||
assertThat(filter.topLeft().lat(), closeTo(40, 0.00001));
|
||||
assertThat(filter.topLeft().lon(), closeTo(-70, 0.00001));
|
||||
assertThat(filter.bottomRight().lat(), closeTo(30, 0.00001));
|
||||
assertThat(filter.bottomRight().lon(), closeTo(-80, 0.00001));
|
||||
// norelease cut over to .before(Version.2_2_0) once GeoPointFieldV2 is fully merged
|
||||
if (queryShardContext().indexVersionCreated().onOrBefore(Version.CURRENT)) {
|
||||
InMemoryGeoBoundingBoxQuery filter = (InMemoryGeoBoundingBoxQuery) parsedQuery;
|
||||
assertThat(filter.fieldName(), equalTo(GEO_POINT_FIELD_NAME));
|
||||
assertThat(filter.topLeft().lat(), closeTo(40, 1E-5));
|
||||
assertThat(filter.topLeft().lon(), closeTo(-70, 1E-5));
|
||||
assertThat(filter.bottomRight().lat(), closeTo(30, 1E-5));
|
||||
assertThat(filter.bottomRight().lon(), closeTo(-80, 1E-5));
|
||||
} else {
|
||||
GeoPointInBBoxQuery q = (GeoPointInBBoxQuery) parsedQuery;
|
||||
assertThat(q.getField(), equalTo(GEO_POINT_FIELD_NAME));
|
||||
assertThat(q.getMaxLat(), closeTo(40, 1E-5));
|
||||
assertThat(q.getMinLon(), closeTo(-70, 1E-5));
|
||||
assertThat(q.getMinLat(), closeTo(30, 1E-5));
|
||||
assertThat(q.getMaxLon(), closeTo(-80, 1E-5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,10 @@ package org.elasticsearch.index.query;
|
|||
|
||||
import com.spatial4j.core.shape.Point;
|
||||
|
||||
import org.apache.lucene.search.GeoPointDistanceQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.util.GeoUtils;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.geo.GeoDistance;
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.unit.DistanceUnit;
|
||||
|
@ -158,6 +161,16 @@ public class GeoDistanceQueryBuilderTests extends AbstractQueryTestCase<GeoDista
|
|||
|
||||
@Override
|
||||
protected void doAssertLuceneQuery(GeoDistanceQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException {
|
||||
Version version = context.indexVersionCreated();
|
||||
// norelease update to .before(Version.V_2_2_0 once GeoPointFieldV2 is fully merged
|
||||
if (version.onOrBefore(Version.CURRENT)) {
|
||||
assertLegacyQuery(queryBuilder, query);
|
||||
} else {
|
||||
assertGeoPointQuery(queryBuilder, query);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertLegacyQuery(GeoDistanceQueryBuilder queryBuilder, Query query) throws IOException {
|
||||
assertThat(query, instanceOf(GeoDistanceRangeQuery.class));
|
||||
GeoDistanceRangeQuery geoQuery = (GeoDistanceRangeQuery) query;
|
||||
assertThat(geoQuery.fieldName(), equalTo(queryBuilder.fieldName()));
|
||||
|
@ -169,11 +182,26 @@ public class GeoDistanceQueryBuilderTests extends AbstractQueryTestCase<GeoDista
|
|||
assertThat(geoQuery.minInclusiveDistance(), equalTo(Double.NEGATIVE_INFINITY));
|
||||
double distance = queryBuilder.distance();
|
||||
if (queryBuilder.geoDistance() != null) {
|
||||
distance = queryBuilder.geoDistance().normalize(distance, DistanceUnit.DEFAULT);
|
||||
distance = queryBuilder.geoDistance().normalize(distance, DistanceUnit.DEFAULT);
|
||||
}
|
||||
assertThat(geoQuery.maxInclusiveDistance(), closeTo(distance, Math.abs(distance) / 1000));
|
||||
}
|
||||
|
||||
private void assertGeoPointQuery(GeoDistanceQueryBuilder queryBuilder, Query query) throws IOException {
|
||||
assertThat(query, instanceOf(GeoPointDistanceQuery.class));
|
||||
GeoPointDistanceQuery geoQuery = (GeoPointDistanceQuery) query;
|
||||
assertThat(geoQuery.getField(), equalTo(queryBuilder.fieldName()));
|
||||
if (queryBuilder.point() != null) {
|
||||
assertThat(geoQuery.getCenterLat(), equalTo(queryBuilder.point().lat()));
|
||||
assertThat(geoQuery.getCenterLon(), equalTo(queryBuilder.point().lon()));
|
||||
}
|
||||
double distance = queryBuilder.distance();
|
||||
if (queryBuilder.geoDistance() != null) {
|
||||
distance = queryBuilder.geoDistance().normalize(distance, DistanceUnit.DEFAULT);
|
||||
assertThat(geoQuery.getRadiusMeters(), closeTo(distance, GeoUtils.TOLERANCE));
|
||||
}
|
||||
}
|
||||
|
||||
public void testParsingAndToQuery1() throws IOException {
|
||||
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
|
||||
String query = "{\n" +
|
||||
|
@ -185,7 +213,7 @@ public class GeoDistanceQueryBuilderTests extends AbstractQueryTestCase<GeoDista
|
|||
" }\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
assertGeoDistanceRangeQuery(query);
|
||||
assertGeoDistanceRangeQuery(query, 40, -70, 12, DistanceUnit.DEFAULT);
|
||||
}
|
||||
|
||||
public void testParsingAndToQuery2() throws IOException {
|
||||
|
@ -196,7 +224,7 @@ public class GeoDistanceQueryBuilderTests extends AbstractQueryTestCase<GeoDista
|
|||
" \"" + GEO_POINT_FIELD_NAME + "\":[-70, 40]\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
assertGeoDistanceRangeQuery(query);
|
||||
assertGeoDistanceRangeQuery(query, 40, -70, 12, DistanceUnit.DEFAULT);
|
||||
}
|
||||
|
||||
public void testParsingAndToQuery3() throws IOException {
|
||||
|
@ -207,7 +235,7 @@ public class GeoDistanceQueryBuilderTests extends AbstractQueryTestCase<GeoDista
|
|||
" \"" + GEO_POINT_FIELD_NAME + "\":\"40, -70\"\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
assertGeoDistanceRangeQuery(query);
|
||||
assertGeoDistanceRangeQuery(query, 40, -70, 12, DistanceUnit.DEFAULT);
|
||||
}
|
||||
|
||||
public void testParsingAndToQuery4() throws IOException {
|
||||
|
@ -218,7 +246,7 @@ public class GeoDistanceQueryBuilderTests extends AbstractQueryTestCase<GeoDista
|
|||
" \"" + GEO_POINT_FIELD_NAME + "\":\"drn5x1g8cu2y\"\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
assertGeoDistanceRangeQuery(query);
|
||||
assertGeoDistanceRangeQuery(query, 40, -70, 12, DistanceUnit.DEFAULT);
|
||||
}
|
||||
|
||||
public void testParsingAndToQuery5() throws IOException {
|
||||
|
@ -233,7 +261,7 @@ public class GeoDistanceQueryBuilderTests extends AbstractQueryTestCase<GeoDista
|
|||
" }\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
assertGeoDistanceRangeQuery(query);
|
||||
assertGeoDistanceRangeQuery(query, 40, -70, 12, DistanceUnit.DEFAULT);
|
||||
}
|
||||
|
||||
public void testParsingAndToQuery6() throws IOException {
|
||||
|
@ -248,7 +276,7 @@ public class GeoDistanceQueryBuilderTests extends AbstractQueryTestCase<GeoDista
|
|||
" }\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
assertGeoDistanceRangeQuery(query);
|
||||
assertGeoDistanceRangeQuery(query, 40, -70, 12, DistanceUnit.DEFAULT);
|
||||
}
|
||||
|
||||
public void testParsingAndToQuery7() throws IOException {
|
||||
|
@ -262,13 +290,7 @@ public class GeoDistanceQueryBuilderTests extends AbstractQueryTestCase<GeoDista
|
|||
" }\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
Query parsedQuery = parseQuery(query).toQuery(createShardContext());
|
||||
GeoDistanceRangeQuery filter = (GeoDistanceRangeQuery) parsedQuery;
|
||||
assertThat(filter.fieldName(), equalTo(GEO_POINT_FIELD_NAME));
|
||||
assertThat(filter.lat(), closeTo(40, 0.00001));
|
||||
assertThat(filter.lon(), closeTo(-70, 0.00001));
|
||||
assertThat(filter.minInclusiveDistance(), equalTo(Double.NEGATIVE_INFINITY));
|
||||
assertThat(filter.maxInclusiveDistance(), closeTo(DistanceUnit.DEFAULT.convert(0.012, DistanceUnit.MILES), 0.00001));
|
||||
assertGeoDistanceRangeQuery(query, 40, -70, 0.012, DistanceUnit.DEFAULT);
|
||||
}
|
||||
|
||||
public void testParsingAndToQuery8() throws IOException {
|
||||
|
@ -282,13 +304,7 @@ public class GeoDistanceQueryBuilderTests extends AbstractQueryTestCase<GeoDista
|
|||
" }\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
Query parsedQuery = parseQuery(query).toQuery(createShardContext());
|
||||
GeoDistanceRangeQuery filter = (GeoDistanceRangeQuery) parsedQuery;
|
||||
assertThat(filter.fieldName(), equalTo(GEO_POINT_FIELD_NAME));
|
||||
assertThat(filter.lat(), closeTo(40, 0.00001));
|
||||
assertThat(filter.lon(), closeTo(-70, 0.00001));
|
||||
assertThat(filter.minInclusiveDistance(), equalTo(Double.NEGATIVE_INFINITY));
|
||||
assertThat(filter.maxInclusiveDistance(), closeTo(DistanceUnit.KILOMETERS.convert(12, DistanceUnit.MILES), 0.00001));
|
||||
assertGeoDistanceRangeQuery(query, 40, -70, 12, DistanceUnit.KILOMETERS);
|
||||
}
|
||||
|
||||
public void testParsingAndToQuery9() throws IOException {
|
||||
|
@ -303,7 +319,7 @@ public class GeoDistanceQueryBuilderTests extends AbstractQueryTestCase<GeoDista
|
|||
" }\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
assertGeoDistanceRangeQuery(query);
|
||||
assertGeoDistanceRangeQuery(query, 40, -70, 12, DistanceUnit.DEFAULT);
|
||||
}
|
||||
|
||||
public void testParsingAndToQuery10() throws IOException {
|
||||
|
@ -318,7 +334,7 @@ public class GeoDistanceQueryBuilderTests extends AbstractQueryTestCase<GeoDista
|
|||
" }\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
assertGeoDistanceRangeQuery(query);
|
||||
assertGeoDistanceRangeQuery(query, 40, -70, 12, DistanceUnit.DEFAULT);
|
||||
}
|
||||
|
||||
public void testParsingAndToQuery11() throws IOException {
|
||||
|
@ -332,7 +348,7 @@ public class GeoDistanceQueryBuilderTests extends AbstractQueryTestCase<GeoDista
|
|||
" }\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
assertGeoDistanceRangeQuery(query);
|
||||
assertGeoDistanceRangeQuery(query, 40, -70, 12, DistanceUnit.DEFAULT);
|
||||
}
|
||||
|
||||
public void testParsingAndToQuery12() throws IOException {
|
||||
|
@ -347,17 +363,27 @@ public class GeoDistanceQueryBuilderTests extends AbstractQueryTestCase<GeoDista
|
|||
" }\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
assertGeoDistanceRangeQuery(query);
|
||||
assertGeoDistanceRangeQuery(query, 40, -70, 12, DistanceUnit.DEFAULT);
|
||||
}
|
||||
|
||||
private void assertGeoDistanceRangeQuery(String query) throws IOException {
|
||||
private void assertGeoDistanceRangeQuery(String query, double lat, double lon, double distance, DistanceUnit distanceUnit) throws IOException {
|
||||
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
|
||||
Query parsedQuery = parseQuery(query).toQuery(createShardContext());
|
||||
GeoDistanceRangeQuery filter = (GeoDistanceRangeQuery) parsedQuery;
|
||||
assertThat(filter.fieldName(), equalTo(GEO_POINT_FIELD_NAME));
|
||||
assertThat(filter.lat(), closeTo(40, 0.00001));
|
||||
assertThat(filter.lon(), closeTo(-70, 0.00001));
|
||||
assertThat(filter.minInclusiveDistance(), equalTo(Double.NEGATIVE_INFINITY));
|
||||
assertThat(filter.maxInclusiveDistance(), closeTo(DistanceUnit.DEFAULT.convert(12, DistanceUnit.MILES), 0.00001));
|
||||
Version version = queryShardContext().indexVersionCreated();
|
||||
// norelease update to .before(Version.V_2_2_0 once GeoPointFieldV2 is fully merged
|
||||
if (version.onOrBefore(Version.CURRENT)) {
|
||||
GeoDistanceRangeQuery q = (GeoDistanceRangeQuery) parsedQuery;
|
||||
assertThat(q.fieldName(), equalTo(GEO_POINT_FIELD_NAME));
|
||||
assertThat(q.lat(), closeTo(lat, 1E-5D));
|
||||
assertThat(q.lon(), closeTo(lon, 1E-5D));
|
||||
assertThat(q.minInclusiveDistance(), equalTo(Double.NEGATIVE_INFINITY));
|
||||
assertThat(q.maxInclusiveDistance(), closeTo(distanceUnit.convert(distance, DistanceUnit.MILES), 1E-5D));
|
||||
} else {
|
||||
GeoPointDistanceQuery q = (GeoPointDistanceQuery) parsedQuery;
|
||||
assertThat(q.getField(), equalTo(GEO_POINT_FIELD_NAME));
|
||||
assertThat(q.getCenterLat(), closeTo(lat, 1E-5D));
|
||||
assertThat(q.getCenterLon(), closeTo(lon, 1E-5D));
|
||||
assertThat(q.getRadiusMeters(), closeTo(distanceUnit.convert(distance, DistanceUnit.MILES), 1E-5D));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.search.GeoPointDistanceRangeQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.util.SloppyMath;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.geo.GeoDistance;
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.geo.GeoUtils;
|
||||
|
@ -37,6 +40,7 @@ public class GeoDistanceRangeQueryTests extends AbstractQueryTestCase<GeoDistanc
|
|||
|
||||
@Override
|
||||
protected GeoDistanceRangeQueryBuilder doCreateTestQueryBuilder() {
|
||||
Version version = queryShardContext().indexVersionCreated();
|
||||
GeoDistanceRangeQueryBuilder builder;
|
||||
if (randomBoolean()) {
|
||||
builder = new GeoDistanceRangeQueryBuilder(GEO_POINT_FIELD_NAME, randomGeohash(1, 12));
|
||||
|
@ -49,35 +53,45 @@ public class GeoDistanceRangeQueryTests extends AbstractQueryTestCase<GeoDistanc
|
|||
builder = new GeoDistanceRangeQueryBuilder(GEO_POINT_FIELD_NAME, lat, lon);
|
||||
}
|
||||
}
|
||||
int fromValue = randomInt(1000000);
|
||||
int toValue = randomIntBetween(fromValue, 1000000);
|
||||
String fromToUnits = randomFrom(DistanceUnit.values()).toString();
|
||||
GeoPoint point = builder.point();
|
||||
// todo remove the following pole hack when LUCENE-6846 lands
|
||||
final double distToPole = SloppyMath.haversin(point.lat(), point.lon(), (point.lat()<0) ? -90.0 : 90.0, point.lon());
|
||||
final double maxRadius = GeoUtils.maxRadialDistance(point, distToPole);
|
||||
|
||||
final int fromValueMeters = randomInt((int)(maxRadius*0.5));
|
||||
final int toValueMeters = randomIntBetween(fromValueMeters, (int)maxRadius);
|
||||
DistanceUnit fromToUnits = randomFrom(DistanceUnit.values());
|
||||
final String fromToUnitsStr = fromToUnits.toString();
|
||||
final double fromValue = DistanceUnit.convert(fromValueMeters, DistanceUnit.DEFAULT, fromToUnits);
|
||||
final double toValue = DistanceUnit.convert(toValueMeters, DistanceUnit.DEFAULT, fromToUnits);
|
||||
|
||||
if (randomBoolean()) {
|
||||
int branch = randomInt(2);
|
||||
fromToUnits = DistanceUnit.DEFAULT;
|
||||
switch (branch) {
|
||||
case 0:
|
||||
builder.from(fromValue);
|
||||
builder.from(fromValueMeters);
|
||||
break;
|
||||
case 1:
|
||||
builder.to(toValue);
|
||||
break;
|
||||
case 2:
|
||||
builder.from(fromValue);
|
||||
builder.to(toValue);
|
||||
builder.from(fromValueMeters);
|
||||
builder.to(toValueMeters);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
int branch = randomInt(2);
|
||||
switch (branch) {
|
||||
case 0:
|
||||
builder.from(fromValue + fromToUnits);
|
||||
builder.from(fromValue + fromToUnitsStr);
|
||||
break;
|
||||
case 1:
|
||||
builder.to(toValue + fromToUnits);
|
||||
builder.to(toValue + fromToUnitsStr);
|
||||
break;
|
||||
case 2:
|
||||
builder.from(fromValue + fromToUnits);
|
||||
builder.to(toValue + fromToUnits);
|
||||
builder.from(fromValue + fromToUnitsStr);
|
||||
builder.to(toValue + fromToUnitsStr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -90,12 +104,11 @@ public class GeoDistanceRangeQueryTests extends AbstractQueryTestCase<GeoDistanc
|
|||
if (randomBoolean()) {
|
||||
builder.geoDistance(randomFrom(GeoDistance.values()));
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
builder.unit(randomFrom(DistanceUnit.values()));
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
// norelease update to .before(Version.V_2_2_0 once GeoPointFieldV2 is fully merged
|
||||
if (randomBoolean() && version.onOrBefore(Version.CURRENT)) {
|
||||
builder.optimizeBbox(randomFrom("none", "memory", "indexed"));
|
||||
}
|
||||
builder.unit(fromToUnits);
|
||||
if (randomBoolean()) {
|
||||
builder.setValidationMethod(randomFrom(GeoValidationMethod.values()));
|
||||
}
|
||||
|
@ -105,6 +118,16 @@ public class GeoDistanceRangeQueryTests extends AbstractQueryTestCase<GeoDistanc
|
|||
@Override
|
||||
protected void doAssertLuceneQuery(GeoDistanceRangeQueryBuilder queryBuilder, Query query, QueryShardContext context)
|
||||
throws IOException {
|
||||
Version version = context.indexVersionCreated();
|
||||
// norelease update to .before(Version.V_2_2_0 once GeoPointFieldV2 is fully merged
|
||||
if (version.onOrBefore(Version.CURRENT)) {
|
||||
assertLegacyQuery(queryBuilder, query);
|
||||
} else {
|
||||
assertGeoPointQuery(queryBuilder, query);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertLegacyQuery(GeoDistanceRangeQueryBuilder queryBuilder, Query query) throws IOException {
|
||||
assertThat(query, instanceOf(GeoDistanceRangeQuery.class));
|
||||
GeoDistanceRangeQuery geoQuery = (GeoDistanceRangeQuery) query;
|
||||
assertThat(geoQuery.fieldName(), equalTo(queryBuilder.fieldName()));
|
||||
|
@ -139,6 +162,35 @@ public class GeoDistanceRangeQueryTests extends AbstractQueryTestCase<GeoDistanc
|
|||
}
|
||||
}
|
||||
|
||||
private void assertGeoPointQuery(GeoDistanceRangeQueryBuilder queryBuilder, Query query) throws IOException {
|
||||
assertThat(query, instanceOf(GeoPointDistanceRangeQuery.class));
|
||||
GeoPointDistanceRangeQuery geoQuery = (GeoPointDistanceRangeQuery) query;
|
||||
assertThat(geoQuery.getField(), equalTo(queryBuilder.fieldName()));
|
||||
if (queryBuilder.point() != null) {
|
||||
GeoPoint expectedPoint = new GeoPoint(queryBuilder.point());
|
||||
GeoUtils.normalizePoint(expectedPoint);
|
||||
assertThat(geoQuery.getCenterLat(), equalTo(expectedPoint.lat()));
|
||||
assertThat(geoQuery.getCenterLon(), equalTo(expectedPoint.lon()));
|
||||
}
|
||||
if (queryBuilder.from() != null && queryBuilder.from() instanceof Number) {
|
||||
double fromValue = ((Number) queryBuilder.from()).doubleValue();
|
||||
if (queryBuilder.unit() != null) {
|
||||
fromValue = queryBuilder.unit().toMeters(fromValue);
|
||||
}
|
||||
assertThat(geoQuery.getMinRadiusMeters(), closeTo(fromValue, 1E-5));
|
||||
}
|
||||
if (queryBuilder.to() != null && queryBuilder.to() instanceof Number) {
|
||||
double toValue = ((Number) queryBuilder.to()).doubleValue();
|
||||
if (queryBuilder.unit() != null) {
|
||||
toValue = queryBuilder.unit().toMeters(toValue);
|
||||
}
|
||||
if (queryBuilder.geoDistance() != null) {
|
||||
toValue = queryBuilder.geoDistance().normalize(toValue, DistanceUnit.DEFAULT);
|
||||
}
|
||||
assertThat(geoQuery.getMaxRadiusMeters(), closeTo(toValue, 1E-5));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden here to ensure the test is only run if at least one type is
|
||||
* present in the mappings. Geo queries do not execute if the field is not
|
||||
|
|
|
@ -22,7 +22,9 @@ package org.elasticsearch.index.query;
|
|||
import com.spatial4j.core.shape.jts.JtsGeometry;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
import org.apache.lucene.search.GeoPointInPolygonQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.ParsingException;
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.geo.GeoUtils;
|
||||
|
@ -56,6 +58,16 @@ public class GeoPolygonQueryBuilderTests extends AbstractQueryTestCase<GeoPolygo
|
|||
|
||||
@Override
|
||||
protected void doAssertLuceneQuery(GeoPolygonQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException {
|
||||
Version version = context.indexVersionCreated();
|
||||
// norelease update to .before(Version.V_2_2_0 once GeoPointFieldV2 is fully merged
|
||||
if (version.onOrBefore(Version.CURRENT)) {
|
||||
assertLegacyQuery(queryBuilder, query);
|
||||
} else {
|
||||
assertGeoPointQuery(queryBuilder, query);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertLegacyQuery(GeoPolygonQueryBuilder queryBuilder, Query query) {
|
||||
assertThat(query, instanceOf(GeoPolygonQuery.class));
|
||||
GeoPolygonQuery geoQuery = (GeoPolygonQuery) query;
|
||||
assertThat(geoQuery.fieldName(), equalTo(queryBuilder.fieldName()));
|
||||
|
@ -76,6 +88,24 @@ public class GeoPolygonQueryBuilderTests extends AbstractQueryTestCase<GeoPolygo
|
|||
}
|
||||
}
|
||||
|
||||
private void assertGeoPointQuery(GeoPolygonQueryBuilder queryBuilder, Query query) {
|
||||
assertThat(query, instanceOf(GeoPointInPolygonQuery.class));
|
||||
GeoPointInPolygonQuery geoQuery = (GeoPointInPolygonQuery) query;
|
||||
assertThat(geoQuery.getField(), equalTo(queryBuilder.fieldName()));
|
||||
List<GeoPoint> queryBuilderPoints = queryBuilder.points();
|
||||
double[] lats = geoQuery.getLats();
|
||||
double[] lons = geoQuery.getLons();
|
||||
assertThat(lats.length, equalTo(queryBuilderPoints.size()));
|
||||
assertThat(lons.length, equalTo(queryBuilderPoints.size()));
|
||||
for (int i=0; i < queryBuilderPoints.size(); ++i) {
|
||||
final GeoPoint queryBuilderPoint = queryBuilderPoints.get(i);
|
||||
final GeoPoint pointCopy = new GeoPoint(queryBuilderPoint);
|
||||
GeoUtils.normalizePoint(pointCopy);
|
||||
assertThat(lats[i], closeTo(pointCopy.getLat(), 1E-5D));
|
||||
assertThat(lons[i], closeTo(pointCopy.getLon(), 1E-5D));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden here to ensure the test is only run if at least one type is
|
||||
* present in the mappings. Geo queries do not execute if the field is not
|
||||
|
@ -267,15 +297,35 @@ public class GeoPolygonQueryBuilderTests extends AbstractQueryTestCase<GeoPolygo
|
|||
}
|
||||
|
||||
private void assertGeoPolygonQuery(String query) throws IOException {
|
||||
Query parsedQuery = parseQuery(query).toQuery(createShardContext());
|
||||
GeoPolygonQuery filter = (GeoPolygonQuery) parsedQuery;
|
||||
assertThat(filter.fieldName(), equalTo(GEO_POINT_FIELD_NAME));
|
||||
assertThat(filter.points().length, equalTo(4));
|
||||
assertThat(filter.points()[0].lat(), closeTo(40, 0.00001));
|
||||
assertThat(filter.points()[0].lon(), closeTo(-70, 0.00001));
|
||||
assertThat(filter.points()[1].lat(), closeTo(30, 0.00001));
|
||||
assertThat(filter.points()[1].lon(), closeTo(-80, 0.00001));
|
||||
assertThat(filter.points()[2].lat(), closeTo(20, 0.00001));
|
||||
assertThat(filter.points()[2].lon(), closeTo(-90, 0.00001));
|
||||
QueryShardContext context = createShardContext();
|
||||
Version version = context.indexVersionCreated();
|
||||
Query parsedQuery = parseQuery(query).toQuery(context);
|
||||
// norelease update to .before(Version.V_2_2_0 once GeoPointFieldV2 is fully merged
|
||||
if (version.onOrBefore(Version.CURRENT)) {
|
||||
GeoPolygonQuery filter = (GeoPolygonQuery) parsedQuery;
|
||||
assertThat(filter.fieldName(), equalTo(GEO_POINT_FIELD_NAME));
|
||||
assertThat(filter.points().length, equalTo(4));
|
||||
assertThat(filter.points()[0].lat(), closeTo(40, 0.00001));
|
||||
assertThat(filter.points()[0].lon(), closeTo(-70, 0.00001));
|
||||
assertThat(filter.points()[1].lat(), closeTo(30, 0.00001));
|
||||
assertThat(filter.points()[1].lon(), closeTo(-80, 0.00001));
|
||||
assertThat(filter.points()[2].lat(), closeTo(20, 0.00001));
|
||||
assertThat(filter.points()[2].lon(), closeTo(-90, 0.00001));
|
||||
} else {
|
||||
GeoPointInPolygonQuery q = (GeoPointInPolygonQuery) parsedQuery;
|
||||
assertThat(q.getField(), equalTo(GEO_POINT_FIELD_NAME));
|
||||
final double[] lats = q.getLats();
|
||||
final double[] lons = q.getLons();
|
||||
assertThat(lats.length, equalTo(4));
|
||||
assertThat(lons.length, equalTo(4));
|
||||
assertThat(lats[0], closeTo(40, 1E-5));
|
||||
assertThat(lons[0], closeTo(-70, 1E-5));
|
||||
assertThat(lats[1], closeTo(30, 1E-5));
|
||||
assertThat(lons[1], closeTo(-80, 1E-5));
|
||||
assertThat(lats[2], closeTo(20, 1E-5));
|
||||
assertThat(lons[2], closeTo(-90, 1E-5));
|
||||
assertThat(lats[3], equalTo(lats[0]));
|
||||
assertThat(lons[3], equalTo(lons[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue