Geo: bounding box filter, closes #290.
This commit is contained in:
parent
d1e404c1b3
commit
de8ffaf5fb
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* 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.common.lucene.geo;
|
||||
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.search.DocIdSet;
|
||||
import org.apache.lucene.search.Filter;
|
||||
import org.elasticsearch.common.lucene.docset.GetDocSet;
|
||||
import org.elasticsearch.index.cache.field.data.FieldDataCache;
|
||||
import org.elasticsearch.index.field.data.FieldData;
|
||||
import org.elasticsearch.index.field.data.NumericFieldData;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class GeoBoundingBoxFilter extends Filter {
|
||||
|
||||
private final Point topLeft;
|
||||
|
||||
private final Point bottomRight;
|
||||
|
||||
private final String latFieldName;
|
||||
|
||||
private final String lonFieldName;
|
||||
|
||||
private final FieldData.Type fieldDataType;
|
||||
|
||||
private final FieldDataCache fieldDataCache;
|
||||
|
||||
public GeoBoundingBoxFilter(Point topLeft, Point bottomRight, String latFieldName, String lonFieldName, FieldData.Type fieldDataType, FieldDataCache fieldDataCache) {
|
||||
this.topLeft = topLeft;
|
||||
this.bottomRight = bottomRight;
|
||||
this.latFieldName = latFieldName;
|
||||
this.lonFieldName = lonFieldName;
|
||||
this.fieldDataType = fieldDataType;
|
||||
this.fieldDataCache = fieldDataCache;
|
||||
}
|
||||
|
||||
public Point topLeft() {
|
||||
return topLeft;
|
||||
}
|
||||
|
||||
public Point bottomRight() {
|
||||
return bottomRight;
|
||||
}
|
||||
|
||||
public String latFieldName() {
|
||||
return latFieldName;
|
||||
}
|
||||
|
||||
public String lonFieldName() {
|
||||
return lonFieldName;
|
||||
}
|
||||
|
||||
@Override public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
|
||||
final NumericFieldData latFieldData = (NumericFieldData) fieldDataCache.cache(fieldDataType, reader, latFieldName);
|
||||
final NumericFieldData lonFieldData = (NumericFieldData) fieldDataCache.cache(fieldDataType, reader, lonFieldName);
|
||||
|
||||
if (topLeft.lon > bottomRight.lon) {
|
||||
return new GetDocSet(reader.maxDoc()) {
|
||||
@Override public boolean get(int doc) throws IOException {
|
||||
if (!latFieldData.hasValue(doc) || !lonFieldData.hasValue(doc)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (latFieldData.multiValued()) {
|
||||
double[] lats = latFieldData.doubleValues(doc);
|
||||
double[] lons = latFieldData.doubleValues(doc);
|
||||
for (int i = 0; i < lats.length; i++) {
|
||||
if (topLeft.lon >= lons[i] && bottomRight.lon <= lons[i]
|
||||
&& topLeft.lat >= lats[i] && bottomRight.lat <= lats[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
double lat = latFieldData.doubleValue(doc);
|
||||
double lon = lonFieldData.doubleValue(doc);
|
||||
if (topLeft.lon >= lon && bottomRight.lon <= lon
|
||||
&& topLeft.lat >= lat && bottomRight.lat <= lat) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return new GetDocSet(reader.maxDoc()) {
|
||||
@Override public boolean get(int doc) throws IOException {
|
||||
if (!latFieldData.hasValue(doc) || !lonFieldData.hasValue(doc)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (latFieldData.multiValued()) {
|
||||
double[] lats = latFieldData.doubleValues(doc);
|
||||
double[] lons = latFieldData.doubleValues(doc);
|
||||
for (int i = 0; i < lats.length; i++) {
|
||||
if (topLeft.lon <= lons[i] && bottomRight.lon >= lons[i]
|
||||
&& topLeft.lat >= lats[i] && bottomRight.lat <= lats[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
double lat = latFieldData.doubleValue(doc);
|
||||
double lon = lonFieldData.doubleValue(doc);
|
||||
|
||||
if (topLeft.lon <= lon && bottomRight.lon >= lon
|
||||
&& topLeft.lat >= lat && bottomRight.lat <= lat) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class Point {
|
||||
public double lat;
|
||||
public double lon;
|
||||
}
|
||||
}
|
|
@ -179,10 +179,14 @@ public abstract class FilterBuilders {
|
|||
return new ScriptFilterBuilder(script);
|
||||
}
|
||||
|
||||
public static GeoDistanceFilterBuilder geoDistance(String name) {
|
||||
public static GeoDistanceFilterBuilder geoDistanceFilter(String name) {
|
||||
return new GeoDistanceFilterBuilder(name);
|
||||
}
|
||||
|
||||
public static GeoBoundingBoxFilterBuilder geoBoundingBoxFilter(String name) {
|
||||
return new GeoBoundingBoxFilterBuilder(name);
|
||||
}
|
||||
|
||||
public static BoolFilterBuilder boolFilter() {
|
||||
return new BoolFilterBuilder();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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.query.xcontent;
|
||||
|
||||
import org.elasticsearch.common.lucene.geo.GeoBoundingBoxFilter;
|
||||
import org.elasticsearch.common.xcontent.builder.XContentBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilderException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class GeoBoundingBoxFilterBuilder extends BaseFilterBuilder {
|
||||
|
||||
private final String name;
|
||||
|
||||
private GeoBoundingBoxFilter.Point topLeft;
|
||||
|
||||
private String topLeftGeohash;
|
||||
|
||||
private GeoBoundingBoxFilter.Point bottomRight;
|
||||
|
||||
private String bottomRightGeohash;
|
||||
|
||||
public GeoBoundingBoxFilterBuilder(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public GeoBoundingBoxFilterBuilder topLeft(double lat, double lon) {
|
||||
topLeft = new GeoBoundingBoxFilter.Point();
|
||||
topLeft.lat = lat;
|
||||
topLeft.lon = lon;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GeoBoundingBoxFilterBuilder bottomRight(double lat, double lon) {
|
||||
bottomRight = new GeoBoundingBoxFilter.Point();
|
||||
bottomRight.lat = lat;
|
||||
bottomRight.lon = lon;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GeoBoundingBoxFilterBuilder topLeft(String geohash) {
|
||||
this.topLeftGeohash = geohash;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GeoBoundingBoxFilterBuilder bottomRight(String geohash) {
|
||||
this.bottomRightGeohash = geohash;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(GeoBoundingBoxFilterParser.NAME);
|
||||
|
||||
builder.field("field", name);
|
||||
if (topLeftGeohash != null) {
|
||||
builder.field("top_left", topLeftGeohash);
|
||||
} else if (topLeft != null) {
|
||||
builder.startArray("top_left").value(topLeft.lat).value(topLeft.lon).endArray();
|
||||
} else {
|
||||
throw new QueryBuilderException("geo_bounding_box requires 'top_left' to be set");
|
||||
}
|
||||
|
||||
if (bottomRightGeohash != null) {
|
||||
builder.field("bottom_right", bottomRightGeohash);
|
||||
} else if (bottomRight != null) {
|
||||
builder.startArray("bottom_right").value(bottomRight.lat).value(bottomRight.lon).endArray();
|
||||
} else {
|
||||
throw new QueryBuilderException("geo_bounding_box requires 'bottom_right' to be set");
|
||||
}
|
||||
|
||||
builder.endObject();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* 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.query.xcontent;
|
||||
|
||||
import org.apache.lucene.search.Filter;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.lucene.geo.GeoBoundingBoxFilter;
|
||||
import org.elasticsearch.common.lucene.geo.GeoHashUtils;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.AbstractIndexComponent;
|
||||
import org.elasticsearch.index.Index;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.mapper.MapperService;
|
||||
import org.elasticsearch.index.mapper.xcontent.XContentGeoPointFieldMapper;
|
||||
import org.elasticsearch.index.query.QueryParsingException;
|
||||
import org.elasticsearch.index.settings.IndexSettings;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class GeoBoundingBoxFilterParser extends AbstractIndexComponent implements XContentFilterParser {
|
||||
|
||||
public static final String NAME = "geo_bounding_box";
|
||||
|
||||
@Inject public GeoBoundingBoxFilterParser(Index index, @IndexSettings Settings indexSettings) {
|
||||
super(index, indexSettings);
|
||||
}
|
||||
|
||||
@Override public String[] names() {
|
||||
return new String[]{NAME, "geoBoundingBox"};
|
||||
}
|
||||
|
||||
@Override public Filter parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
|
||||
XContentParser parser = parseContext.parser();
|
||||
|
||||
GeoBoundingBoxFilter.Point topLeft = new GeoBoundingBoxFilter.Point();
|
||||
GeoBoundingBoxFilter.Point bottomRight = new GeoBoundingBoxFilter.Point();
|
||||
|
||||
String latFieldName = null;
|
||||
String lonFieldName = null;
|
||||
|
||||
String currentFieldName = null;
|
||||
XContentParser.Token token;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (token == XContentParser.Token.START_ARRAY) {
|
||||
GeoBoundingBoxFilter.Point point = null;
|
||||
if ("top_left".equals(currentFieldName) || "topLeft".equals(currentFieldName)) {
|
||||
point = topLeft;
|
||||
} else if ("bottom_right".equals(currentFieldName) || "bottomRight".equals(currentFieldName)) {
|
||||
point = bottomRight;
|
||||
}
|
||||
|
||||
if (point != null) {
|
||||
token = parser.nextToken();
|
||||
point.lat = parser.doubleValue();
|
||||
token = parser.nextToken();
|
||||
point.lon = parser.doubleValue();
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
|
||||
}
|
||||
}
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
GeoBoundingBoxFilter.Point point = null;
|
||||
if ("top_left".equals(currentFieldName) || "topLeft".equals(currentFieldName)) {
|
||||
point = topLeft;
|
||||
} else if ("bottom_right".equals(currentFieldName) || "bottomRight".equals(currentFieldName)) {
|
||||
point = bottomRight;
|
||||
}
|
||||
|
||||
if (point != null) {
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (token.isValue()) {
|
||||
if (currentFieldName.equals(XContentGeoPointFieldMapper.Names.LAT)) {
|
||||
point.lat = parser.doubleValue();
|
||||
} else if (currentFieldName.equals(XContentGeoPointFieldMapper.Names.LON)) {
|
||||
point.lon = parser.doubleValue();
|
||||
} else if (currentFieldName.equals(XContentGeoPointFieldMapper.Names.GEOHASH)) {
|
||||
double[] values = GeoHashUtils.decode(parser.text());
|
||||
point.lat = values[0];
|
||||
point.lon = values[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (token.isValue()) {
|
||||
if ("field".equals(currentFieldName)) {
|
||||
latFieldName = parser.text() + XContentGeoPointFieldMapper.Names.LAT_SUFFIX;
|
||||
lonFieldName = parser.text() + XContentGeoPointFieldMapper.Names.LON_SUFFIX;
|
||||
} else {
|
||||
GeoBoundingBoxFilter.Point point = null;
|
||||
if ("top_left".equals(currentFieldName) || "topLeft".equals(currentFieldName)) {
|
||||
point = topLeft;
|
||||
} else if ("bottom_right".equals(currentFieldName) || "bottomRight".equals(currentFieldName)) {
|
||||
point = bottomRight;
|
||||
}
|
||||
|
||||
if (point != null) {
|
||||
String value = parser.text();
|
||||
int comma = value.indexOf(',');
|
||||
if (comma != -1) {
|
||||
point.lat = Double.parseDouble(value.substring(0, comma).trim());
|
||||
point.lon = Double.parseDouble(value.substring(comma + 1).trim());
|
||||
} else {
|
||||
double[] values = GeoHashUtils.decode(value);
|
||||
point.lat = values[0];
|
||||
point.lon = values[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MapperService mapperService = parseContext.mapperService();
|
||||
FieldMapper mapper = mapperService.smartNameFieldMapper(latFieldName);
|
||||
if (mapper == null) {
|
||||
throw new QueryParsingException(index, "failed to find lat field [" + latFieldName + "]");
|
||||
}
|
||||
latFieldName = mapper.names().indexName();
|
||||
|
||||
mapper = mapperService.smartNameFieldMapper(lonFieldName);
|
||||
if (mapper == null) {
|
||||
throw new QueryParsingException(index, "failed to find lon field [" + lonFieldName + "]");
|
||||
}
|
||||
lonFieldName = mapper.names().indexName();
|
||||
|
||||
|
||||
return new GeoBoundingBoxFilter(topLeft, bottomRight, latFieldName, lonFieldName, mapper.fieldDataType(), parseContext.indexCache().fieldData());
|
||||
}
|
||||
}
|
|
@ -87,6 +87,7 @@ public class XContentQueryParserRegistry {
|
|||
add(filterParsersMap, new PrefixFilterParser(index, indexSettings));
|
||||
add(filterParsersMap, new ScriptFilterParser(index, indexSettings));
|
||||
add(filterParsersMap, new GeoDistanceFilterParser(index, indexSettings));
|
||||
add(filterParsersMap, new GeoBoundingBoxFilterParser(index, indexSettings));
|
||||
add(filterParsersMap, new QueryFilterParser(index, indexSettings));
|
||||
add(filterParsersMap, new BoolFilterParser(index, indexSettings));
|
||||
add(filterParsersMap, new AndFilterParser(index, indexSettings));
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.lucene.index.Term;
|
|||
import org.apache.lucene.search.*;
|
||||
import org.apache.lucene.search.spans.*;
|
||||
import org.apache.lucene.util.NumericUtils;
|
||||
import org.elasticsearch.common.lucene.geo.GeoBoundingBoxFilter;
|
||||
import org.elasticsearch.common.lucene.geo.GeoDistanceFilter;
|
||||
import org.elasticsearch.common.lucene.search.*;
|
||||
import org.elasticsearch.common.lucene.search.function.BoostScoreFunction;
|
||||
|
@ -1013,6 +1014,66 @@ public class SimpleIndexQueryParserTests {
|
|||
assertThat(filter.distance(), closeTo(12, 0.00001));
|
||||
}
|
||||
|
||||
@Test public void testGeoBoundingBoxFilter1() throws IOException {
|
||||
IndexQueryParser queryParser = newQueryParser();
|
||||
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/xcontent/geo_boundingbox1.json");
|
||||
Query parsedQuery = queryParser.parse(query);
|
||||
assertThat(parsedQuery, instanceOf(FilteredQuery.class));
|
||||
FilteredQuery filteredQuery = (FilteredQuery) parsedQuery;
|
||||
GeoBoundingBoxFilter filter = (GeoBoundingBoxFilter) filteredQuery.getFilter();
|
||||
assertThat(filter.latFieldName(), equalTo("location.lat"));
|
||||
assertThat(filter.lonFieldName(), equalTo("location.lon"));
|
||||
assertThat(filter.topLeft().lat, closeTo(40, 0.00001));
|
||||
assertThat(filter.topLeft().lon, closeTo(-70, 0.00001));
|
||||
assertThat(filter.bottomRight().lat, closeTo(30, 0.00001));
|
||||
assertThat(filter.bottomRight().lon, closeTo(-80, 0.00001));
|
||||
}
|
||||
|
||||
@Test public void testGeoBoundingBoxFilter2() throws IOException {
|
||||
IndexQueryParser queryParser = newQueryParser();
|
||||
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/xcontent/geo_boundingbox2.json");
|
||||
Query parsedQuery = queryParser.parse(query);
|
||||
assertThat(parsedQuery, instanceOf(FilteredQuery.class));
|
||||
FilteredQuery filteredQuery = (FilteredQuery) parsedQuery;
|
||||
GeoBoundingBoxFilter filter = (GeoBoundingBoxFilter) filteredQuery.getFilter();
|
||||
assertThat(filter.latFieldName(), equalTo("location.lat"));
|
||||
assertThat(filter.lonFieldName(), equalTo("location.lon"));
|
||||
assertThat(filter.topLeft().lat, closeTo(40, 0.00001));
|
||||
assertThat(filter.topLeft().lon, closeTo(-70, 0.00001));
|
||||
assertThat(filter.bottomRight().lat, closeTo(30, 0.00001));
|
||||
assertThat(filter.bottomRight().lon, closeTo(-80, 0.00001));
|
||||
}
|
||||
|
||||
@Test public void testGeoBoundingBoxFilter3() throws IOException {
|
||||
IndexQueryParser queryParser = newQueryParser();
|
||||
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/xcontent/geo_boundingbox3.json");
|
||||
Query parsedQuery = queryParser.parse(query);
|
||||
assertThat(parsedQuery, instanceOf(FilteredQuery.class));
|
||||
FilteredQuery filteredQuery = (FilteredQuery) parsedQuery;
|
||||
GeoBoundingBoxFilter filter = (GeoBoundingBoxFilter) filteredQuery.getFilter();
|
||||
assertThat(filter.latFieldName(), equalTo("location.lat"));
|
||||
assertThat(filter.lonFieldName(), equalTo("location.lon"));
|
||||
assertThat(filter.topLeft().lat, closeTo(40, 0.00001));
|
||||
assertThat(filter.topLeft().lon, closeTo(-70, 0.00001));
|
||||
assertThat(filter.bottomRight().lat, closeTo(30, 0.00001));
|
||||
assertThat(filter.bottomRight().lon, closeTo(-80, 0.00001));
|
||||
}
|
||||
|
||||
@Test public void testGeoBoundingBoxFilter4() throws IOException {
|
||||
IndexQueryParser queryParser = newQueryParser();
|
||||
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/xcontent/geo_boundingbox4.json");
|
||||
Query parsedQuery = queryParser.parse(query);
|
||||
assertThat(parsedQuery, instanceOf(FilteredQuery.class));
|
||||
FilteredQuery filteredQuery = (FilteredQuery) parsedQuery;
|
||||
GeoBoundingBoxFilter filter = (GeoBoundingBoxFilter) filteredQuery.getFilter();
|
||||
assertThat(filter.latFieldName(), equalTo("location.lat"));
|
||||
assertThat(filter.lonFieldName(), equalTo("location.lon"));
|
||||
assertThat(filter.topLeft().lat, closeTo(40, 0.00001));
|
||||
assertThat(filter.topLeft().lon, closeTo(-70, 0.00001));
|
||||
assertThat(filter.bottomRight().lat, closeTo(30, 0.00001));
|
||||
assertThat(filter.bottomRight().lon, closeTo(-80, 0.00001));
|
||||
}
|
||||
|
||||
private XContentIndexQueryParser newQueryParser() throws IOException {
|
||||
return new XContentIndexQueryParser(new Index("test"), EMPTY_SETTINGS, new ScriptService(EMPTY_SETTINGS),
|
||||
newMapperService(), new IndexCache(index), new RobinIndexEngine(index), new AnalysisService(index), null, null, null, "test", null);
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"filtered" : {
|
||||
"query" : {
|
||||
"match_all" : {}
|
||||
},
|
||||
"filter" : {
|
||||
"geo_bounding_box" : {
|
||||
"field" : "person.location",
|
||||
"top_left" : [40, -70],
|
||||
"bottom_right" : [30, -80]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"filtered" : {
|
||||
"query" : {
|
||||
"match_all" : {}
|
||||
},
|
||||
"filter" : {
|
||||
"geo_bounding_box" : {
|
||||
"field" : "person.location",
|
||||
"top_left" : {
|
||||
"lat" : 40,
|
||||
"lon" : -70
|
||||
},
|
||||
"bottom_right" : {
|
||||
"lat" : 30,
|
||||
"lon" : -80
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"filtered" : {
|
||||
"query" : {
|
||||
"match_all" : {}
|
||||
},
|
||||
"filter" : {
|
||||
"geo_bounding_box" : {
|
||||
"field" : "person.location",
|
||||
"top_left" : "40, -70",
|
||||
"bottom_right" : "30, -80"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"filtered" : {
|
||||
"query" : {
|
||||
"match_all" : {}
|
||||
},
|
||||
"filter" : {
|
||||
"geo_bounding_box" : {
|
||||
"field" : "person.location",
|
||||
"top_left" : "drn5x1g8cu2y",
|
||||
"bottom_right" : "30, -80"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* 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.test.integration.search.geo;
|
||||
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.elasticsearch.test.integration.AbstractNodesTests;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.*;
|
||||
import static org.elasticsearch.index.query.xcontent.FilterBuilders.*;
|
||||
import static org.elasticsearch.index.query.xcontent.QueryBuilders.*;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class GeoBoundingBoxTests extends AbstractNodesTests {
|
||||
|
||||
private Client client;
|
||||
|
||||
@BeforeClass public void createNodes() throws Exception {
|
||||
startNode("server1");
|
||||
startNode("server2");
|
||||
client = getClient();
|
||||
}
|
||||
|
||||
@AfterClass public void closeNodes() {
|
||||
client.close();
|
||||
closeAllNodes();
|
||||
}
|
||||
|
||||
protected Client getClient() {
|
||||
return client("server1");
|
||||
}
|
||||
|
||||
@Test public void simpleBoundingBoxTest() throws Exception {
|
||||
try {
|
||||
client.admin().indices().prepareDelete("test").execute().actionGet();
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
client.admin().indices().prepareCreate("test").execute().actionGet();
|
||||
client.admin().cluster().prepareHealth().setWaitForGreenStatus().execute().actionGet();
|
||||
|
||||
client.prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject()
|
||||
.field("name", "New York")
|
||||
.startObject("location").field("lat", 40.7143528).field("lon", -74.0059731).endObject()
|
||||
.endObject()).execute().actionGet();
|
||||
|
||||
// to NY: 5.286 km
|
||||
client.prepareIndex("test", "type1", "2").setSource(jsonBuilder().startObject()
|
||||
.field("name", "Times Square")
|
||||
.startObject("location").field("lat", 40.759011).field("lon", -73.9844722).endObject()
|
||||
.endObject()).execute().actionGet();
|
||||
|
||||
// to NY: 0.4621 km
|
||||
client.prepareIndex("test", "type1", "3").setSource(jsonBuilder().startObject()
|
||||
.field("name", "Tribeca")
|
||||
.startObject("location").field("lat", 40.718266).field("lon", -74.007819).endObject()
|
||||
.endObject()).execute().actionGet();
|
||||
|
||||
// to NY: 1.055 km
|
||||
client.prepareIndex("test", "type1", "4").setSource(jsonBuilder().startObject()
|
||||
.field("name", "Wall Street")
|
||||
.startObject("location").field("lat", 40.7051157).field("lon", -74.0088305).endObject()
|
||||
.endObject()).execute().actionGet();
|
||||
|
||||
// to NY: 1.258 km
|
||||
client.prepareIndex("test", "type1", "5").setSource(jsonBuilder().startObject()
|
||||
.field("name", "Soho")
|
||||
.startObject("location").field("lat", 40.7247222).field("lon", -74).endObject()
|
||||
.endObject()).execute().actionGet();
|
||||
|
||||
// to NY: 2.029 km
|
||||
client.prepareIndex("test", "type1", "6").setSource(jsonBuilder().startObject()
|
||||
.field("name", "Greenwich Village")
|
||||
.startObject("location").field("lat", 40.731033).field("lon", -73.9962255).endObject()
|
||||
.endObject()).execute().actionGet();
|
||||
|
||||
// to NY: 8.572 km
|
||||
client.prepareIndex("test", "type1", "7").setSource(jsonBuilder().startObject()
|
||||
.field("name", "Brooklyn")
|
||||
.startObject("location").field("lat", 40.65).field("lon", -73.95).endObject()
|
||||
.endObject()).execute().actionGet();
|
||||
|
||||
client.admin().indices().prepareRefresh().execute().actionGet();
|
||||
|
||||
SearchResponse searchResponse = client.prepareSearch() // from NY
|
||||
.setQuery(filtered(matchAllQuery(), geoBoundingBoxFilter("location").topLeft(40.73, -74.1).bottomRight(40.717, -73.99)))
|
||||
.execute().actionGet();
|
||||
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")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -108,22 +108,28 @@ public class GeoDistanceTests extends AbstractNodesTests {
|
|||
client.admin().indices().prepareRefresh().execute().actionGet();
|
||||
|
||||
SearchResponse searchResponse = client.prepareSearch() // from NY
|
||||
.setQuery(filtered(matchAllQuery(), geoDistance("location").distance("3km").point(40.7143528, -74.0059731)))
|
||||
.setQuery(filtered(matchAllQuery(), geoDistanceFilter("location").distance("3km").point(40.7143528, -74.0059731)))
|
||||
.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")));
|
||||
}
|
||||
|
||||
searchResponse = client.prepareSearch() // from NY
|
||||
.setQuery(filtered(matchAllQuery(), geoDistance("location").distance("2km").point(40.7143528, -74.0059731)))
|
||||
.setQuery(filtered(matchAllQuery(), geoDistanceFilter("location").distance("2km").point(40.7143528, -74.0059731)))
|
||||
.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(filtered(matchAllQuery(), geoDistance("location").distance("1.242mi").point(40.7143528, -74.0059731)))
|
||||
.setQuery(filtered(matchAllQuery(), geoDistanceFilter("location").distance("1.242mi").point(40.7143528, -74.0059731)))
|
||||
.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")));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue