FeatureCollection to geo_shape in Elasticsearch - elasticsearch

Whats the right way to translate a geojson FeatureCollection to a es geo_shape?
I have a FeatureCollection looking like this:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[[1.96, 42.455],[1.985,42.445]]]
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [...]
}
}
]
}
How can I translate this into the es geo_shape.
Currently I just index it like that (dropping type: Feature and type: FeatureCollection fields) and add a mapping saying:
"features": {
"geometry": {
"type": "geo_shape"
}
}
This seems to work fine, but feels wrong, as I give an array of geometrys.
Is this okay or would the right way be to translate the FeatureCollection to type geometrycollection? Which clearly wants multiple geometry elements.
One Followup question, can I do a query a la: Give me all elements geometrically inside Element X(where X is also in the index) in one query, without fetching X and than doing multiple follow up queries for each polygon?

The GeometryCollection is probably what you're looking for.
So if you have this:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[[1.96, 42.455],[1.985,42.445]]]
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [...]
}
}
]
}
You can index it in ES like this:
PUT example
{
"mappings": {
"doc": {
"properties": {
"location": {
"type": "geo_shape"
}
}
}
}
}
POST /example/doc
{
"location" : {
"type": "geometrycollection",
"geometries": [
{
"type": "Polygon",
"coordinates": [[[1.96, 42.455],[1.985,42.445]]]
},
{
"type": "Polygon",
"coordinates": [...]
}
]
}
}
So basically, you simply need to:
change FeatureCollection to geometrycollection
change features to geometries
populate the geometries array with the geometry inner-objects
Regarding your query, you can do it like this:
POST /example/_search
{
"query":{
"bool": {
"filter": {
"geo_shape": {
"location": {
"shape": {
"type": "envelope",
"coordinates" : [[13.0, 53.0], [14.0, 52.0]]
},
"relation": "within"
}
}
}
}
}
}
The within relationship returns all documents whose geo_shape field is within the geometry given in the query.

Related

what is the best way to find available points(merchants) around a point(user) if these points(merchants) use different radius in Elasticsearch

I used geo_shape for this problem, want to know if there are some other better ways(faster) to solve this problem, ES version is 6.5.
mapping:
{
"index": {
"mappings": {
"merchant": {
"_all": {
"enabled": false
},
"properties": {
"delivery_circle": {
"type": "geo_shape",
"tree": "quadtree",
"precision": "50.0m",
"distance_error_pct": 0.025
}
}
}
}
}
}
document example:
{
"_source": {
"id": 1,
"delivery_circle": {
"coordinates": [ // merchant location, its radius is 4km
123.456,
1.2345
],
"radius": "4000m",
"type": "circle"
}
}
}
{
"_source": {
"id": 2,
"delivery_circle": {
"coordinates": [ // merchant location, its radius is 5km
123.567,
1.3456
],
"radius": "5000m",
"type": "circle"
}
}
}
search query example:
{
"query": {
"bool": {
"filter": [
{
"geo_shape": {
"delivery_circle": {
"relation": "contains",
"shape": {
"coordinates": [ // user location
123,
1
],
"type": "point"
}
}
}
}
]
}
}
}
This is off topic suggestion, but you can consider using geohash for the same. This can reduce your search time complexity.
https://en.wikipedia.org/wiki/Geohash

Find coordinates in a polygon

How can I find polygons that stored in elastic index.
Simple mapping:
PUT /regions
{
"mappings": {
"properties": {
"location": {
"type": "geo_shape"
}
}
}
}
And simple polygon:
/regions/_doc/1
{
"location" : {
"type" : "polygon",
"coordinates" : [
[
[53.847332102970626,27.485155519098047],
[53.84626875748117,27.487134989351038],
[53.8449047241684,27.48501067981124],
[53.84612634308789,27.482945378869765],
[53.847411219859,27.48502677306532],
[53.847332102970626,27.485155519098047]
]
]
}
}
According to documentation I can only search coordinates within polygon only if the polygon is contained in the request Geo-polygon query, but I need to find polygons by coordinates in query. Elasticsearch 7.6 version.
Query:
{
"query": {
"match_all": {}
},
"filter": {
"geo_shape": {
"geometry": {
"shape": {
"coordinates": [
53.846415,
27.485756
],
"type": "point"
},
"relation": "whithin"
}
}
}
}
You were on the right path but your query was heavily malformed. Here's the fix:
{
"query": {
"bool": {
"filter": {
"geo_shape": {
"location": {
"shape": {
"coordinates": [
53.846415,
27.485756
],
"type": "point"
},
"relation": "intersects"
}
}
}
}
}
}
Notice how I used intersects instead of within. The reason is explained in this GIS StackExchange answer.

Elasticsearch geosearch with distance preference

Sorry for the noob question... I have Restaurant objects in Elasticsearch 2.3, each has a GeoPoint and a home delivery distance preference. In pseudocode
restaurant: {
location: (x, y)
deliveryPreference: 10km
}
and a user:
user {
location: (a,b)
}
How would I issue a search for a user looking for all restaurants that can deliver in his area?
The solution involves using geo_shapes. You need to model the restaurant documents as follows:
PUT restaurants
{
"mappings": {
"restaurant": {
"properties": {
"name": {
"type": "text"
},
"location": {
"type": "geo_point"
},
"delivery_area": {
"type": "geo_shape",
"tree": "quadtree",
"precision": "1m"
}
}
}
}
}
You can then index your restaurants as follows:
POST /restaurants/restaurant/1
{
"name": "My Food place",
"location": [-45.0, 45.0], <-- lon, lat !!!
"delivery_area": {
"type": "circle",
"coordinates" : [-45.0, 45.0], <-- lon, lat !!!
"radius" : "10km"
}
}
Each restaurant will thus be associated with a circle shape centered on its location and with a proper radius.
Finally, when a user wants to know which restaurant can deliver at the location she is currently at, you can issue the following geo_shape query:
POST /restaurants/_search
{
"query":{
"bool": {
"filter": {
"geo_shape": {
"delivery_area": {
"shape": {
"type": "point",
"coordinates" : [<user_lon>, <user_lat>]
},
"relation": "contains"
}
}
}
}
}
}
In this query, we are retrieving restaurants whose delivery_area shape contains the point the user is currently located at.
Index the restraunts documents with following mappings
{
"mappings": {
"type_name": {
"properties": {
"name": {
"type": "text"
},
"location": {
"type": "text"
},
"location_geo": {
"type": "geo_point"
}
}
}
}
}
Use geo_filter query
{
"query": {
"bool": {
"filter": {
"geo_distance": {
"distance": "10km",
"location_geo": {
"lat": 40,
"lon": -70
}
}
}
}
}
}

Elasticsearch - find points inside huge geo shape

I have 'shapes' index that stores a lot of huge geoshapes (original shapefile for one geoshape was 6MB in size).
I'm using this mapping:
"shape": {
"type": "geo_shape",
"tree": "quadtree",
"tree_levels": "20"
},
"_all": {
"enabled": false
},
"dynamic": "true"
I also have 'photos' index. Each photo have latitude and longitude presented as geoshape with type Point.
e.g.
"location": {
"type": "Point",
"coordinates": [
-103.262600,
43.685315
]
}
Mapping for it:
"location": {
"type": "geo_shape",
"tree": "quadtree",
"tree_levels": 20
}
I'm trying to find all photos that located inside selected shape by using following query:
GET photos/_search
{
"query": {
"filtered": {
"filter": {
"geo_shape": {
"location": {
"relation": "intersects",
"indexed_shape": {
"id": "huge_region_shape_id",
"type": "country",
"index": "shapes",
"path": "shape"
}
}
}
},
"query": {
"match_all": {}
}
}
}
}
Issues:
1) On a huge shapes this query executes several minutes or forever.
2) Just searching shapes by some parameters takes a lot of time if "shape" included into source, but if I exclude it - geo_shape filter will throw an exception - "Shape found but missing field"
In mapping:
_source: {
excludes : ['shape']
}
Is there some way to solve this issues?

How do I use Elasticsearch's geo_point and geo_shape types at the same time?

Here is our document:
{
"geometry" : {
"type" : "Point",
"coordinates" : [ -87.662682, 41.843014 ]
}
}
We'd like to do a geo_shape search with a _geo_distance sort, both against the same geometry field. The former requiresgeo_shape types while the latter requires geo_point.
These two indexes succeed individually, but not together:
"geometry": {
"type": "geo_shape"
}
and
"geometry": {
"properties": {
"coordinates": {
"type": "geo_point"
}
}
},
So far we've tried these and failed:
"geometry": {
"type": "geo_shape"
},
"geometry.coordinates": {
"type": "geo_point"
},
also
"geometry": {
"copy_to": "geometryShape",
"type": "geo_shape"
},
"geometryShape": {
"properties": {
"coordinates": {
"type": "geo_point"
}
}
}
also
"geometry": {
"copy_to": "geometryShape",
"properties": {
"coordinates": {
"type": "geo_point"
}
}
},
"geometryShape": {
"type": "geo_shape"
}
Any ideas on how to create this index properly?
If scripting is enabled then you could achieve it via specifying transforms in mapping
would look something on these lines :
put test/test_type/_mapping
{
"transform": {
"script": "if (ctx._source['geometry']['coordinates']) ctx._source['test'] = ctx._source['geometry']['coordinates']",
"lang": "groovy"
},
"properties": {
"geometry": {
"type": "geo_shape"
},
"coordinates": {
"type": "geo_point"
}
}
}
I'd go with a function_score_query and your original mapping with just the geo_shape. Elasticsearch docs suggest that scoring by distance is usually better than sorting by distance.
On another note, have you checked out using a geo_bounding_box with a geo_point? I'm not sure exactly what you're using the geo_shape type for but you may be able to replicate it using the bounding box. Check out an example here.

Resources