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:
Nicholas Knize 2015-11-04 16:29:10 -06:00
parent 10f9de4d5f
commit 86ae08fa88
9 changed files with 274 additions and 81 deletions

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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));
}
}
}

View File

@ -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));
}
}
}

View File

@ -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

View File

@ -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]));
}
}
}