Elasticsearch - return polygons in a given point (relation": "intersects returns union instead) - elasticsearch

I have multiple polygons in the index and I'm trying to return all the polygons in a given point.
But my query returns all the docs in the index even if it doesn't falls in polygon 1.
It gives me union instead of intersect.
Query is given below
Map Ref. http://geojson.io/#map=7/-31.775/144.382
PUT /example3
{
"mappings": {
"_doc": {
"properties": {
"features": {
"properties": {
"geometry": {
"type": "geo_shape"
}
}
}
}
}
}
}
Sample data:
{
"type": "Feature",
"geometry": {
"name": "Poly - 04",
"type": "Polygon",
"coordinates": [
[
[
144.91670608520508,
-37.82524314302977
],
[
144.96846199035645,
-37.82524314302977
],
[
144.96846199035645,
-37.78787789236923
],
[
144.91670608520508,
-37.78787789236923
],
[
144.91670608520508,
-37.82524314302977
]
]
]
}
}
Query:
GET /example3/_search
{
"query":{
"bool": {
"must": {
"match_all": {}
},
"filter": {
"geo_shape": {
"features.geometry": {
"relation": "intersects",
"shape": {
"type": "point",
"coordinates" :
[
146.0138,
-37.1734
]
}
}
}
}
}
}
}

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

Elasticsearch get intersection of coordinates

I have the an index field, with which, given a set of coordinates for a polygon, I want to get any fields that intersect those coordinates. Is this possible given the structure of the field index using elasticsearch geo location features? I am using elasticsearch version 7.9
{
"geo_json": {
"geometry": {
"coordinates": [
[
[
2.1228971832029644,
41.3011586218355
],
[
2.122596585111679,
41.3012384865674
],
[
2.1221786804481835,
41.30191870980272
],
[
2.1223509744761158,
41.302042636348716
],
[
2.1226735685285507,
41.30192972550523
],
[
2.1232820963718857,
41.30165984025794
],
[
2.1232820963718857,
41.30131559725024
],
[
2.1228971832029644,
41.3011586218355
]
]
],
"type": "Polygon"
},
"properties": null,
"type": "Feature"
},
"name": "Barcelona"
}
I have tried the following query, with returned error "Field [geo_json.geometry.coordinates] is of unsupported type [float]. [geo_shape] query supports the following types [geo_shape,geo_point]"
GET field/_search
{
"query": {
"bool": {
"filter": {
"geo_shape": {
"geo_json.geometry.coordinates": {
"shape": {
"type": "polygon",
"coordinates": [
[
[
2.1228971832029644,
41.3011586218355
],
[
2.122596585111679,
41.3012384865674
],
[
2.1221786804481835,
41.30191870980272
],
[
2.1223509744761158,
41.302042636348716
],
[
2.1226735685285507,
41.30192972550523
],
[
2.1232820963718857,
41.30165984025794
],
[
2.1232820963718857,
41.30131559725024
],
[
2.1228971832029644,
41.3011586218355
]
]
]
},
"relation": "intersects"
}
}
}
}
}
}
It surely is possible. Adapting my previous answer to your use case:
Set up the index mapping
PUT geoindex
{
"mappings": {
"properties": {
"area": {
"type": "float"
},
"center": {
"type": "geo_point"
},
"geo_json": {
"type": "geo_shape"
},
"name": {
"type": "text"
}
}
}
}
Add the Barcelona polygon
POST geoindex/_doc
{
"area": 5380.8444064004625,
"center": [ 2.1227303884100346, 41.30160062909211 ],
"geo_json": {
"type": "polygon",
"coordinates": [[[2.1228971832029644,41.3011586218355],[2.122596585111679,41.3012384865674],[2.1221786804481835,41.30191870980272],[2.1223509744761158,41.302042636348716],[2.1226735685285507,41.30192972550523],[2.1232820963718857,41.30165984025794],[2.1232820963718857,41.30131559725024],[2.1228971832029644,41.3011586218355]]]
},
"name": "Barcelona"
}
Check for the intersection (the query polygon is yellow):
POST geoindex/_search
{
"query": {
"geo_shape": {
"geo_json": {
"relation": "intersects",
"shape": {
"type": "polygon",
"coordinates": [[[2.122421264648437,41.30061251600798],[2.123579978942871,41.300354591849114],[2.123579978942871,41.30120896171846],[2.122957706451416,41.30129762210163],[2.122421264648437,41.30061251600798]]]
}
}
}
}
}

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.

Distinct values from array-field matching filter in Elasticsearch 2.4

In short: I want to lookup for distinct values in some field of the document BUT only matching some filter. The problem is in array-fields.
Imagine there are following documents in ES 2.4:
[
{
"states": [
"Washington (US-WA)",
"California (US-CA)"
]
},
{
"states": [
"Washington (US-WA)"
]
}
]
I'd like my users to be able to lookup all possible states via typeahead, so I have the following query for the "wa" user request:
{
"query": {
"wildcard": {
"states.raw": "*wa*"
}
},
"aggregations": {
"typed": {
"terms": {
"field": "states.raw"
},
"aggregations": {
"typed_hits": {
"top_hits": {
"_source": { "includes": ["states"] }
}
}
}
}
}
}
states.raw is a sub-field with not_analyzed option
This query works pretty well unless I have an array of values like in the example - it returns both Washington and California. I do understand why it happens (query and aggregations are working on top of the document and the document contains both, even though only one option matched the filter), but I really want to only see Washington and don't want to add another layer of filtering on the application side for the ES results.
Is there a way to do so via single ES 2.4 request?
You could use the "Filtering Values" feature (see https://www.elastic.co/guide/en/elasticsearch/reference/2.4/search-aggregations-bucket-terms-aggregation.html#_filtering_values_2).
So, your request could look like:
POST /index/collection/_search?size=0
{
"aggregations": {
"typed": {
"terms": {
"field": "states.raw",
"include": ".*wa.*" // You need to carefully quote the "wa" string because it'll be used as part of RegExp
},
"aggregations": {
"typed_hits": {
"top_hits": {
"_source": { "includes": ["states"] }
}
}
}
}
}
}
I can't hold myself back, though, and not tell you that using wildcard with leading wildcard is not the best solution. Do, please please, consider using ngrams for this:
PUT states
{
"settings": {
"analysis": {
"filter": {
"ngrams": {
"type": "nGram",
"min_gram": "2",
"max_gram": "20"
}
},
"analyzer": {
"ngram_analyzer": {
"type": "custom",
"filter": [
"standard",
"lowercase",
"ngrams"
],
"tokenizer": "standard"
}
}
}
},
"mappings": {
"doc": {
"properties": {
"location": {
"properties": {
"states": {
"type": "string",
"fields": {
"raw": {
"type": "string",
"index": "not_analyzed"
},
"ngrams": {
"type": "string",
"analyzer": "ngram_analyzer"
}
}
}
}
}
}
}
}
}
POST states/doc/1
{
"text":"bla1",
"location": [
{
"states": [
"Washington (US-WA)",
"California (US-CA)"
]
},
{
"states": [
"Washington (US-WA)"
]
}
]
}
POST states/doc/2
{
"text":"bla2",
"location": [
{
"states": [
"Washington (US-WA)",
"California (US-CA)"
]
}
]
}
POST states/doc/3
{
"text":"bla3",
"location": [
{
"states": [
"California (US-CA)"
]
},
{
"states": [
"Illinois (US-IL)"
]
}
]
}
And the final query:
GET states/_search
{
"query": {
"term": {
"location.states.ngrams": {
"value": "sh"
}
}
},
"aggregations": {
"filtering_states": {
"terms": {
"field": "location.states.raw",
"include": ".*sh.*"
},
"aggs": {
"typed_hits": {
"top_hits": {
"_source": {
"includes": [
"location.states"
]
}
}
}
}
}
}
}

Elasticsearch nested query and order by "hits"

Using Elasticsearch, I'm trying to search nested data and return the documents with the most "hits."
Relevant Example Data
POST myrecipes/recipe
{
"title": "Potato Salad",
"ingredients": [
{"name":"potato"},
{"name":"mayonaise"},
{"name":"mustard"},
{"name":"bacon"},
{"name":"onion"},
{"name":"parsley"}
]
}
POST myrecipes/recipe
{
"title": "Seared Scallops",
"ingredients": [
{"name":"scallops"},
{"name":"butter"},
{"name":"bacon"}
]
}
POST myrecipes/recipe
{
"title": "Tuna melt",
"ingredients": [
{"name":"tuna"},
{"name":"onion"},
{"name":"butter"},
{"name":"bacon"},
{"name":"mayonaise"},
{"name":"lettuce"},
{"name":"tomato"},
{"name":"bread"}
]
}
My Index
PUT myrecipes
{
"mappings": {
"recipe": {
"properties": {
"ingredients": {
"type": "nested",
"include_in_parent": true,
"properties": {
"name": {
"type": "string",
"fields": {
"untouched": {
"type": "string",
"index": "not_analyzed"
}
}
}
}
}
}
}
}
}
My Search:
POST myrecipes/recipe/_search
{
"query": {
"nested": {
"path": "ingredients",
"query": {
"bool": {
"should": [
{
"match": {
"ingredients.name": {
"query": "bacon"
}
}
},
{
"match": {
"ingredients.name": {
"query": "butter"
}
}
}
]
}
}
}
}
}
The query returns
"Tuna melt", "Potato Salad", "Seared Scallops"
I'm hoping for:
"Seared Scallops", "Tuna melt", "Potato Salad"
Since there are two "hits" on "Seared scallops" and "Tuna Melt" (bacon and butter), and only one "hit" on "Potato Salad" (bacon).

Resources