mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-26 14:54:56 +00:00
Don't assume fixed earth diameter in the geo-distance bounding box optimization.
We switched to Lucene's SloppyMath way of computing an approximate value of the eath diameter given a latitude in order to compute distances, yet the bounding box optimization of the geo distance filter still assumed a constant earth diameter, equal to the average. Close #6008
This commit is contained in:
parent
6feeac98c8
commit
c306d8c5f5
@ -140,7 +140,8 @@ public enum GeoDistance {
|
||||
|
||||
public static DistanceBoundingCheck distanceBoundingCheck(double sourceLatitude, double sourceLongitude, double distance, DistanceUnit unit) {
|
||||
// angular distance in radians on a great circle
|
||||
double radDist = distance / unit.getEarthRadius();
|
||||
// assume worst-case: use the minor axis
|
||||
double radDist = unit.toMeters(distance) / GeoUtils.EARTH_SEMI_MINOR_AXIS;
|
||||
|
||||
double radLat = Math.toRadians(sourceLatitude);
|
||||
double radLon = Math.toRadians(sourceLongitude);
|
||||
|
@ -52,7 +52,7 @@ public class GeoDistanceFilter extends Filter {
|
||||
private final IndexGeoPointFieldData indexFieldData;
|
||||
|
||||
private final GeoDistance.FixedSourceDistance fixedSourceDistance;
|
||||
private GeoDistance.DistanceBoundingCheck distanceBoundingCheck;
|
||||
private final GeoDistance.DistanceBoundingCheck distanceBoundingCheck;
|
||||
private final Filter boundingBoxFilter;
|
||||
|
||||
public GeoDistanceFilter(double lat, double lon, double distance, GeoDistance geoDistance, IndexGeoPointFieldData indexFieldData, GeoPointFieldMapper mapper,
|
||||
@ -64,6 +64,7 @@ public class GeoDistanceFilter extends Filter {
|
||||
this.indexFieldData = indexFieldData;
|
||||
|
||||
this.fixedSourceDistance = geoDistance.fixedSourceDistance(lat, lon, DistanceUnit.DEFAULT);
|
||||
GeoDistance.DistanceBoundingCheck distanceBoundingCheck = null;
|
||||
if (optimizeBbox != null && !"none".equals(optimizeBbox)) {
|
||||
distanceBoundingCheck = GeoDistance.distanceBoundingCheck(lat, lon, distance, DistanceUnit.DEFAULT);
|
||||
if ("memory".equals(optimizeBbox)) {
|
||||
@ -78,6 +79,7 @@ public class GeoDistanceFilter extends Filter {
|
||||
distanceBoundingCheck = GeoDistance.ALWAYS_INSTANCE;
|
||||
boundingBoxFilter = null;
|
||||
}
|
||||
this.distanceBoundingCheck = distanceBoundingCheck;
|
||||
}
|
||||
|
||||
public double lat() {
|
||||
|
@ -19,7 +19,9 @@
|
||||
|
||||
package org.elasticsearch.search.geo;
|
||||
|
||||
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.common.geo.GeoDistance;
|
||||
import org.elasticsearch.common.geo.GeoHashUtils;
|
||||
import org.elasticsearch.common.unit.DistanceUnit;
|
||||
@ -36,6 +38,9 @@ import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.index.query.FilterBuilders.*;
|
||||
@ -633,4 +638,44 @@ public class GeoDistanceTests extends ElasticsearchIntegrationTest {
|
||||
assertHitCount(result, 1);
|
||||
}
|
||||
|
||||
private double randomLon() {
|
||||
return randomDouble() * 360 - 180;
|
||||
}
|
||||
|
||||
private double randomLat() {
|
||||
return randomDouble() * 180 - 90;
|
||||
}
|
||||
|
||||
public void testDuelOptimizations() throws Exception {
|
||||
assertAcked(prepareCreate("index").addMapping("type", "location", "type=geo_point,lat_lon=true"));
|
||||
final int numDocs = scaledRandomIntBetween(3000, 10000);
|
||||
List<IndexRequestBuilder> docs = new ArrayList<>();
|
||||
for (int i = 0; i < numDocs; ++i) {
|
||||
docs.add(client().prepareIndex("index", "type").setSource(jsonBuilder().startObject().startObject("location").field("lat", randomLat()).field("lon", randomLon()).endObject().endObject()));
|
||||
}
|
||||
indexRandom(true, docs);
|
||||
ensureSearchable();
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
final double originLat = randomLat();
|
||||
final double originLon = randomLon();
|
||||
final String distance = DistanceUnit.KILOMETERS.toString(randomInt(10000));
|
||||
for (GeoDistance geoDistance : Arrays.asList(GeoDistance.ARC, GeoDistance.SLOPPY_ARC)) {
|
||||
logger.info("Now testing GeoDistance={}, distance={}, origin=({}, {})", geoDistance, distance, originLat, originLon);
|
||||
long matches = -1;
|
||||
for (String optimizeBbox : Arrays.asList("none", "memory", "indexed")) {
|
||||
SearchResponse resp = client().prepareSearch("index").setSearchType(SearchType.COUNT).setQuery(QueryBuilders.constantScoreQuery(
|
||||
FilterBuilders.geoDistanceFilter("location").point(originLat, originLon).distance(distance).geoDistance(geoDistance).optimizeBbox(optimizeBbox))).execute().actionGet();
|
||||
assertSearchResponse(resp);
|
||||
logger.info("{} -> {} hits", optimizeBbox, resp.getHits().totalHits());
|
||||
if (matches < 0) {
|
||||
matches = resp.getHits().totalHits();
|
||||
} else {
|
||||
assertEquals(matches, resp.getHits().totalHits());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user