You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在OpenSearch/ElasticSearch中按距离排序并返回唯一地址

问题描述

我在OpenSearch/ElasticSearch中有如下索引数据:

{
  "_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
    }
  }
}

需要根据输入经纬度(106.7485418, -6.5875987)返回按最近距离排序的唯一地址,预期结果为{Graha Blok A, Graha}。目前的查询语句能按距离排序获取地址,但无法实现地址去重:

{ 
  "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" 
      }
    }
  ]
}
解决方法

要实现按距离排序的地址去重,可以用ElasticSearch/OpenSearch的terms聚合结合top_hits子聚合,核心逻辑是按地址分组、保留每组内最近的文档、再按距离排序。

最终查询语句

{
  "size": 0, // 不返回原始文档,只取聚合结果
  "query": {
    "bool": {
      "must": {
        "geo_distance": {
          "distance": "1km",
          "location": [106.7485418, -6.5875987]
        }
      },
      "filter": {"match": {"geohash6": "qqgft0"}}
    }
  },
  "aggs": {
    "unique_address": {
      "terms": {
        "field": "address.keyword", // 用keyword类型字段做精确聚合去重
        "size": 10,
        "order": {
          "closest_distance": "asc" // 按每组的最近距离升序排序
        }
      },
      "aggs": {
        "closest_distance": {
          "min": {
            "script": {
              "source": "doc['location'].arcDistance(params.lat, params.lon)",
              "params": {
                "lat": -6.5875987,
                "lon": 106.7485418
              }
            }
          }
        },
        "closest_doc": {
          "top_hits": {
            "size": 1, // 每组只保留最近的1条文档
            "_source": ["address"],
            "sort": [
              {
                "_geo_distance": {
                  "location": {
                    "lat": -6.5875987,
                    "lon": 106.7485418
                  },
                  "order": "asc",
                  "unit": "m",
                  "distance_type": "plane"
                }
              }
            ]
          }
        }
      }
    }
  }
}

结果说明

聚合结果会返回按距离排序的唯一地址分组,每个分组包含该地址的最近距离和对应文档,提取address字段就能得到预期的["Graha Blok A", "Graha"]。

注意事项

  • 确保address字段有keyword子字段(若为text类型),否则无法精确聚合;如果字段本身是keyword类型,直接用address即可。
  • size:0用于减少不必要的数据传输,若需要查看原始文档可调整该值,但不影响聚合结果。

内容的提问来源于stack exchange,提问作者SoraHeart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 19:05:24