Allow to filter geo bounding box or distance based on indexed lat lon, closes #1334.
This commit is contained in:
parent
819653cdba
commit
e2b1cb1640
|
@ -107,23 +107,40 @@ public class GeoDistanceSearchBenchmark {
|
|||
System.err.println("--> Warming up (ARC) - optimize_bbox");
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i = 0; i < NUM_WARM; i++) {
|
||||
run(client, GeoDistance.ARC, true);
|
||||
run(client, GeoDistance.ARC, "memory");
|
||||
}
|
||||
long totalTime = System.currentTimeMillis() - start;
|
||||
System.err.println("--> Warmup (ARC) - optimize_bbox " + (totalTime / NUM_WARM) + "ms");
|
||||
System.err.println("--> Warmup (ARC) - optimize_bbox (memory) " + (totalTime / NUM_WARM) + "ms");
|
||||
|
||||
System.err.println("--> Perf (ARC) - optimize_bbox");
|
||||
System.err.println("--> Perf (ARC) - optimize_bbox (memory)");
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < NUM_RUNS; i++) {
|
||||
run(client, GeoDistance.ARC, true);
|
||||
run(client, GeoDistance.ARC, "memory");
|
||||
}
|
||||
totalTime = System.currentTimeMillis() - start;
|
||||
System.err.println("--> Perf (ARC) - optimize_bbox " + (totalTime / NUM_RUNS) + "ms");
|
||||
|
||||
System.err.println("--> Warming up (ARC) - optimize_bbox (indexed)");
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < NUM_WARM; i++) {
|
||||
run(client, GeoDistance.ARC, "indexed");
|
||||
}
|
||||
totalTime = System.currentTimeMillis() - start;
|
||||
System.err.println("--> Warmup (ARC) - optimize_bbox (indexed) " + (totalTime / NUM_WARM) + "ms");
|
||||
|
||||
System.err.println("--> Perf (ARC) - optimize_bbox (indexed)");
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < NUM_RUNS; i++) {
|
||||
run(client, GeoDistance.ARC, "indexed");
|
||||
}
|
||||
totalTime = System.currentTimeMillis() - start;
|
||||
System.err.println("--> Perf (ARC) - optimize_bbox (indexed) " + (totalTime / NUM_RUNS) + "ms");
|
||||
|
||||
|
||||
System.err.println("--> Warming up (ARC) - no optimize_bbox");
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < NUM_WARM; i++) {
|
||||
run(client, GeoDistance.ARC, false);
|
||||
run(client, GeoDistance.ARC, "none");
|
||||
}
|
||||
totalTime = System.currentTimeMillis() - start;
|
||||
System.err.println("--> Warmup (ARC) - no optimize_bbox " + (totalTime / NUM_WARM) + "ms");
|
||||
|
@ -131,7 +148,7 @@ public class GeoDistanceSearchBenchmark {
|
|||
System.err.println("--> Perf (ARC) - no optimize_bbox");
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < NUM_RUNS; i++) {
|
||||
run(client, GeoDistance.ARC, false);
|
||||
run(client, GeoDistance.ARC, "none");
|
||||
}
|
||||
totalTime = System.currentTimeMillis() - start;
|
||||
System.err.println("--> Perf (ARC) - no optimize_bbox " + (totalTime / NUM_RUNS) + "ms");
|
||||
|
@ -139,7 +156,7 @@ public class GeoDistanceSearchBenchmark {
|
|||
System.err.println("--> Warming up (PLANE)");
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < NUM_WARM; i++) {
|
||||
run(client, GeoDistance.PLANE, true);
|
||||
run(client, GeoDistance.PLANE, "memory");
|
||||
}
|
||||
totalTime = System.currentTimeMillis() - start;
|
||||
System.err.println("--> Warmup (PLANE) " + (totalTime / NUM_WARM) + "ms");
|
||||
|
@ -147,7 +164,7 @@ public class GeoDistanceSearchBenchmark {
|
|||
System.err.println("--> Perf (PLANE)");
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < NUM_RUNS; i++) {
|
||||
run(client, GeoDistance.PLANE, true);
|
||||
run(client, GeoDistance.PLANE, "memory");
|
||||
}
|
||||
totalTime = System.currentTimeMillis() - start;
|
||||
System.err.println("--> Perf (PLANE) " + (totalTime / NUM_RUNS) + "ms");
|
||||
|
@ -155,7 +172,7 @@ public class GeoDistanceSearchBenchmark {
|
|||
node.close();
|
||||
}
|
||||
|
||||
public static void run(Client client, GeoDistance geoDistance, boolean optimizeBbox) {
|
||||
public static void run(Client client, GeoDistance geoDistance, String optimizeBbox) {
|
||||
client.prepareSearch() // from NY
|
||||
.setSearchType(SearchType.COUNT)
|
||||
.setQuery(filteredQuery(matchAllQuery(), geoDistanceFilter("location")
|
||||
|
|
|
@ -164,6 +164,10 @@ public class DoubleFieldMapper extends NumberFieldMapper<Double> {
|
|||
includeLower, includeUpper);
|
||||
}
|
||||
|
||||
public Filter rangeFilter(Double lowerTerm, Double upperTerm, boolean includeLower, boolean includeUpper) {
|
||||
return NumericRangeFilter.newDoubleRange(names.indexName(), precisionStep, lowerTerm, upperTerm, includeLower, includeUpper);
|
||||
}
|
||||
|
||||
@Override public Filter rangeFilter(FieldDataCache fieldDataCache, String lowerTerm, String upperTerm, boolean includeLower, boolean includeUpper) {
|
||||
return NumericRangeFieldDataFilter.newDoubleRange(fieldDataCache, names.indexName(),
|
||||
lowerTerm == null ? null : Double.parseDouble(lowerTerm),
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.elasticsearch.index.mapper.MergeMappingException;
|
|||
import org.elasticsearch.index.mapper.ObjectMapperListener;
|
||||
import org.elasticsearch.index.mapper.ParseContext;
|
||||
import org.elasticsearch.index.mapper.core.AbstractFieldMapper;
|
||||
import org.elasticsearch.index.mapper.core.DoubleFieldMapper;
|
||||
import org.elasticsearch.index.mapper.core.NumberFieldMapper;
|
||||
import org.elasticsearch.index.mapper.core.StringFieldMapper;
|
||||
import org.elasticsearch.index.mapper.object.ArrayValueMapperParser;
|
||||
|
@ -147,8 +148,8 @@ public class GeoPointFieldMapper implements Mapper, ArrayValueMapperParser {
|
|||
.index(Field.Index.NOT_ANALYZED).omitNorms(true).omitTermFreqAndPositions(true).includeInAll(false).store(store).build(context);
|
||||
|
||||
|
||||
NumberFieldMapper latMapper = null;
|
||||
NumberFieldMapper lonMapper = null;
|
||||
DoubleFieldMapper latMapper = null;
|
||||
DoubleFieldMapper lonMapper = null;
|
||||
|
||||
context.path().add(name);
|
||||
if (enableLatLon) {
|
||||
|
@ -158,8 +159,8 @@ public class GeoPointFieldMapper implements Mapper, ArrayValueMapperParser {
|
|||
latMapperBuilder.precisionStep(precisionStep);
|
||||
lonMapperBuilder.precisionStep(precisionStep);
|
||||
}
|
||||
latMapper = (NumberFieldMapper) latMapperBuilder.includeInAll(false).store(store).build(context);
|
||||
lonMapper = (NumberFieldMapper) lonMapperBuilder.includeInAll(false).store(store).build(context);
|
||||
latMapper = (DoubleFieldMapper) latMapperBuilder.includeInAll(false).store(store).build(context);
|
||||
lonMapper = (DoubleFieldMapper) lonMapperBuilder.includeInAll(false).store(store).build(context);
|
||||
}
|
||||
StringFieldMapper geohashMapper = null;
|
||||
if (enableGeoHash) {
|
||||
|
@ -226,13 +227,13 @@ public class GeoPointFieldMapper implements Mapper, ArrayValueMapperParser {
|
|||
|
||||
private final int precision;
|
||||
|
||||
private final NumberFieldMapper latMapper;
|
||||
private final DoubleFieldMapper latMapper;
|
||||
|
||||
private final NumberFieldMapper lonMapper;
|
||||
private final DoubleFieldMapper lonMapper;
|
||||
|
||||
private final StringFieldMapper geohashMapper;
|
||||
|
||||
private final StringFieldMapper geoStringMapper;
|
||||
private final GeoStringFieldMapper geoStringMapper;
|
||||
|
||||
private final boolean validateLon;
|
||||
private final boolean validateLat;
|
||||
|
@ -241,7 +242,7 @@ public class GeoPointFieldMapper implements Mapper, ArrayValueMapperParser {
|
|||
private final boolean normalizeLat;
|
||||
|
||||
public GeoPointFieldMapper(String name, ContentPath.Type pathType, boolean enableLatLon, boolean enableGeoHash, Integer precisionStep, int precision,
|
||||
NumberFieldMapper latMapper, NumberFieldMapper lonMapper, StringFieldMapper geohashMapper, StringFieldMapper geoStringMapper,
|
||||
DoubleFieldMapper latMapper, DoubleFieldMapper lonMapper, StringFieldMapper geohashMapper, GeoStringFieldMapper geoStringMapper,
|
||||
boolean validateLon, boolean validateLat,
|
||||
boolean normalizeLon, boolean normalizeLat) {
|
||||
this.name = name;
|
||||
|
@ -256,6 +257,8 @@ public class GeoPointFieldMapper implements Mapper, ArrayValueMapperParser {
|
|||
this.geoStringMapper = geoStringMapper;
|
||||
this.geohashMapper = geohashMapper;
|
||||
|
||||
this.geoStringMapper.geoMapper = this;
|
||||
|
||||
this.validateLat = validateLat;
|
||||
this.validateLon = validateLon;
|
||||
|
||||
|
@ -267,6 +270,18 @@ public class GeoPointFieldMapper implements Mapper, ArrayValueMapperParser {
|
|||
return this.name;
|
||||
}
|
||||
|
||||
public DoubleFieldMapper latMapper() {
|
||||
return latMapper;
|
||||
}
|
||||
|
||||
public DoubleFieldMapper lonMapper() {
|
||||
return lonMapper;
|
||||
}
|
||||
|
||||
public boolean isEnableLatLon() {
|
||||
return enableLatLon;
|
||||
}
|
||||
|
||||
@Override public void parse(ParseContext context) throws IOException {
|
||||
ContentPath.Type origPathType = context.path().pathType();
|
||||
context.path().pathType(pathType);
|
||||
|
@ -536,6 +551,8 @@ public class GeoPointFieldMapper implements Mapper, ArrayValueMapperParser {
|
|||
}
|
||||
}
|
||||
|
||||
GeoPointFieldMapper geoMapper;
|
||||
|
||||
public GeoStringFieldMapper(Names names, Field.Index index, Field.Store store, Field.TermVector termVector, float boost, boolean omitNorms, boolean omitTermFreqAndPositions, String nullValue, NamedAnalyzer indexAnalyzer, NamedAnalyzer searchAnalyzer) {
|
||||
super(names, index, store, termVector, boost, omitNorms, omitTermFreqAndPositions, nullValue, indexAnalyzer, searchAnalyzer);
|
||||
}
|
||||
|
@ -543,5 +560,9 @@ public class GeoPointFieldMapper implements Mapper, ArrayValueMapperParser {
|
|||
@Override public FieldDataType fieldDataType() {
|
||||
return GeoPointFieldDataType.TYPE;
|
||||
}
|
||||
|
||||
public GeoPointFieldMapper geoMapper() {
|
||||
return geoMapper;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ public class GeoBoundingBoxFilterBuilder extends BaseFilterBuilder {
|
|||
|
||||
private String filterName;
|
||||
|
||||
private String type;
|
||||
|
||||
public GeoBoundingBoxFilterBuilder(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
@ -105,6 +107,15 @@ public class GeoBoundingBoxFilterBuilder extends BaseFilterBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of executing of the geo bounding box. Can be either `memory` or `indexed`. Defaults
|
||||
* to `memory`.
|
||||
*/
|
||||
public GeoBoundingBoxFilterBuilder type(String type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(GeoBoundingBoxFilterParser.NAME);
|
||||
|
||||
|
@ -135,6 +146,9 @@ public class GeoBoundingBoxFilterBuilder extends BaseFilterBuilder {
|
|||
if (cacheKey != null) {
|
||||
builder.field("_cache_key", cacheKey);
|
||||
}
|
||||
if (type != null) {
|
||||
builder.field("type", type);
|
||||
}
|
||||
|
||||
builder.endObject();
|
||||
}
|
||||
|
|
|
@ -25,11 +25,11 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
|||
import org.elasticsearch.index.cache.filter.support.CacheKeyFilter;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.mapper.MapperService;
|
||||
import org.elasticsearch.index.mapper.geo.GeoPointFieldDataType;
|
||||
import org.elasticsearch.index.mapper.geo.GeoPointFieldMapper;
|
||||
import org.elasticsearch.index.search.geo.GeoBoundingBoxFilter;
|
||||
import org.elasticsearch.index.search.geo.GeoHashUtils;
|
||||
import org.elasticsearch.index.search.geo.GeoUtils;
|
||||
import org.elasticsearch.index.search.geo.InMemoryGeoBoundingBoxFilter;
|
||||
import org.elasticsearch.index.search.geo.IndexedGeoBoundingBoxFilter;
|
||||
import org.elasticsearch.index.search.geo.Point;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -64,6 +64,9 @@ public class GeoBoundingBoxFilterParser implements FilterParser {
|
|||
XContentParser.Token token;
|
||||
boolean normalizeLon = true;
|
||||
boolean normalizeLat = true;
|
||||
|
||||
String type = "memory";
|
||||
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
|
@ -151,6 +154,8 @@ public class GeoBoundingBoxFilterParser implements FilterParser {
|
|||
} else if ("normalize".equals(currentFieldName)) {
|
||||
normalizeLat = parser.booleanValue();
|
||||
normalizeLon = parser.booleanValue();
|
||||
} else if ("type".equals(currentFieldName)) {
|
||||
type = parser.text();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -170,13 +175,22 @@ public class GeoBoundingBoxFilterParser implements FilterParser {
|
|||
if (mapper == null) {
|
||||
throw new QueryParsingException(parseContext.index(), "failed to find geo_point field [" + fieldName + "]");
|
||||
}
|
||||
if (mapper.fieldDataType() != GeoPointFieldDataType.TYPE) {
|
||||
if (!(mapper instanceof GeoPointFieldMapper.GeoStringFieldMapper)) {
|
||||
throw new QueryParsingException(parseContext.index(), "field [" + fieldName + "] is not a geo_point field");
|
||||
}
|
||||
GeoPointFieldMapper geoMapper = ((GeoPointFieldMapper.GeoStringFieldMapper) mapper).geoMapper();
|
||||
|
||||
fieldName = mapper.names().indexName();
|
||||
|
||||
Filter filter;
|
||||
if ("indexed".equals(type)) {
|
||||
filter = IndexedGeoBoundingBoxFilter.create(topLeft, bottomRight, geoMapper);
|
||||
} else if ("memory".equals(type)) {
|
||||
filter = new InMemoryGeoBoundingBoxFilter(topLeft, bottomRight, fieldName, parseContext.indexCache().fieldData());
|
||||
} else {
|
||||
throw new QueryParsingException(parseContext.index(), "geo bounding box type [" + type + "] not supported, either 'indexed' or 'memory' are allowed");
|
||||
}
|
||||
|
||||
Filter filter = new GeoBoundingBoxFilter(topLeft, bottomRight, fieldName, parseContext.indexCache().fieldData());
|
||||
if (cache) {
|
||||
filter = parseContext.cacheFilter(filter, cacheKey);
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ public class GeoDistanceFilterBuilder extends BaseFilterBuilder {
|
|||
|
||||
private GeoDistance geoDistance;
|
||||
|
||||
private Boolean optimizeBbox;
|
||||
private String optimizeBbox;
|
||||
|
||||
private Boolean cache;
|
||||
private String cacheKey;
|
||||
|
@ -89,7 +89,7 @@ public class GeoDistanceFilterBuilder extends BaseFilterBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public GeoDistanceFilterBuilder optimizeBbox(boolean optimizeBbox) {
|
||||
public GeoDistanceFilterBuilder optimizeBbox(String optimizeBbox) {
|
||||
this.optimizeBbox = optimizeBbox;
|
||||
return this;
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ public class GeoDistanceFilterBuilder extends BaseFilterBuilder {
|
|||
builder.field("distance_type", geoDistance.name().toLowerCase());
|
||||
}
|
||||
if (optimizeBbox != null) {
|
||||
builder.field("optimize_bbox", optimizeBbox.booleanValue());
|
||||
builder.field("optimize_bbox", optimizeBbox);
|
||||
}
|
||||
if (filterName != null) {
|
||||
builder.field("_name", filterName);
|
||||
|
|
|
@ -74,7 +74,7 @@ public class GeoDistanceFilterParser implements FilterParser {
|
|||
Object vDistance = null;
|
||||
DistanceUnit unit = DistanceUnit.KILOMETERS; // default unit
|
||||
GeoDistance geoDistance = GeoDistance.ARC;
|
||||
boolean optimizeBbox = true;
|
||||
String optimizeBbox = "memory";
|
||||
boolean normalizeLon = true;
|
||||
boolean normalizeLat = true;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
|
@ -137,7 +137,7 @@ public class GeoDistanceFilterParser implements FilterParser {
|
|||
} else if ("_cache_key".equals(currentFieldName) || "_cacheKey".equals(currentFieldName)) {
|
||||
cacheKey = new CacheKeyFilter.Key(parser.text());
|
||||
} else if ("optimize_bbox".equals(currentFieldName) || "optimizeBbox".equals(currentFieldName)) {
|
||||
optimizeBbox = parser.booleanValue();
|
||||
optimizeBbox = parser.textOrNull();
|
||||
} else if ("normalize".equals(currentFieldName)) {
|
||||
normalizeLat = parser.booleanValue();
|
||||
normalizeLon = parser.booleanValue();
|
||||
|
@ -180,9 +180,10 @@ public class GeoDistanceFilterParser implements FilterParser {
|
|||
if (mapper.fieldDataType() != GeoPointFieldDataType.TYPE) {
|
||||
throw new QueryParsingException(parseContext.index(), "field [" + fieldName + "] is not a geo_point field");
|
||||
}
|
||||
GeoPointFieldMapper geoMapper = ((GeoPointFieldMapper.GeoStringFieldMapper) mapper).geoMapper();
|
||||
fieldName = mapper.names().indexName();
|
||||
|
||||
Filter filter = new GeoDistanceFilter(lat, lon, distance, geoDistance, fieldName, parseContext.indexCache().fieldData(), optimizeBbox);
|
||||
Filter filter = new GeoDistanceFilter(lat, lon, distance, geoDistance, fieldName, geoMapper, parseContext.indexCache().fieldData(), optimizeBbox);
|
||||
if (cache) {
|
||||
filter = parseContext.cacheFilter(filter, cacheKey);
|
||||
}
|
||||
|
|
|
@ -49,6 +49,8 @@ public class GeoDistanceRangeFilterBuilder extends BaseFilterBuilder {
|
|||
|
||||
private String filterName;
|
||||
|
||||
private String optimizeBbox;
|
||||
|
||||
public GeoDistanceRangeFilterBuilder(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
@ -123,6 +125,11 @@ public class GeoDistanceRangeFilterBuilder extends BaseFilterBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public GeoDistanceRangeFilterBuilder optimizeBbox(String optimizeBbox) {
|
||||
this.optimizeBbox = optimizeBbox;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the filter name for the filter that can be used when searching for matched_filters per hit.
|
||||
*/
|
||||
|
@ -158,6 +165,9 @@ public class GeoDistanceRangeFilterBuilder extends BaseFilterBuilder {
|
|||
if (geoDistance != null) {
|
||||
builder.field("distance_type", geoDistance.name().toLowerCase());
|
||||
}
|
||||
if (optimizeBbox != null) {
|
||||
builder.field("optimize_bbox", optimizeBbox);
|
||||
}
|
||||
if (filterName != null) {
|
||||
builder.field("_name", filterName);
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ public class GeoDistanceRangeFilterParser implements FilterParser {
|
|||
boolean includeUpper = true;
|
||||
DistanceUnit unit = DistanceUnit.KILOMETERS; // default unit
|
||||
GeoDistance geoDistance = GeoDistance.ARC;
|
||||
boolean optimizeBbox = true;
|
||||
String optimizeBbox = "memory";
|
||||
boolean normalizeLon = true;
|
||||
boolean normalizeLat = true;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
|
@ -186,7 +186,7 @@ public class GeoDistanceRangeFilterParser implements FilterParser {
|
|||
} else if ("_cache_key".equals(currentFieldName) || "_cacheKey".equals(currentFieldName)) {
|
||||
cacheKey = new CacheKeyFilter.Key(parser.text());
|
||||
} else if ("optimize_bbox".equals(currentFieldName) || "optimizeBbox".equals(currentFieldName)) {
|
||||
optimizeBbox = parser.booleanValue();
|
||||
optimizeBbox = parser.textOrNull();
|
||||
} else if ("normalize".equals(currentFieldName)) {
|
||||
normalizeLat = parser.booleanValue();
|
||||
normalizeLon = parser.booleanValue();
|
||||
|
@ -237,9 +237,10 @@ public class GeoDistanceRangeFilterParser implements FilterParser {
|
|||
if (mapper.fieldDataType() != GeoPointFieldDataType.TYPE) {
|
||||
throw new QueryParsingException(parseContext.index(), "field [" + fieldName + "] is not a geo_point field");
|
||||
}
|
||||
GeoPointFieldMapper geoMapper = ((GeoPointFieldMapper.GeoStringFieldMapper) mapper).geoMapper();
|
||||
fieldName = mapper.names().indexName();
|
||||
|
||||
Filter filter = new GeoDistanceRangeFilter(lat, lon, from, to, includeLower, includeUpper, geoDistance, fieldName, parseContext.indexCache().fieldData(), optimizeBbox);
|
||||
Filter filter = new GeoDistanceRangeFilter(lat, lon, from, to, includeLower, includeUpper, geoDistance, fieldName, geoMapper, parseContext.indexCache().fieldData(), optimizeBbox);
|
||||
if (cache) {
|
||||
filter = parseContext.cacheFilter(filter, cacheKey);
|
||||
}
|
||||
|
|
|
@ -131,12 +131,12 @@ public enum GeoDistance {
|
|||
maxLon = MAX_LON;
|
||||
}
|
||||
|
||||
Point left = new Point(Math.toDegrees(minLat), Math.toDegrees(minLon));
|
||||
Point right = new Point(Math.toDegrees(maxLat), Math.toDegrees(maxLon));
|
||||
Point topLeft = new Point(Math.toDegrees(maxLat), Math.toDegrees(minLon));
|
||||
Point bottomRight = new Point(Math.toDegrees(minLat), Math.toDegrees(maxLon));
|
||||
if (minLon > maxLon) {
|
||||
return new Meridian180DistanceBoundingCheck(left, right);
|
||||
return new Meridian180DistanceBoundingCheck(topLeft, bottomRight);
|
||||
}
|
||||
return new SimpleDistanceBoundingCheck(left, right);
|
||||
return new SimpleDistanceBoundingCheck(topLeft, bottomRight);
|
||||
}
|
||||
|
||||
public static GeoDistance fromString(String s) {
|
||||
|
@ -158,6 +158,10 @@ public enum GeoDistance {
|
|||
public static interface DistanceBoundingCheck {
|
||||
|
||||
boolean isWithin(double targetLatitude, double targetLongitude);
|
||||
|
||||
Point topLeft();
|
||||
|
||||
Point bottomRight();
|
||||
}
|
||||
|
||||
public static AlwaysDistanceBoundingCheck ALWAYS_INSTANCE = new AlwaysDistanceBoundingCheck();
|
||||
|
@ -166,36 +170,60 @@ public enum GeoDistance {
|
|||
@Override public boolean isWithin(double targetLatitude, double targetLongitude) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public Point topLeft() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public Point bottomRight() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Meridian180DistanceBoundingCheck implements DistanceBoundingCheck {
|
||||
|
||||
private final Point left;
|
||||
private final Point right;
|
||||
private final Point topLeft;
|
||||
private final Point bottomRight;
|
||||
|
||||
public Meridian180DistanceBoundingCheck(Point left, Point right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
public Meridian180DistanceBoundingCheck(Point topLeft, Point bottomRight) {
|
||||
this.topLeft = topLeft;
|
||||
this.bottomRight = bottomRight;
|
||||
}
|
||||
|
||||
@Override public boolean isWithin(double targetLatitude, double targetLongitude) {
|
||||
return (targetLatitude >= left.lat && targetLatitude <= right.lat) &&
|
||||
(targetLongitude >= left.lon || targetLongitude <= right.lon);
|
||||
return (targetLatitude >= bottomRight.lat && targetLatitude <= topLeft.lat) &&
|
||||
(targetLongitude >= topLeft.lon || targetLongitude <= bottomRight.lon);
|
||||
}
|
||||
|
||||
@Override public Point topLeft() {
|
||||
return topLeft;
|
||||
}
|
||||
|
||||
@Override public Point bottomRight() {
|
||||
return bottomRight;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SimpleDistanceBoundingCheck implements DistanceBoundingCheck {
|
||||
private final Point left;
|
||||
private final Point right;
|
||||
private final Point topLeft;
|
||||
private final Point bottomRight;
|
||||
|
||||
public SimpleDistanceBoundingCheck(Point left, Point right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
public SimpleDistanceBoundingCheck(Point topLeft, Point bottomRight) {
|
||||
this.topLeft = topLeft;
|
||||
this.bottomRight = bottomRight;
|
||||
}
|
||||
|
||||
@Override public boolean isWithin(double targetLatitude, double targetLongitude) {
|
||||
return (targetLatitude >= left.lat && targetLatitude <= right.lat) &&
|
||||
(targetLongitude >= left.lon && targetLongitude <= right.lon);
|
||||
return (targetLatitude >= bottomRight.lat && targetLatitude <= topLeft.lat) &&
|
||||
(targetLongitude >= topLeft.lon && targetLongitude <= bottomRight.lon);
|
||||
}
|
||||
|
||||
@Override public Point topLeft() {
|
||||
return topLeft;
|
||||
}
|
||||
|
||||
@Override public Point bottomRight() {
|
||||
return bottomRight;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,16 +22,21 @@ package org.elasticsearch.index.search.geo;
|
|||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.search.DocIdSet;
|
||||
import org.apache.lucene.search.Filter;
|
||||
import org.elasticsearch.ElasticSearchIllegalArgumentException;
|
||||
import org.elasticsearch.common.collect.ImmutableList;
|
||||
import org.elasticsearch.common.lucene.docset.AndDocSet;
|
||||
import org.elasticsearch.common.lucene.docset.DocSet;
|
||||
import org.elasticsearch.common.lucene.docset.DocSets;
|
||||
import org.elasticsearch.common.lucene.docset.GetDocSet;
|
||||
import org.elasticsearch.common.unit.DistanceUnit;
|
||||
import org.elasticsearch.index.cache.field.data.FieldDataCache;
|
||||
import org.elasticsearch.index.mapper.geo.GeoPointFieldData;
|
||||
import org.elasticsearch.index.mapper.geo.GeoPointFieldDataType;
|
||||
import org.elasticsearch.index.mapper.geo.GeoPointFieldMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class GeoDistanceFilter extends Filter {
|
||||
|
||||
|
@ -48,10 +53,11 @@ public class GeoDistanceFilter extends Filter {
|
|||
private final FieldDataCache fieldDataCache;
|
||||
|
||||
private final GeoDistance.FixedSourceDistance fixedSourceDistance;
|
||||
private final GeoDistance.DistanceBoundingCheck distanceBoundingCheck;
|
||||
private GeoDistance.DistanceBoundingCheck distanceBoundingCheck;
|
||||
private final Filter boundingBoxFilter;
|
||||
|
||||
public GeoDistanceFilter(double lat, double lon, double distance, GeoDistance geoDistance, String fieldName, FieldDataCache fieldDataCache,
|
||||
boolean optimizeBbox) {
|
||||
public GeoDistanceFilter(double lat, double lon, double distance, GeoDistance geoDistance, String fieldName, GeoPointFieldMapper mapper, FieldDataCache fieldDataCache,
|
||||
String optimizeBbox) {
|
||||
this.lat = lat;
|
||||
this.lon = lon;
|
||||
this.distance = distance;
|
||||
|
@ -60,7 +66,20 @@ public class GeoDistanceFilter extends Filter {
|
|||
this.fieldDataCache = fieldDataCache;
|
||||
|
||||
this.fixedSourceDistance = geoDistance.fixedSourceDistance(lat, lon, DistanceUnit.MILES);
|
||||
this.distanceBoundingCheck = optimizeBbox ? GeoDistance.distanceBoundingCheck(lat, lon, distance, DistanceUnit.MILES) : GeoDistance.ALWAYS_INSTANCE;
|
||||
if (optimizeBbox != null && !"none".equals(optimizeBbox)) {
|
||||
distanceBoundingCheck = GeoDistance.distanceBoundingCheck(lat, lon, distance, DistanceUnit.MILES);
|
||||
if ("memory".equals(optimizeBbox)) {
|
||||
boundingBoxFilter = null;
|
||||
} else if ("indexed".equals(optimizeBbox)) {
|
||||
boundingBoxFilter = IndexedGeoBoundingBoxFilter.create(distanceBoundingCheck.topLeft(), distanceBoundingCheck.bottomRight(), mapper);
|
||||
distanceBoundingCheck = GeoDistance.ALWAYS_INSTANCE; // fine, we do the bounding box check using the filter
|
||||
} else {
|
||||
throw new ElasticSearchIllegalArgumentException("type [" + optimizeBbox + "] for bounding box optimization not supported");
|
||||
}
|
||||
} else {
|
||||
distanceBoundingCheck = GeoDistance.ALWAYS_INSTANCE;
|
||||
boundingBoxFilter = null;
|
||||
}
|
||||
}
|
||||
|
||||
public double lat() {
|
||||
|
@ -84,8 +103,21 @@ public class GeoDistanceFilter extends Filter {
|
|||
}
|
||||
|
||||
@Override public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
|
||||
DocSet boundingBoxDocSet = null;
|
||||
if (boundingBoxFilter != null) {
|
||||
DocIdSet docIdSet = boundingBoxFilter.getDocIdSet(reader);
|
||||
if (docIdSet == null) {
|
||||
return null;
|
||||
}
|
||||
boundingBoxDocSet = DocSets.convert(reader, docIdSet);
|
||||
}
|
||||
final GeoPointFieldData fieldData = (GeoPointFieldData) fieldDataCache.cache(GeoPointFieldDataType.TYPE, reader, fieldName);
|
||||
return new GeoDistanceDocSet(reader.maxDoc(), fieldData, fixedSourceDistance, distanceBoundingCheck, distance);
|
||||
GeoDistanceDocSet distDocSet = new GeoDistanceDocSet(reader.maxDoc(), fieldData, fixedSourceDistance, distanceBoundingCheck, distance);
|
||||
if (boundingBoxDocSet == null) {
|
||||
return distDocSet;
|
||||
} else {
|
||||
return new AndDocSet(ImmutableList.of(boundingBoxDocSet, distDocSet));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -23,11 +23,17 @@ import org.apache.lucene.index.IndexReader;
|
|||
import org.apache.lucene.search.DocIdSet;
|
||||
import org.apache.lucene.search.Filter;
|
||||
import org.apache.lucene.util.NumericUtils;
|
||||
import org.elasticsearch.ElasticSearchIllegalArgumentException;
|
||||
import org.elasticsearch.common.collect.ImmutableList;
|
||||
import org.elasticsearch.common.lucene.docset.AndDocSet;
|
||||
import org.elasticsearch.common.lucene.docset.DocSet;
|
||||
import org.elasticsearch.common.lucene.docset.DocSets;
|
||||
import org.elasticsearch.common.lucene.docset.GetDocSet;
|
||||
import org.elasticsearch.common.unit.DistanceUnit;
|
||||
import org.elasticsearch.index.cache.field.data.FieldDataCache;
|
||||
import org.elasticsearch.index.mapper.geo.GeoPointFieldData;
|
||||
import org.elasticsearch.index.mapper.geo.GeoPointFieldDataType;
|
||||
import org.elasticsearch.index.mapper.geo.GeoPointFieldMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -44,14 +50,15 @@ public class GeoDistanceRangeFilter extends Filter {
|
|||
|
||||
private final GeoDistance geoDistance;
|
||||
private final GeoDistance.FixedSourceDistance fixedSourceDistance;
|
||||
private final GeoDistance.DistanceBoundingCheck distanceBoundingCheck;
|
||||
private GeoDistance.DistanceBoundingCheck distanceBoundingCheck;
|
||||
private final Filter boundingBoxFilter;
|
||||
|
||||
private final String fieldName;
|
||||
|
||||
private final FieldDataCache fieldDataCache;
|
||||
|
||||
public GeoDistanceRangeFilter(double lat, double lon, Double lowerVal, Double upperVal, boolean includeLower, boolean includeUpper, GeoDistance geoDistance, String fieldName, FieldDataCache fieldDataCache,
|
||||
boolean optimizeBbox) {
|
||||
public GeoDistanceRangeFilter(double lat, double lon, Double lowerVal, Double upperVal, boolean includeLower, boolean includeUpper, GeoDistance geoDistance, String fieldName, GeoPointFieldMapper mapper, FieldDataCache fieldDataCache,
|
||||
String optimizeBbox) {
|
||||
this.lat = lat;
|
||||
this.lon = lon;
|
||||
this.geoDistance = geoDistance;
|
||||
|
@ -73,10 +80,23 @@ public class GeoDistanceRangeFilter extends Filter {
|
|||
inclusiveUpperPoint = NumericUtils.sortableLongToDouble(includeUpper ? i : (i - 1L));
|
||||
} else {
|
||||
inclusiveUpperPoint = Double.POSITIVE_INFINITY;
|
||||
optimizeBbox = false;
|
||||
optimizeBbox = null;
|
||||
}
|
||||
|
||||
this.distanceBoundingCheck = optimizeBbox ? GeoDistance.distanceBoundingCheck(lat, lon, inclusiveUpperPoint, DistanceUnit.MILES) : GeoDistance.ALWAYS_INSTANCE;
|
||||
if (optimizeBbox != null && !"none".equals(optimizeBbox)) {
|
||||
distanceBoundingCheck = GeoDistance.distanceBoundingCheck(lat, lon, inclusiveUpperPoint, DistanceUnit.MILES);
|
||||
if ("memory".equals(optimizeBbox)) {
|
||||
boundingBoxFilter = null;
|
||||
} else if ("indexed".equals(optimizeBbox)) {
|
||||
boundingBoxFilter = IndexedGeoBoundingBoxFilter.create(distanceBoundingCheck.topLeft(), distanceBoundingCheck.bottomRight(), mapper);
|
||||
distanceBoundingCheck = GeoDistance.ALWAYS_INSTANCE; // fine, we do the bounding box check using the filter
|
||||
} else {
|
||||
throw new ElasticSearchIllegalArgumentException("type [" + optimizeBbox + "] for bounding box optimization not supported");
|
||||
}
|
||||
} else {
|
||||
distanceBoundingCheck = GeoDistance.ALWAYS_INSTANCE;
|
||||
boundingBoxFilter = null;
|
||||
}
|
||||
}
|
||||
|
||||
public double lat() {
|
||||
|
@ -96,8 +116,21 @@ public class GeoDistanceRangeFilter extends Filter {
|
|||
}
|
||||
|
||||
@Override public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
|
||||
DocSet boundingBoxDocSet = null;
|
||||
if (boundingBoxFilter != null) {
|
||||
DocIdSet docIdSet = boundingBoxFilter.getDocIdSet(reader);
|
||||
if (docIdSet == null) {
|
||||
return null;
|
||||
}
|
||||
boundingBoxDocSet = DocSets.convert(reader, docIdSet);
|
||||
}
|
||||
final GeoPointFieldData fieldData = (GeoPointFieldData) fieldDataCache.cache(GeoPointFieldDataType.TYPE, reader, fieldName);
|
||||
return new GeoDistanceRangeDocSet(reader.maxDoc(), fieldData, fixedSourceDistance, distanceBoundingCheck, inclusiveLowerPoint, inclusiveUpperPoint);
|
||||
GeoDistanceRangeDocSet distDocSet = new GeoDistanceRangeDocSet(reader.maxDoc(), fieldData, fixedSourceDistance, distanceBoundingCheck, inclusiveLowerPoint, inclusiveUpperPoint);
|
||||
if (boundingBoxDocSet == null) {
|
||||
return distDocSet;
|
||||
} else {
|
||||
return new AndDocSet(ImmutableList.of(boundingBoxDocSet, distDocSet));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -32,7 +32,7 @@ import java.io.IOException;
|
|||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class GeoBoundingBoxFilter extends Filter {
|
||||
public class InMemoryGeoBoundingBoxFilter extends Filter {
|
||||
|
||||
private final Point topLeft;
|
||||
|
||||
|
@ -42,7 +42,7 @@ public class GeoBoundingBoxFilter extends Filter {
|
|||
|
||||
private final FieldDataCache fieldDataCache;
|
||||
|
||||
public GeoBoundingBoxFilter(Point topLeft, Point bottomRight, String fieldName, FieldDataCache fieldDataCache) {
|
||||
public InMemoryGeoBoundingBoxFilter(Point topLeft, Point bottomRight, String fieldName, FieldDataCache fieldDataCache) {
|
||||
this.topLeft = topLeft;
|
||||
this.bottomRight = bottomRight;
|
||||
this.fieldName = fieldName;
|
||||
|
@ -66,18 +66,18 @@ public class GeoBoundingBoxFilter extends Filter {
|
|||
|
||||
//checks to see if bounding box crosses 180 degrees
|
||||
if (topLeft.lon > bottomRight.lon) {
|
||||
return new LeftGeoBoundingBoxDocSet(reader.maxDoc(), fieldData, topLeft, bottomRight);
|
||||
return new Meridian180GeoBoundingBoxDocSet(reader.maxDoc(), fieldData, topLeft, bottomRight);
|
||||
} else {
|
||||
return new RightGeoBoundingBoxDocSet(reader.maxDoc(), fieldData, topLeft, bottomRight);
|
||||
return new GeoBoundingBoxDocSet(reader.maxDoc(), fieldData, topLeft, bottomRight);
|
||||
}
|
||||
}
|
||||
|
||||
public static class LeftGeoBoundingBoxDocSet extends GetDocSet {
|
||||
public static class Meridian180GeoBoundingBoxDocSet extends GetDocSet {
|
||||
private final GeoPointFieldData fieldData;
|
||||
private final Point topLeft;
|
||||
private final Point bottomRight;
|
||||
|
||||
public LeftGeoBoundingBoxDocSet(int maxDoc, GeoPointFieldData fieldData, Point topLeft, Point bottomRight) {
|
||||
public Meridian180GeoBoundingBoxDocSet(int maxDoc, GeoPointFieldData fieldData, Point topLeft, Point bottomRight) {
|
||||
super(maxDoc);
|
||||
this.fieldData = fieldData;
|
||||
this.topLeft = topLeft;
|
||||
|
@ -120,12 +120,12 @@ public class GeoBoundingBoxFilter extends Filter {
|
|||
}
|
||||
}
|
||||
|
||||
public static class RightGeoBoundingBoxDocSet extends GetDocSet {
|
||||
public static class GeoBoundingBoxDocSet extends GetDocSet {
|
||||
private final GeoPointFieldData fieldData;
|
||||
private final Point topLeft;
|
||||
private final Point bottomRight;
|
||||
|
||||
public RightGeoBoundingBoxDocSet(int maxDoc, GeoPointFieldData fieldData, Point topLeft, Point bottomRight) {
|
||||
public GeoBoundingBoxDocSet(int maxDoc, GeoPointFieldData fieldData, Point topLeft, Point bottomRight) {
|
||||
super(maxDoc);
|
||||
this.fieldData = fieldData;
|
||||
this.topLeft = topLeft;
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Licensed to Elastic Search and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. Elastic Search licenses this
|
||||
* file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.index.search.geo;
|
||||
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.search.DocIdSet;
|
||||
import org.apache.lucene.search.Filter;
|
||||
import org.apache.lucene.util.OpenBitSet;
|
||||
import org.elasticsearch.ElasticSearchIllegalArgumentException;
|
||||
import org.elasticsearch.index.mapper.geo.GeoPointFieldMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class IndexedGeoBoundingBoxFilter {
|
||||
|
||||
public static Filter create(Point topLeft, Point bottomRight, GeoPointFieldMapper fieldMapper) {
|
||||
if (!fieldMapper.isEnableLatLon()) {
|
||||
throw new ElasticSearchIllegalArgumentException("lat/lon is not enabled (indexed) for field [" + fieldMapper.name() + "], can't use indexed filter on it");
|
||||
}
|
||||
//checks to see if bounding box crosses 180 degrees
|
||||
if (topLeft.lon > bottomRight.lon) {
|
||||
return new LeftGeoBoundingBoxFilter(topLeft, bottomRight, fieldMapper);
|
||||
} else {
|
||||
return new RightGeoBoundingBoxFilter(topLeft, bottomRight, fieldMapper);
|
||||
}
|
||||
}
|
||||
|
||||
static class LeftGeoBoundingBoxFilter extends Filter {
|
||||
|
||||
final Filter lonFilter1;
|
||||
final Filter lonFilter2;
|
||||
final Filter latFilter;
|
||||
|
||||
public LeftGeoBoundingBoxFilter(Point topLeft, Point bottomRight, GeoPointFieldMapper fieldMapper) {
|
||||
lonFilter1 = fieldMapper.lonMapper().rangeFilter(null, bottomRight.lon, true, true);
|
||||
lonFilter2 = fieldMapper.lonMapper().rangeFilter(topLeft.lon, null, true, true);
|
||||
latFilter = fieldMapper.latMapper().rangeFilter(bottomRight.lat, topLeft.lat, true, true);
|
||||
}
|
||||
|
||||
@Override public OpenBitSet getDocIdSet(IndexReader reader) throws IOException {
|
||||
OpenBitSet main;
|
||||
DocIdSet set = lonFilter1.getDocIdSet(reader);
|
||||
if (set == null || set == DocIdSet.EMPTY_DOCIDSET) {
|
||||
main = null;
|
||||
} else {
|
||||
main = (OpenBitSet) set;
|
||||
}
|
||||
|
||||
set = lonFilter2.getDocIdSet(reader);
|
||||
if (set == null || set == DocIdSet.EMPTY_DOCIDSET) {
|
||||
if (main == null) {
|
||||
return null;
|
||||
} else {
|
||||
// nothing to do here, we remain with the main one
|
||||
}
|
||||
} else {
|
||||
if (main == null) {
|
||||
main = (OpenBitSet) set;
|
||||
} else {
|
||||
main.or((OpenBitSet) set);
|
||||
}
|
||||
}
|
||||
|
||||
set = latFilter.getDocIdSet(reader);
|
||||
if (set == null || set == DocIdSet.EMPTY_DOCIDSET) {
|
||||
return null;
|
||||
}
|
||||
main.and((OpenBitSet) set);
|
||||
return main;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
LeftGeoBoundingBoxFilter that = (LeftGeoBoundingBoxFilter) o;
|
||||
|
||||
if (latFilter != null ? !latFilter.equals(that.latFilter) : that.latFilter != null) return false;
|
||||
if (lonFilter1 != null ? !lonFilter1.equals(that.lonFilter1) : that.lonFilter1 != null) return false;
|
||||
if (lonFilter2 != null ? !lonFilter2.equals(that.lonFilter2) : that.lonFilter2 != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = lonFilter1 != null ? lonFilter1.hashCode() : 0;
|
||||
result = 31 * result + (lonFilter2 != null ? lonFilter2.hashCode() : 0);
|
||||
result = 31 * result + (latFilter != null ? latFilter.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static class RightGeoBoundingBoxFilter extends Filter {
|
||||
|
||||
final Filter lonFilter;
|
||||
final Filter latFilter;
|
||||
|
||||
public RightGeoBoundingBoxFilter(Point topLeft, Point bottomRight, GeoPointFieldMapper fieldMapper) {
|
||||
lonFilter = fieldMapper.lonMapper().rangeFilter(topLeft.lon, bottomRight.lon, true, true);
|
||||
latFilter = fieldMapper.latMapper().rangeFilter(bottomRight.lat, topLeft.lat, true, true);
|
||||
}
|
||||
|
||||
@Override public OpenBitSet getDocIdSet(IndexReader reader) throws IOException {
|
||||
OpenBitSet main;
|
||||
DocIdSet set = lonFilter.getDocIdSet(reader);
|
||||
if (set == null || set == DocIdSet.EMPTY_DOCIDSET) {
|
||||
return null;
|
||||
}
|
||||
main = (OpenBitSet) set;
|
||||
set = latFilter.getDocIdSet(reader);
|
||||
if (set == null || set == DocIdSet.EMPTY_DOCIDSET) {
|
||||
return null;
|
||||
}
|
||||
main.and((OpenBitSet) set);
|
||||
return main;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
RightGeoBoundingBoxFilter that = (RightGeoBoundingBoxFilter) o;
|
||||
|
||||
if (latFilter != null ? !latFilter.equals(that.latFilter) : that.latFilter != null) return false;
|
||||
if (lonFilter != null ? !lonFilter.equals(that.lonFilter) : that.lonFilter != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = lonFilter != null ? lonFilter.hashCode() : 0;
|
||||
result = 31 * result + (latFilter != null ? latFilter.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -51,9 +51,9 @@ import org.elasticsearch.index.engine.IndexEngineModule;
|
|||
import org.elasticsearch.index.mapper.MapperService;
|
||||
import org.elasticsearch.index.mapper.MapperServiceModule;
|
||||
import org.elasticsearch.index.search.NumericRangeFieldDataFilter;
|
||||
import org.elasticsearch.index.search.geo.GeoBoundingBoxFilter;
|
||||
import org.elasticsearch.index.search.geo.GeoDistanceFilter;
|
||||
import org.elasticsearch.index.search.geo.GeoPolygonFilter;
|
||||
import org.elasticsearch.index.search.geo.InMemoryGeoBoundingBoxFilter;
|
||||
import org.elasticsearch.index.settings.IndexSettingsModule;
|
||||
import org.elasticsearch.index.similarity.SimilarityModule;
|
||||
import org.elasticsearch.indices.query.IndicesQueriesModule;
|
||||
|
@ -1531,7 +1531,7 @@ public class SimpleIndexQueryParserTests {
|
|||
assertThat(parsedQuery.query(), instanceOf(DeletionAwareConstantScoreQuery.class));
|
||||
assertThat(parsedQuery.namedFilters().containsKey("test"), equalTo(true));
|
||||
DeletionAwareConstantScoreQuery constantScoreQuery = (DeletionAwareConstantScoreQuery) parsedQuery.query();
|
||||
GeoBoundingBoxFilter filter = (GeoBoundingBoxFilter) constantScoreQuery.getFilter();
|
||||
InMemoryGeoBoundingBoxFilter filter = (InMemoryGeoBoundingBoxFilter) constantScoreQuery.getFilter();
|
||||
assertThat(filter.fieldName(), equalTo("location"));
|
||||
assertThat(filter.topLeft().lat, closeTo(40, 0.00001));
|
||||
assertThat(filter.topLeft().lon, closeTo(-70, 0.00001));
|
||||
|
@ -1546,7 +1546,7 @@ public class SimpleIndexQueryParserTests {
|
|||
Query parsedQuery = queryParser.parse(query).query();
|
||||
assertThat(parsedQuery, instanceOf(DeletionAwareConstantScoreQuery.class));
|
||||
DeletionAwareConstantScoreQuery constantScoreQuery = (DeletionAwareConstantScoreQuery) parsedQuery;
|
||||
GeoBoundingBoxFilter filter = (GeoBoundingBoxFilter) constantScoreQuery.getFilter();
|
||||
InMemoryGeoBoundingBoxFilter filter = (InMemoryGeoBoundingBoxFilter) constantScoreQuery.getFilter();
|
||||
assertThat(filter.fieldName(), equalTo("location"));
|
||||
assertThat(filter.topLeft().lat, closeTo(40, 0.00001));
|
||||
assertThat(filter.topLeft().lon, closeTo(-70, 0.00001));
|
||||
|
@ -1560,7 +1560,7 @@ public class SimpleIndexQueryParserTests {
|
|||
Query parsedQuery = queryParser.parse(query).query();
|
||||
assertThat(parsedQuery, instanceOf(DeletionAwareConstantScoreQuery.class));
|
||||
DeletionAwareConstantScoreQuery constantScoreQuery = (DeletionAwareConstantScoreQuery) parsedQuery;
|
||||
GeoBoundingBoxFilter filter = (GeoBoundingBoxFilter) constantScoreQuery.getFilter();
|
||||
InMemoryGeoBoundingBoxFilter filter = (InMemoryGeoBoundingBoxFilter) constantScoreQuery.getFilter();
|
||||
assertThat(filter.fieldName(), equalTo("location"));
|
||||
assertThat(filter.topLeft().lat, closeTo(40, 0.00001));
|
||||
assertThat(filter.topLeft().lon, closeTo(-70, 0.00001));
|
||||
|
@ -1574,7 +1574,7 @@ public class SimpleIndexQueryParserTests {
|
|||
Query parsedQuery = queryParser.parse(query).query();
|
||||
assertThat(parsedQuery, instanceOf(DeletionAwareConstantScoreQuery.class));
|
||||
DeletionAwareConstantScoreQuery constantScoreQuery = (DeletionAwareConstantScoreQuery) parsedQuery;
|
||||
GeoBoundingBoxFilter filter = (GeoBoundingBoxFilter) constantScoreQuery.getFilter();
|
||||
InMemoryGeoBoundingBoxFilter filter = (InMemoryGeoBoundingBoxFilter) constantScoreQuery.getFilter();
|
||||
assertThat(filter.fieldName(), equalTo("location"));
|
||||
assertThat(filter.topLeft().lat, closeTo(40, 0.00001));
|
||||
assertThat(filter.topLeft().lon, closeTo(-70, 0.00001));
|
||||
|
@ -1588,7 +1588,7 @@ public class SimpleIndexQueryParserTests {
|
|||
Query parsedQuery = queryParser.parse(query).query();
|
||||
assertThat(parsedQuery, instanceOf(DeletionAwareConstantScoreQuery.class));
|
||||
DeletionAwareConstantScoreQuery constantScoreQuery = (DeletionAwareConstantScoreQuery) parsedQuery;
|
||||
GeoBoundingBoxFilter filter = (GeoBoundingBoxFilter) constantScoreQuery.getFilter();
|
||||
InMemoryGeoBoundingBoxFilter filter = (InMemoryGeoBoundingBoxFilter) constantScoreQuery.getFilter();
|
||||
assertThat(filter.fieldName(), equalTo("location"));
|
||||
assertThat(filter.topLeft().lat, closeTo(40, 0.00001));
|
||||
assertThat(filter.topLeft().lon, closeTo(-70, 0.00001));
|
||||
|
|
|
@ -118,7 +118,15 @@ public class GeoBoundingBoxTests extends AbstractNodesTests {
|
|||
assertThat(searchResponse.hits().getTotalHits(), equalTo(2l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(2));
|
||||
for (SearchHit hit : searchResponse.hits()) {
|
||||
System.err.println("-->" + hit.id());
|
||||
assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("5")));
|
||||
}
|
||||
|
||||
searchResponse = client.prepareSearch() // from NY
|
||||
.setQuery(filteredQuery(matchAllQuery(), geoBoundingBoxFilter("location").topLeft(40.73, -74.1).bottomRight(40.717, -73.99).type("indexed")))
|
||||
.execute().actionGet();
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(2l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(2));
|
||||
for (SearchHit hit : searchResponse.hits()) {
|
||||
assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("5")));
|
||||
}
|
||||
}
|
||||
|
@ -183,6 +191,12 @@ public class GeoBoundingBoxTests extends AbstractNodesTests {
|
|||
assertThat(searchResponse.hits().getTotalHits(), equalTo(1l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(1));
|
||||
assertThat(searchResponse.hits().getAt(0).id(), equalTo("2"));
|
||||
searchResponse = client.prepareSearch()
|
||||
.setQuery(filteredQuery(matchAllQuery(), geoBoundingBoxFilter("location").topLeft(41, -11).bottomRight(40, 9).type("indexed")))
|
||||
.execute().actionGet();
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(1l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(1));
|
||||
assertThat(searchResponse.hits().getAt(0).id(), equalTo("2"));
|
||||
|
||||
searchResponse = client.prepareSearch()
|
||||
.setQuery(filteredQuery(matchAllQuery(), geoBoundingBoxFilter("location").topLeft(41, -9).bottomRight(40, 11)))
|
||||
|
@ -190,6 +204,12 @@ public class GeoBoundingBoxTests extends AbstractNodesTests {
|
|||
assertThat(searchResponse.hits().getTotalHits(), equalTo(1l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(1));
|
||||
assertThat(searchResponse.hits().getAt(0).id(), equalTo("3"));
|
||||
searchResponse = client.prepareSearch()
|
||||
.setQuery(filteredQuery(matchAllQuery(), geoBoundingBoxFilter("location").topLeft(41, -9).bottomRight(40, 11).type("indexed")))
|
||||
.execute().actionGet();
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(1l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(1));
|
||||
assertThat(searchResponse.hits().getAt(0).id(), equalTo("3"));
|
||||
|
||||
searchResponse = client.prepareSearch()
|
||||
.setQuery(filteredQuery(matchAllQuery(), geoBoundingBoxFilter("location").topLeft(11, 171).bottomRight(1, -169)))
|
||||
|
@ -197,6 +217,12 @@ public class GeoBoundingBoxTests extends AbstractNodesTests {
|
|||
assertThat(searchResponse.hits().getTotalHits(), equalTo(1l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(1));
|
||||
assertThat(searchResponse.hits().getAt(0).id(), equalTo("5"));
|
||||
searchResponse = client.prepareSearch()
|
||||
.setQuery(filteredQuery(matchAllQuery(), geoBoundingBoxFilter("location").topLeft(11, 171).bottomRight(1, -169).type("indexed")))
|
||||
.execute().actionGet();
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(1l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(1));
|
||||
assertThat(searchResponse.hits().getAt(0).id(), equalTo("5"));
|
||||
|
||||
searchResponse = client.prepareSearch()
|
||||
.setQuery(filteredQuery(matchAllQuery(), geoBoundingBoxFilter("location").topLeft(9, 169).bottomRight(-1, -171)))
|
||||
|
@ -204,6 +230,12 @@ public class GeoBoundingBoxTests extends AbstractNodesTests {
|
|||
assertThat(searchResponse.hits().getTotalHits(), equalTo(1l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(1));
|
||||
assertThat(searchResponse.hits().getAt(0).id(), equalTo("9"));
|
||||
searchResponse = client.prepareSearch()
|
||||
.setQuery(filteredQuery(matchAllQuery(), geoBoundingBoxFilter("location").topLeft(9, 169).bottomRight(-1, -171).type("indexed")))
|
||||
.execute().actionGet();
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(1l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(1));
|
||||
assertThat(searchResponse.hits().getAt(0).id(), equalTo("9"));
|
||||
}
|
||||
|
||||
@Test public void limit2BoundingBoxTest() throws Exception {
|
||||
|
@ -240,6 +272,12 @@ public class GeoBoundingBoxTests extends AbstractNodesTests {
|
|||
geoBoundingBoxFilter("location").topLeft(74.579421999999994, 143.5).bottomRight(-66.668903999999998, 113.96875))
|
||||
).execute().actionGet();
|
||||
assertThat(searchResponse.hits().totalHits(), equalTo(1l));
|
||||
searchResponse = client.prepareSearch()
|
||||
.setQuery(
|
||||
filteredQuery(termQuery("userid", 880),
|
||||
geoBoundingBoxFilter("location").topLeft(74.579421999999994, 143.5).bottomRight(-66.668903999999998, 113.96875).type("indexed"))
|
||||
).execute().actionGet();
|
||||
assertThat(searchResponse.hits().totalHits(), equalTo(1l));
|
||||
|
||||
searchResponse = client.prepareSearch()
|
||||
.setQuery(
|
||||
|
@ -247,6 +285,12 @@ public class GeoBoundingBoxTests extends AbstractNodesTests {
|
|||
geoBoundingBoxFilter("location").topLeft(74.579421999999994, 143.5).bottomRight(-66.668903999999998, 113.96875))
|
||||
).execute().actionGet();
|
||||
assertThat(searchResponse.hits().totalHits(), equalTo(1l));
|
||||
searchResponse = client.prepareSearch()
|
||||
.setQuery(
|
||||
filteredQuery(termQuery("userid", 534),
|
||||
geoBoundingBoxFilter("location").topLeft(74.579421999999994, 143.5).bottomRight(-66.668903999999998, 113.96875).type("indexed"))
|
||||
).execute().actionGet();
|
||||
assertThat(searchResponse.hits().totalHits(), equalTo(1l));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ import static org.hamcrest.MatcherAssert.*;
|
|||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class GeoDistanceTests extends AbstractNodesTests {
|
||||
|
||||
|
@ -122,6 +121,14 @@ public class GeoDistanceTests extends AbstractNodesTests {
|
|||
for (SearchHit hit : searchResponse.hits()) {
|
||||
assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"), equalTo("6")));
|
||||
}
|
||||
searchResponse = client.prepareSearch() // from NY
|
||||
.setQuery(filteredQuery(matchAllQuery(), geoDistanceFilter("location").distance("3km").point(40.7143528, -74.0059731).optimizeBbox("indexed")))
|
||||
.execute().actionGet();
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(5l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(5));
|
||||
for (SearchHit hit : searchResponse.hits()) {
|
||||
assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"), equalTo("6")));
|
||||
}
|
||||
|
||||
// now with a PLANE type
|
||||
searchResponse = client.prepareSearch() // from NY
|
||||
|
@ -143,6 +150,14 @@ public class GeoDistanceTests extends AbstractNodesTests {
|
|||
for (SearchHit hit : searchResponse.hits()) {
|
||||
assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5")));
|
||||
}
|
||||
searchResponse = client.prepareSearch() // from NY
|
||||
.setQuery(filteredQuery(matchAllQuery(), geoDistanceFilter("location").distance("2km").point(40.7143528, -74.0059731).optimizeBbox("indexed")))
|
||||
.execute().actionGet();
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(4l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(4));
|
||||
for (SearchHit hit : searchResponse.hits()) {
|
||||
assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5")));
|
||||
}
|
||||
|
||||
searchResponse = client.prepareSearch() // from NY
|
||||
.setQuery(filteredQuery(matchAllQuery(), geoDistanceFilter("location").distance("1.242mi").point(40.7143528, -74.0059731)))
|
||||
|
@ -152,6 +167,14 @@ public class GeoDistanceTests extends AbstractNodesTests {
|
|||
for (SearchHit hit : searchResponse.hits()) {
|
||||
assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5")));
|
||||
}
|
||||
searchResponse = client.prepareSearch() // from NY
|
||||
.setQuery(filteredQuery(matchAllQuery(), geoDistanceFilter("location").distance("1.242mi").point(40.7143528, -74.0059731).optimizeBbox("indexed")))
|
||||
.execute().actionGet();
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(4l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(4));
|
||||
for (SearchHit hit : searchResponse.hits()) {
|
||||
assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5")));
|
||||
}
|
||||
|
||||
searchResponse = client.prepareSearch() // from NY
|
||||
.setQuery(filteredQuery(matchAllQuery(), geoDistanceRangeFilter("location").from("1.0km").to("2.0km").point(40.7143528, -74.0059731)))
|
||||
|
@ -161,6 +184,14 @@ public class GeoDistanceTests extends AbstractNodesTests {
|
|||
for (SearchHit hit : searchResponse.hits()) {
|
||||
assertThat(hit.id(), anyOf(equalTo("4"), equalTo("5")));
|
||||
}
|
||||
searchResponse = client.prepareSearch() // from NY
|
||||
.setQuery(filteredQuery(matchAllQuery(), geoDistanceRangeFilter("location").from("1.0km").to("2.0km").point(40.7143528, -74.0059731).optimizeBbox("indexed")))
|
||||
.execute().actionGet();
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(2l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(2));
|
||||
for (SearchHit hit : searchResponse.hits()) {
|
||||
assertThat(hit.id(), anyOf(equalTo("4"), equalTo("5")));
|
||||
}
|
||||
|
||||
// SORTING
|
||||
|
||||
|
|
Loading…
Reference in New Issue