如何在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
相关产品推荐
相关产品推荐

