Calculate geospatial distance in ElasticSearch 6.4 for multi value fields

Here's how to calculate the nearest distance from gps coordinates for a multi value field.


Applies to: ElasticSearch 6.4

Suppose you have items in ElasticSearch for a 'Brand'.
Each brand has mutiple stores. The locations are stored in a multi value field 'gps_locations'.

Suppose you want to know from an ElasticSearch query how close the nearest location is where you can get that brand.

ElasticSearch only offers a possibility to calculate the distance for the 'first' location in the multi value geopoint field.

Here's how to retrieve the 'nearest' location from a gps_locations field using a script query.


prototype/example model for a brand, stored in elasticsearch

{
  title: "brand title",
  gps_locations: [
     {lat: '...', lon: '...'},
     {lat: '...', lon: '...'},
     {lat: '...', lon: '...'},
     ....
  ]
}

ElasticSearch 6.4 script query to calculate the distance for the nearest geopoint from a given point (i.e. the user's location) using a script query

This would create a field 'min_distance' in the output, containing the distance to the location closest to lat/lon 52.3556740442177, 4.9525189115380996

{
  "query": {
      .......
  },
  "_source": [
      .......
  ],
  "script_fields": {
    "min_distance": {
      "script": {
        "lang": "painless",
        "source": "            double dist=9999999;\n            for (el in doc[\"gps_locations\"]) {\n                double lon1= el.lon;\n                double lat1= el.lat;\n                double lon2= params.plon;\n                double lat2= params.plat;\n                double theta = lon1 - lon2;\n                double cdist = Math.sin(Math.toRadians(lat1)) * Math.sin(Math.toRadians(lat2)) + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * Math.cos(Math.toRadians(theta));\n                cdist= Math.acos(cdist);\n                cdist= Math.toDegrees(cdist);\n                cdist= cdist * 60 * 1.1515;\n                cdist= cdist * 1609.344;\n                dist= Math.min(dist, cdist);\n            } \n            return dist;",
        "params": {
          "plat": 52.3556740442177,
          "plon": 4.9525189115380996
        }
      }
    }
  }
}