Find distance from a point to the n closest polygons in Elastic Search?

Viewed 606

This is similar to Find closest GeoJSON polygon to point when point lies outside of all polygons in Elasticsearch but instead of returning the closest polygon, I'd like to return all documents that has a polygon closer than a particular distance (say 10 km). I'd like the distance to each polygon to be included in the result and it should be sorted by distance (ascending or descending doesn't matter).

A comment in the referred question pointed to a github issue that has now been resolved (since Elastic Search 7.7) but I cannot seem to figure out how to do it based on the documentation.

Update

After reading the answer by joe I want to clarify that by "distance" I mean the closest distance to the nearest point of the polygon's border. Like what's described in this question for PostGIS.

1 Answers

You could use a geo_shape query with a buffered circle which will act as an umbrella that your polygons-of-interest will intersect. If they do, they match. The only issue is that the "distance to each polygon" is somewhat arbitrary -- are we talking about the nearest point of a polygon's border? Or maybe its center?

I've only been able to come up with an implementation of the latter but it requires a secondary center field since scripted center computation would be too onerous.

Here's a visual:

enter image description here

Set up an index:

PUT geo/
{
  "mappings": {
    "properties": {
      "polygon_field": {
        "type": "geo_shape"
      },
      "center_field": {
        "type": "geo_point"
      }
    }
  }
}

Sync 4 polygons w/ their centers:

POST _bulk
{"index":{"_index":"geo","_type":"_doc"}}
{"polygon_field":{"type":"Polygon","coordinates":[[[16.391773223876953,48.20248146453242],[16.389713287353516,48.19939223822629],[16.39812469482422,48.19721822655714],[16.39812469482422,48.200422001027874],[16.395721435546875,48.20248146453242],[16.391773223876953,48.20248146453242]]]},"center_field":[16.393918991088867,48.199849845544776]}
{"index":{"_index":"geo","_type":"_doc"}}
{"polygon_field":{"type":"Polygon","coordinates":[[[16.340789794921875,48.207172155652366],[16.333751678466797,48.203625575146994],[16.337528228759766,48.199735494793444],[16.34490966796875,48.19882013883662],[16.34490966796875,48.20293911184484],[16.341476440429688,48.20682894891699],[16.340789794921875,48.207172155652366]]]},"center_field":[16.339330673217773,48.20299614724449]}
{"index":{"_index":"geo","_type":"_doc"}}
{"polygon_field":{"type":"Polygon","coordinates":[[[16.37014389038086,48.23370651063653],[16.36585235595703,48.23061916787409],[16.369457244873047,48.2286751898296],[16.37683868408203,48.23119091206881],[16.374778747558594,48.233592167930034],[16.37014389038086,48.23370651063653]]]},"center_field":[16.37134552001953,48.23119085023306]}
{"index":{"_index":"geo","_type":"_doc"}}
{"polygon_field":{"type":"Polygon","coordinates":[[[16.47777557373047,48.14936662796115],[16.466102600097656,48.143868849060205],[16.475372314453125,48.13562107648419],[16.494598388671875,48.13493370228957],[16.494598388671875,48.144097934938884],[16.47777557373047,48.14936662796115]]]},"center_field":[16.480350494384766,48.14215016512536]}

Search & sort by the closest (against the center) ascending:

GET geo/_search
{
  "query": {
    "geo_shape": {
      "polygon_field": {
        "shape": {
          "type": "circle",
          "radius": "10km",
          "coordinates": [
            16.3704,
            48.21
          ]
        },
        "relation": "intersects"
      }
    }
  },
  "sort": [
    {
      "_geo_distance": {
        "center_field": [
          16.3704,
          48.21
        ],
        "order": "asc",
        "unit": "km",
        "mode": "min"
      }
    }
  ]
}
Related