Geo: Polygon based filter, closes #294.
This commit is contained in:
parent
39f344c11e
commit
959eb0e703
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* 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 GeoPolygonFilter extends Filter {
|
||||
|
||||
private final Point[] points;
|
||||
|
||||
private final String latFieldName;
|
||||
|
||||
private final String lonFieldName;
|
||||
|
||||
private final FieldData.Type fieldDataType;
|
||||
|
||||
private final FieldDataCache fieldDataCache;
|
||||
|
||||
public GeoPolygonFilter(Point[] points, String latFieldName, String lonFieldName, FieldData.Type fieldDataType, FieldDataCache fieldDataCache) {
|
||||
this.points = points;
|
||||
this.latFieldName = latFieldName;
|
||||
this.lonFieldName = lonFieldName;
|
||||
this.fieldDataType = fieldDataType;
|
||||
this.fieldDataCache = fieldDataCache;
|
||||
}
|
||||
|
||||
public Point[] points() {
|
||||
return points;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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 (pointInPolygon(points, lats[i], lons[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
double lat = latFieldData.doubleValue(doc);
|
||||
double lon = lonFieldData.doubleValue(doc);
|
||||
return pointInPolygon(points, lat, lon);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean pointInPolygon(Point[] points, double lat, double lon) {
|
||||
int i;
|
||||
int j = points.length - 1;
|
||||
boolean inPoly = false;
|
||||
|
||||
for (i = 0; i < points.length; i++) {
|
||||
if (points[i].lon < lon && points[j].lon >= lon
|
||||
|| points[j].lon < lon && points[i].lon >= lon) {
|
||||
if (points[i].lat + (lon - points[i].lon) /
|
||||
(points[j].lon - points[i].lon) * (points[j].lat - points[i].lat) < lat) {
|
||||
inPoly = !inPoly;
|
||||
}
|
||||
}
|
||||
j = i;
|
||||
}
|
||||
return inPoly;
|
||||
}
|
||||
|
||||
public static class Point {
|
||||
public double lat;
|
||||
public double lon;
|
||||
|
||||
public Point() {
|
||||
}
|
||||
|
||||
public Point(double lat, double lon) {
|
||||
this.lat = lat;
|
||||
this.lon = lon;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -175,18 +175,42 @@ public abstract class FilterBuilders {
|
|||
return new QueryFilterBuilder(queryBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for filter based on a script.
|
||||
*
|
||||
* @param script The script to filter by.
|
||||
*/
|
||||
public static ScriptFilterBuilder scriptFilter(String script) {
|
||||
return new ScriptFilterBuilder(script);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filter to filter based on a specific distance from a specific geo location / point.
|
||||
*
|
||||
* @param name The location field name.
|
||||
*/
|
||||
public static GeoDistanceFilterBuilder geoDistanceFilter(String name) {
|
||||
return new GeoDistanceFilterBuilder(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filter to filter based on a bounding box defined by top left and bottom right locations / points
|
||||
*
|
||||
* @param name The location field name.
|
||||
*/
|
||||
public static GeoBoundingBoxFilterBuilder geoBoundingBoxFilter(String name) {
|
||||
return new GeoBoundingBoxFilterBuilder(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filter to filter based on a polygon defined by a set of locations / points.
|
||||
*
|
||||
* @param name The location field name.
|
||||
*/
|
||||
public static GeoPolygonFilterBuilder geoPolygonFilter(String name) {
|
||||
return new GeoPolygonFilterBuilder(name);
|
||||
}
|
||||
|
||||
public static BoolFilterBuilder boolFilter() {
|
||||
return new BoolFilterBuilder();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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.collect.Lists;
|
||||
import org.elasticsearch.common.lucene.geo.GeoHashUtils;
|
||||
import org.elasticsearch.common.lucene.geo.GeoPolygonFilter;
|
||||
import org.elasticsearch.common.xcontent.builder.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class GeoPolygonFilterBuilder extends BaseFilterBuilder {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final List<GeoPolygonFilter.Point> points = Lists.newArrayList();
|
||||
|
||||
public GeoPolygonFilterBuilder(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public GeoPolygonFilterBuilder addPoint(double lat, double lon) {
|
||||
points.add(new GeoPolygonFilter.Point(lat, lon));
|
||||
return this;
|
||||
}
|
||||
|
||||
public GeoPolygonFilterBuilder addPoint(String geohash) {
|
||||
double[] values = GeoHashUtils.decode(geohash);
|
||||
return addPoint(values[0], values[1]);
|
||||
}
|
||||
|
||||
@Override protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(GeoPolygonFilterParser.NAME);
|
||||
|
||||
builder.startObject(name);
|
||||
builder.startArray("points");
|
||||
for (GeoPolygonFilter.Point point : points) {
|
||||
builder.startArray().value(point.lat).value(point.lon).endArray();
|
||||
}
|
||||
builder.endArray();
|
||||
builder.endObject();
|
||||
|
||||
builder.endObject();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* 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.collect.Lists;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.lucene.geo.GeoHashUtils;
|
||||
import org.elasticsearch.common.lucene.geo.GeoPolygonFilter;
|
||||
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;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* {
|
||||
* "pin.location" : {
|
||||
* "points" : [
|
||||
* { "lat" : 12, "lon" : 40},
|
||||
* {}
|
||||
* ]
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class GeoPolygonFilterParser extends AbstractIndexComponent implements XContentFilterParser {
|
||||
|
||||
public static final String NAME = "geo_polygon";
|
||||
|
||||
@Inject public GeoPolygonFilterParser(Index index, @IndexSettings Settings indexSettings) {
|
||||
super(index, indexSettings);
|
||||
}
|
||||
|
||||
@Override public String[] names() {
|
||||
return new String[]{NAME, "geoPolygon"};
|
||||
}
|
||||
|
||||
@Override public Filter parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
|
||||
XContentParser parser = parseContext.parser();
|
||||
|
||||
XContentParser.Token token = parser.nextToken();
|
||||
assert token == XContentParser.Token.FIELD_NAME;
|
||||
String latFieldName = parser.currentName() + XContentGeoPointFieldMapper.Names.LAT_SUFFIX;
|
||||
String lonFieldName = parser.currentName() + XContentGeoPointFieldMapper.Names.LON_SUFFIX;
|
||||
|
||||
// now, we move after the field name, which starts the object
|
||||
token = parser.nextToken();
|
||||
assert token == XContentParser.Token.START_OBJECT;
|
||||
|
||||
List<GeoPolygonFilter.Point> points = Lists.newArrayList();
|
||||
|
||||
|
||||
String currentFieldName = null;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (token == XContentParser.Token.START_ARRAY) {
|
||||
if ("points".equals(currentFieldName)) {
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (token == XContentParser.Token.START_ARRAY) {
|
||||
GeoPolygonFilter.Point point = new GeoPolygonFilter.Point();
|
||||
token = parser.nextToken();
|
||||
point.lat = parser.doubleValue();
|
||||
token = parser.nextToken();
|
||||
point.lon = parser.doubleValue();
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
|
||||
}
|
||||
points.add(point);
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
GeoPolygonFilter.Point point = new GeoPolygonFilter.Point();
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
points.add(point);
|
||||
} else if (token.isValue()) {
|
||||
GeoPolygonFilter.Point point = new GeoPolygonFilter.Point();
|
||||
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];
|
||||
}
|
||||
points.add(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (points.isEmpty()) {
|
||||
throw new QueryParsingException(index, "no points defined for geo_polygon filter");
|
||||
}
|
||||
|
||||
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 GeoPolygonFilter(points.toArray(new GeoPolygonFilter.Point[points.size()]), latFieldName, lonFieldName, mapper.fieldDataType(), parseContext.indexCache().fieldData());
|
||||
}
|
||||
}
|
|
@ -88,6 +88,7 @@ public class XContentQueryParserRegistry {
|
|||
add(filterParsersMap, new ScriptFilterParser(index, indexSettings));
|
||||
add(filterParsersMap, new GeoDistanceFilterParser(index, indexSettings));
|
||||
add(filterParsersMap, new GeoBoundingBoxFilterParser(index, indexSettings));
|
||||
add(filterParsersMap, new GeoPolygonFilterParser(index, indexSettings));
|
||||
add(filterParsersMap, new QueryFilterParser(index, indexSettings));
|
||||
add(filterParsersMap, new BoolFilterParser(index, indexSettings));
|
||||
add(filterParsersMap, new AndFilterParser(index, indexSettings));
|
||||
|
|
|
@ -25,6 +25,7 @@ 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.geo.GeoPolygonFilter;
|
||||
import org.elasticsearch.common.lucene.search.*;
|
||||
import org.elasticsearch.common.lucene.search.function.BoostScoreFunction;
|
||||
import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery;
|
||||
|
@ -1074,6 +1075,78 @@ public class SimpleIndexQueryParserTests {
|
|||
assertThat(filter.bottomRight().lon, closeTo(-80, 0.00001));
|
||||
}
|
||||
|
||||
@Test public void testGeoPolygonFilter1() throws IOException {
|
||||
IndexQueryParser queryParser = newQueryParser();
|
||||
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/xcontent/geo_polygon1.json");
|
||||
Query parsedQuery = queryParser.parse(query);
|
||||
assertThat(parsedQuery, instanceOf(FilteredQuery.class));
|
||||
FilteredQuery filteredQuery = (FilteredQuery) parsedQuery;
|
||||
GeoPolygonFilter filter = (GeoPolygonFilter) filteredQuery.getFilter();
|
||||
assertThat(filter.latFieldName(), equalTo("location.lat"));
|
||||
assertThat(filter.lonFieldName(), equalTo("location.lon"));
|
||||
assertThat(filter.points().length, equalTo(3));
|
||||
assertThat(filter.points()[0].lat, closeTo(40, 0.00001));
|
||||
assertThat(filter.points()[0].lon, closeTo(-70, 0.00001));
|
||||
assertThat(filter.points()[1].lat, closeTo(30, 0.00001));
|
||||
assertThat(filter.points()[1].lon, closeTo(-80, 0.00001));
|
||||
assertThat(filter.points()[2].lat, closeTo(20, 0.00001));
|
||||
assertThat(filter.points()[2].lon, closeTo(-90, 0.00001));
|
||||
}
|
||||
|
||||
@Test public void testGeoPolygonFilter2() throws IOException {
|
||||
IndexQueryParser queryParser = newQueryParser();
|
||||
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/xcontent/geo_polygon2.json");
|
||||
Query parsedQuery = queryParser.parse(query);
|
||||
assertThat(parsedQuery, instanceOf(FilteredQuery.class));
|
||||
FilteredQuery filteredQuery = (FilteredQuery) parsedQuery;
|
||||
GeoPolygonFilter filter = (GeoPolygonFilter) filteredQuery.getFilter();
|
||||
assertThat(filter.latFieldName(), equalTo("location.lat"));
|
||||
assertThat(filter.lonFieldName(), equalTo("location.lon"));
|
||||
assertThat(filter.points().length, equalTo(3));
|
||||
assertThat(filter.points()[0].lat, closeTo(40, 0.00001));
|
||||
assertThat(filter.points()[0].lon, closeTo(-70, 0.00001));
|
||||
assertThat(filter.points()[1].lat, closeTo(30, 0.00001));
|
||||
assertThat(filter.points()[1].lon, closeTo(-80, 0.00001));
|
||||
assertThat(filter.points()[2].lat, closeTo(20, 0.00001));
|
||||
assertThat(filter.points()[2].lon, closeTo(-90, 0.00001));
|
||||
}
|
||||
|
||||
@Test public void testGeoPolygonFilter3() throws IOException {
|
||||
IndexQueryParser queryParser = newQueryParser();
|
||||
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/xcontent/geo_polygon3.json");
|
||||
Query parsedQuery = queryParser.parse(query);
|
||||
assertThat(parsedQuery, instanceOf(FilteredQuery.class));
|
||||
FilteredQuery filteredQuery = (FilteredQuery) parsedQuery;
|
||||
GeoPolygonFilter filter = (GeoPolygonFilter) filteredQuery.getFilter();
|
||||
assertThat(filter.latFieldName(), equalTo("location.lat"));
|
||||
assertThat(filter.lonFieldName(), equalTo("location.lon"));
|
||||
assertThat(filter.points().length, equalTo(3));
|
||||
assertThat(filter.points()[0].lat, closeTo(40, 0.00001));
|
||||
assertThat(filter.points()[0].lon, closeTo(-70, 0.00001));
|
||||
assertThat(filter.points()[1].lat, closeTo(30, 0.00001));
|
||||
assertThat(filter.points()[1].lon, closeTo(-80, 0.00001));
|
||||
assertThat(filter.points()[2].lat, closeTo(20, 0.00001));
|
||||
assertThat(filter.points()[2].lon, closeTo(-90, 0.00001));
|
||||
}
|
||||
|
||||
@Test public void testGeoPolygonFilter4() throws IOException {
|
||||
IndexQueryParser queryParser = newQueryParser();
|
||||
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/xcontent/geo_polygon4.json");
|
||||
Query parsedQuery = queryParser.parse(query);
|
||||
assertThat(parsedQuery, instanceOf(FilteredQuery.class));
|
||||
FilteredQuery filteredQuery = (FilteredQuery) parsedQuery;
|
||||
GeoPolygonFilter filter = (GeoPolygonFilter) filteredQuery.getFilter();
|
||||
assertThat(filter.latFieldName(), equalTo("location.lat"));
|
||||
assertThat(filter.lonFieldName(), equalTo("location.lon"));
|
||||
assertThat(filter.points().length, equalTo(3));
|
||||
assertThat(filter.points()[0].lat, closeTo(40, 0.00001));
|
||||
assertThat(filter.points()[0].lon, closeTo(-70, 0.00001));
|
||||
assertThat(filter.points()[1].lat, closeTo(30, 0.00001));
|
||||
assertThat(filter.points()[1].lon, closeTo(-80, 0.00001));
|
||||
assertThat(filter.points()[2].lat, closeTo(20, 0.00001));
|
||||
assertThat(filter.points()[2].lon, closeTo(-90, 0.00001));
|
||||
}
|
||||
|
||||
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,18 @@
|
|||
{
|
||||
"filtered" : {
|
||||
"query" : {
|
||||
"match_all" : {}
|
||||
},
|
||||
"filter" : {
|
||||
"geo_polygon" : {
|
||||
"person.location" : {
|
||||
"points" : [
|
||||
[40, -70],
|
||||
[30, -80],
|
||||
[20, -90]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"filtered" : {
|
||||
"query" : {
|
||||
"match_all" : {}
|
||||
},
|
||||
"filter" : {
|
||||
"geo_polygon" : {
|
||||
"person.location" : {
|
||||
"points" : [
|
||||
{
|
||||
"lat" : 40,
|
||||
"lon" : -70
|
||||
},
|
||||
{
|
||||
"lat" : 30,
|
||||
"lon" : -80
|
||||
},
|
||||
{
|
||||
"lat" : 20,
|
||||
"lon" : -90
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"filtered" : {
|
||||
"query" : {
|
||||
"match_all" : {}
|
||||
},
|
||||
"filter" : {
|
||||
"geo_polygon" : {
|
||||
"person.location" : {
|
||||
"points" : [
|
||||
"40, -70",
|
||||
"30, -80",
|
||||
"20, -90"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"filtered" : {
|
||||
"query" : {
|
||||
"match_all" : {}
|
||||
},
|
||||
"filter" : {
|
||||
"geo_polygon" : {
|
||||
"person.location" : {
|
||||
"points" : [
|
||||
"drn5x1g8cu2y",
|
||||
"30, -80",
|
||||
"20, -90"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue