Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to know if a geo coordinate lies within a geo polygon in elasticsearch?

I am using elastic search 1.4.1 - 1.4.4. I'm trying to index a geo polygon shape (document) into my index and now when the shape is indexed i want to know if a geo coordinate lies within the boundaries of that particular indexed geo-polygon shape.

GET /city/_search
{
"query":{
    "filtered" : {
        "query" : {
            "match_all" : {}
        },
        "filter" : {
            "geo_polygon" : {
                "location" : {
                    "points" : [
                        [72.776491, 19.259634],
                        [72.955705, 19.268060],
                        [72.945406, 19.189611],
                        [72.987291, 19.169507],
                        [72.963945, 19.069596],
                        [72.914506, 18.994300],
                        [72.873994, 19.007933],
                        [72.817689, 18.896882],
                        [72.816316, 18.941052],
                        [72.816316, 19.113720],
                        [72.816316, 19.113720],
                        [72.790224, 19.192205],
                        [72.776491, 19.259634]
                    ]
                }
            }
        }
    }
}
}

With above geo polygon filter i'm able get all indexed geo-coordinates lies within described polygon but i also need to know if a non-indexed geo-coordinate lies with in this geo polygon or not. My doubt is that if that is possible in the elastic search 1.4.1.

like image 550
Manjit Kumar Avatar asked Apr 03 '15 06:04

Manjit Kumar


1 Answers

Yes, Percolator can be used to solve this problem.

As in normal use case of Elasticsearch, we index our docs into elasticsearch and then we run queries on indexed data to retrieve matched/ required documents.

But percolators works in a different way of it.

In percolators you register your queries and then you percolate your documents through registered queries and gets back the queries which matches your documents.

After going through infinite number of google results and many of blogs i wasn't able to find any thing which could explain how i can use percolators to solve this problem.

So i'm explaining this with an example so that other people facing same problem can take a hint from my problem and the solution i found. I would like if someone can improve my answer or can share a better approach of doing it.

e.g:-

First of all we need to create an index.

PUT /city/

then, we need to add a mapping for user document which consist a user's latitude-longitude for percolating against registered queries.

PUT /city/user/_mapping
{
    "user" : {
        "properties" : {
            "location" : {
                "type" : "geo_point"
            }
        }
    }
}

Now, we can register our geo polygon queries as percolators with id as city name or any other identifier you want to.

PUT /city/.percolator/mumbai
{
    "query":{
        "filtered" : {
            "query" : {
                "match_all" : {}
            },
            "filter" : {
                "geo_polygon" : {
                    "location" : {
                        "points" : [
                            [72.776491, 19.259634],
                            [72.955705, 19.268060],
                            [72.945406, 19.189611],
                            [72.987291, 19.169507],
                            [72.963945, 19.069596],
                            [72.914506, 18.994300],
                            [72.873994, 19.007933],
                            [72.817689, 18.896882],
                            [72.816316, 18.941052],
                            [72.816316, 19.113720],
                            [72.816316, 19.113720],
                            [72.790224, 19.192205],
                            [72.776491, 19.259634]
                        ]
                    }
                }
            }
        }
    }
}

Let's register another geo polygon filter for another city

PUT /city/.percolator/delhi
{
    "query":{
        "filtered" : {
            "query" : {
                "match_all" : {}
            },
            "filter" : {
                "geo_polygon" : {
                    "location" : {
                        "points" : [
                            [76.846998, 28.865160],
                            [77.274092, 28.841104],
                            [77.282331, 28.753252],
                            [77.482832, 28.596619],
                            [77.131269, 28.395064],
                            [76.846998, 28.865160]
                        ]
                    }
                }
            }
        }
    }
}

Now we have registered 2 queries as percolators and we can make sure by making this API call.

GET /city/.percolator/_count

Now to know if a geo point exist with any of registered cities we can percolate a user document using below query.

GET /city/user/_percolate
{
  "doc": {
        "location" : {
            "lat" : 19.088415,
            "lon" : 72.871248
             }
          }
}

This will return : _id as "mumbai"

{
   "took": 25,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "total": 1,
   "matches": [
      {
         "_index": "city",
         "_id": "mumbai"
      }
   ]
}

trying another query with different lat-lon

GET /city/user/_percolate
{
  "doc": {
        "location" : {
            "lat" : 28.539933,
            "lon" : 77.331770
             }
          }
    }

This will return : _id as "delhi"

{
   "took": 25,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "total": 1,
   "matches": [
      {
         "_index": "city",
         "_id": "delhi"
      }
   ]
}

Let's run another query with random lat-lon

GET /city/user/_percolate
{
  "doc": {
        "location" : {
            "lat" : 18.539933,
            "lon" : 45.331770
             }
          }
}

and this query will return no matched results.

{
   "took": 5,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "total": 0,
   "matches": []
}
like image 161
Manjit Kumar Avatar answered Oct 16 '22 09:10

Manjit Kumar