Issue with radius search? - elasticsearch

We're on Elasticsearch 1.3.2.
We can't seem to get a record returned when doing a radial search against a linestring.
Our mapping can be broken down to this:
{
"simpleline":{
"properties": {
"geo_linestring": {
"type": "geo_shape",
"tree": "quadtree",
"tree_levels": 26
}
}
}
}
We have a linear path that sort of forms a "U":
{
"geo_linestring": {
"type": "linestring",
"coordinates": [
[
-96.6906661987305,
47.7989692687988
],
[
-96.7057800292969,
47.2933502197266
],
[
-96.3336181640625,
47.2952117919922
],
[
-96.3226318359375,
47.8358612060547
]
]
}
}
The connection between middle two points appear to be within 15-20 miles of the city of Felton, MN. So, if we wanted to find all "trails" within 30 miles of Felton, we want this to appear.
However, filtering on a circle centered at Felton (30 mile radius) does not return the item. Increasing the radius to 40 miles, however, does:
{
"filter": {
"geo_shape": {
"geo_linestring": {
"shape": {
"type": "circle",
"radius": "30mi",
"coordinates": [
-96.5055999755859,
47.0751991271973
]
}
}
}
}
}
Are we just misunderstanding how this search works, or is there an issue with how we're approaching this?

Related

Elasticsearch intersecting polygon with points

I have elasticsearch v7.4 running and I need to find features that intersects bunch of points.
When I'm using 'Point' and put one coordinate pair it's running ok.
GET xxxxx/_search
{
"query": {
"geo_shape": {
"geometry": {
"shape": {
"type": "Point",
"coordinates":
[-90, 40]
},
"relation": "intersects"
}
}
}
}
But when I'm trying to change 'Point' to 'MultiPoint' I receive an error
Field [geometry] does not support multipoint queries
GET xxxx/_search
{
"query": {
"geo_shape": {
"geometry": {
"shape": {
"type": "MultiPoint",
"coordinates": [
[-90, 40],
[-80, 30]
]
},
"relation": "intersects"
}
}
}
}
Is this something related to v7.4 or am I doing something wrong here?
According to issue #27954, BKD-tree backed geoshapes did not support MultiPoint queries, but it is supported as of 7.7 (see 7.7 release notes)

How to find the nearest linestring(geo_shape) from a given point in elasticsearch and sort them by distance as well?

myquery={
"query": {
"geo_shape": {
"line_shape": {
"shape": {
"type": "circle",
"radius": "100m",
"coordinates": [
lon,lat
]
}
}
}
}}
It shows all lines within 100m , I want to sort them by distance , like - line B then line A and so on. Can you help me please?

Elasticsearch custom geo distance filter

From an Elasticsearch query I'd like to retrieve all the points within a variable distance.
Let say I have 2 shops, one is willing to deliver at maximum 3 km and the other one at maximum 5 km:
PUT /my_shops/_doc/1
{
"location": {
"lat": 40.12,
"lon": -71.34
},
"max_delivery_distance": 3000
}
PUT /my_shops/_doc/2
{
"location": {
"lat": 41.12,
"lon": -72.34
},
"max_delivery_distance": 5000
}
For a given location I'd like to know which shops are able to deliver. IE query should return shop1 if given location is within 3km and shop2 if given location is within 5km
GET /my_shops/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": {
"geo_distance": {
"distance": max_delivery_distance,
"location": {
"lat": 40,
"lon": -70
}
}
}
}
}
}
There's another way to solve this without scripting (big performance hogger !!) and let ES sort it out using native Geo shapes.
I would model each document as a circle, with a center location and a (delivery) radius. First, your index mapping should look like this:
PUT /my_shops
{
"mappings": {
"properties": {
"delivery_area": {
"type": "geo_shape",
"strategy": "recursive"
}
}
}
}
Then, your documents then need to have the following form:
PUT /my_shops/_doc/1
{
"delivery_area" : {
"type" : "circle",
"coordinates" : [-71.34, 40.12],
"radius" : "3000m"
}
}
PUT /my_shops/_doc/2
{
"delivery_area" : {
"type" : "circle",
"coordinates" : [-72.34, 41.12],
"radius" : "5000m"
}
}
And finally the query simply becomes a geo_shape query looking at intersections between a delivery point and the delivery area of each shop.
GET /my_shops/_search
{
"query": {
"bool": {
"filter": {
"geo_shape": {
"delivery_area": {
"shape": {
"type": "point",
"coordinates": [ -70, 40 ]
},
"relation": "contains"
}
}
}
}
}
}
That's it! No scripting, just geo operations.
I think that you need to work with a script to use another field as parameter. After some research I come to this answer:
GET my_shops/_search
{
"query": {
"script": {
"script": {
"params": {
"location": {
"lat": 40,
"lon": -70
}
},
"source": """
return doc['location'].arcDistance(params.location.lat, params.location.lon)/1000 <= doc['max_delivery_distance'].value"""
}
}
}
}
Basically, we exploit the fact that the classes related to the GEO points are whitelisted in painless https://github.com/elastic/elasticsearch/pull/40180/ and that scripts accepts additional parameters (your fixed location).
According to the documentation of arcDistance we retrieve the size in meters, so you need to convert this value into km by dividing by 1000.
Additional Note
I assume that location and max_delivery_distance are always (for each document) defined. If it is not the case, you need to cover this case.
Reference
Another related question
https://github.com/elastic/elasticsearch/pull/40180/

Does Elasticsearch support geo queries like ST_DWithin in postgis

How to perform such query in Elasticsearch that whether a geo_point is within the specified distance(or radius/buffer) of a line(depicted by 2 pairs of lat/lon)
shape like this
This is not implemented in Elastic as far as I know. But you can still achieve what you want by calculating the polygon offline and then use it in a geo_polygon query. The geo_shape query could also be used but you need a geo_shape field instead of a geo_point one.
So, for instance, using turf you can precompute the polygon around the line using the buffer feature. Below, I'm defining a line along some road somewhere in San Jose (CA) and a buffer of 50 meters around that line/road:
const line = turf.lineString([[-121.862282,37.315430], [-121.851553,37.305532]], {name: 'line 1'});
const bufferPoly = turf.buffer(line, 50, {units: 'meters'});
You'll get the following polygon (abbreviated)
{
"type": "Feature",
"properties": {
"name": "line 1"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-121.85121372045873,
37.305765606399724
],
[
-121.85116304254947,
37.30570833334188
],
[
-121.85112738572346,
37.30564429665501
],
[
-121.85110812025259,
37.30557595721911
],
...
[
-121.85121372045873,
37.305765606399724
]
]
]
}
}
Which looks like this:
Then you can leverage the geo_polygon query like this:
GET /_search
{
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": {
"geo_polygon": {
"your_geo_point": {
"points": [
[
-121.85121372045873,
37.305765606399724
],
[
-121.85116304254947,
37.30570833334188
],
[
-121.85112738572346,
37.30564429665501
],
[
-121.85110812025259,
37.30557595721911
],
...
[
-121.85121372045873,
37.305765606399724
]
]
}
}
}
}
}
}

Elasticsearch : Check if GeoPoint exists in the radius of multiple circles

My requirement is to check if a partucular geoPoint falls in radius of a circle or not.
I am using geoShape : circle to store the location. My document is as below:
PUT location_test/doc/1
{
"location" : {
"type" : "circle",
"coordinates" : [73.7769,18.5642],
"radius": "10mi"
}
}
and querying is as below :
GET location_test/_search
{
"query": {
"bool": {
"must": [
{
"geo_shape": {
"location": {
"shape": {
"type": "point",
"coordinates": [
73.877097,
18.455303
],
"relation": "contains"
}
}
}
}
]
}
}
}
This query works perfectly for single circle geo shape.
However now I want to check if a particular geoPoint falls in radius of multiple circles.
Can we have our document something like :
{
"location": [
{
"type": "circle",
"coordinates": [
73.7769,
18.5642
],
"radius": "10mi"
},
{
"type": "circle",
"coordinates": [
-118.240853,
34.052997
],
"radius": "10mi"
}
]
}
and have a query to check if a geoPoint falls in which circle.
Or is there any another way to achieve this ?
EDIT
Is it a good practice to use array of geo-points to sort documents for a particular geo-point ?
Mapping :
{
"mappings": {
"doc": {
"properties": {
"locationPoint": {
"type": "geo_point"
}
}
}
}
}
PUT location_test2/doc/1
{
"locationPoint": ["34.075433, -118.307228","36.336356,-119.304597"]
}
PUT location_test2/doc/2
{
"locationPoint": ["34.075433, -118.307228"]
}
GET location_test2/_search
{
"sort": [
{
"_geo_distance": {
"locationPoint": "34.075433, -118.307228",
"order": "asc"
}
}
]
}
You can surely have multiple circles in one document and the search is still going to match if any of the circles contain your point. Collapsing the steps for brevity:
PUT location_test
{"mappings":{"properties":{"location":{"type":"geo_shape","strategy":"recursive"}}}}
Taking in your array of circles:
PUT location_test/_doc/2
{"location":[{"type":"circle","coordinates":[73.7769,18.5642],"radius":"10mi"},{"type":"circle","coordinates":[-118.240853,34.052997],"radius":"10mi"}]}
Same query as for a single circle.
GET location_test/_search
{"query":{"bool":{"must":[{"geo_shape":{"location":{"shape":{"type":"point","coordinates":[73.7769,18.5642],"relation":"contains"}}}}]}}}
which yields our doc of interest. The counterintuitive but nice thing about this is that it does not matter if you provide a single object or a list of objects. ElasticSearch handles both without a mapping change.
Just note that your circles are on opposite sides of the globe:
If you're aware of this and querying your locations makes sense like this, all is fine.
From a performance standpoint keep in mind that circles are represented as polygons
which, depending on your ES version are represented as a bunch of triangles.
So you may want to index circle-like polygons instead of circles to maybe speed your indexing up or even think about merging your circles in a set of polygons (a MultiPolygon) because from what it looks like, your list of circles represents
related geometries.

Resources