Allow to filter geo bounding box or distance based on indexed lat lon, closes #1334.

This commit is contained in:
Shay Banon 2011-09-14 14:27:39 +03:00
parent 819653cdba
commit e2b1cb1640
17 changed files with 485 additions and 76 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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