Search code examples
elasticsearchopensearch

Return the unique address sorted by shortest distance to an input lat long in OpenSearch/ElasticSearch


I have a database with following sample.

  "_index" : "python-address-test",
    "_type" : "_doc",
    "_id" : "1",
    "_score" : 0.0,
    "_source" : {
      "address" : "Graha Blok A",
      "geohash6" : "qqgft0",
      "location" : {
        "lat" : -6.5881896,
        "lon" : 106.747485
      }
    }
  },
  {
    "_index" : "python-address-test",
    "_type" : "_doc",
    "_id" : "2",
    "_score" : 0.0,
    "_source" : {
      "address" : "Graha",
      "geohash6" : "qqgft0",
      "location" : {
        "lat" : -6.5895002,
        "lon" : 106.7488968
      }
    }
  },
  {
    "_index" : "python-address-test",
    "_type" : "_doc",
    "_id" : "3",
    "_score" : 0.0,
    "_source" : {
      "address" : "Graha",
      "geohash6" : "qqgft0",
      "location" : {
        "lat" : -6.5884867,
        "lon" : 106.749212

Expected Return shall be, where the address shall be unique

{Graha Block A, Graha}

I have written following code, and able to get the address with shortest distance to an input lat, long. However I was unable to get the Unique Address. Please advise

{ "size": 10, 
  "query": {
    "bool": {
      "must": {
        "geo_distance": {
          "distance": "1km",
          "location": [
            106.7485418,
            -6.5875987
          ]
        }
      },
      "filter": {"match" : {"geohash6" : "qqgft0"}}
    }
  },
  "sort": [
    "_score",
    {
      "_geo_distance": {
        "location": { 
          "lat":  -6.5875987,
          "lon": 106.7485418
        },
        "order":         "asc",
        "unit":          "m", 
        "distance_type": "plane" 
      }
    }
  ]
}

Solution

  • You can use collapse query to only show 1 result per address:

    https://www.elastic.co/guide/en/elasticsearch/reference/current/collapse-search-results.html

    Here is the example code:

    Mappings

    PUT test_geo
    {
      "mappings": {
        "properties": {
          "address": {
            "type": "text",
            "fields": {
              "keyword": {
                "type":"keyword"
              }
            }
          },
          "geohash6": {
            "type": "keyword"
          },
          "location": {
            "type": "geo_point"
          }
        }
      }
    }
    

    Documents

    POST test_geo/_doc
    {
      "address": "Graha Blok A",
      "geohash6": "qqgft0",
      "location": {
        "lat": -6.5881896,
        "lon": 106.747485
      }
    }
    
    POST test_geo/_doc
    {
      "address": "Graha Blok A",
      "geohash6": "qqgft0",
      "location": {
        "lat": -6.5881896,
        "lon": 106.747485
      }
    }
    
    POST test_geo/_doc
    {
      "address": "Graha",
      "geohash6": "qqgft0",
      "location": {
        "lat": -6.5895002,
        "lon": 106.7488968
      }
    }
    

    Query

    GET test_geo/_search
    {
      "size": 10,
      "collapse": {
        "field": "address.keyword"
      }, 
      "query": {
        "bool": {
          "must": {
            "geo_distance": {
              "distance": "1km",
              "location": [
                106.7485418,
                -6.5875987
              ]
            }
          },
          "filter": {
            "match": {
              "geohash6": "qqgft0"
            }
          }
        }
      },
      "sort": [
        "_score",
        {
          "_geo_distance": {
            "location": {
              "lat": -6.5875987,
              "lon": 106.7485418
            },
            "order": "asc",
            "unit": "m",
            "distance_type": "plane"
          }
        }
      ]
    }
    

    Results

    {
      "took": 3,
      "timed_out": false,
      "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
      },
      "hits": {
        "total": {
          "value": 3,
          "relation": "eq"
        },
        "max_score": null,
        "hits": [
          {
            "_index": "test_geo",
            "_id": "PBC34oQBtNG1OrZokQMs",
            "_score": 1,
            "_source": {
              "address": "Graha Blok A",
              "geohash6": "qqgft0",
              "location": {
                "lat": -6.5881896,
                "lon": 106.747485
              }
            },
            "fields": {
              "address.keyword": [
                "Graha Blok A"
              ]
            },
            "sort": [
              1,
              133.96461555682822
            ]
          },
          {
            "_index": "test_geo",
            "_id": "hHa34oQB5Gw0WET8m33u",
            "_score": 1,
            "_source": {
              "address": "Graha",
              "geohash6": "qqgft0",
              "location": {
                "lat": -6.5895002,
                "lon": 106.7488968
              }
            },
            "fields": {
              "address.keyword": [
                "Graha"
              ]
            },
            "sort": [
              1,
              215.04628939232288
            ]
          }
        ]
      }
    }