返回地理点数组的 Elasticsearch 距离
Posted
技术标签:
【中文标题】返回地理点数组的 Elasticsearch 距离【英文标题】:Return Elasticsearch distance for array of geo points 【发布时间】:2021-01-31 17:51:49 【问题描述】:我需要返回 Elasticsearch 数组中每个文档的 多个 地理点的距离。到目前为止,我的结果只返回为数组计算的一个距离。
我从以下 *** 问题的代码开始: Return distance in elasticsearch results?
我的 elasticsearch 查询正文包含以下内容:
"stored_fields" : [ "_source" ],
"script_fields" :
"distance" :
"script" :
"inline": "doc['locations.facility.address.coordinates'].arcDistance(params.lat,params.lon) * 0.001",
"lang": "painless",
"params":
"lat": 2.27,
"lon": 50.3
而且,我的 Elasticsearch 源文档在返回时与此类似。 (注意位置是一个数组。)
"locations": [
"facility":
"address":
"country_code": "US",
"city": "San Diego",
"coordinates":
"lon": -117.165,
"lat": 32.8408
,
"country_name": "United States",
"state_province": "California",
"postal_code": "92123"
,
"facility":
"address":
"country_code": "US",
"city": "Tampa",
"coordinates":
"lon": -82.505,
"lat": 28.0831
,
"country_name": "United States",
"state_province": "Florida",
"postal_code": "33613"
]
目前,我的结果返回类似于以下内容:
"fields":
"distance": [
13952.518249603361
]
但在距离数组中,我需要为“位置”中的每个条目返回一个值。
【问题讨论】:
【参考方案1】:这个很棘手。
根据documentation 和source code,arcDistance
方法仅适用于doc values,而不适用于这些文档值基础的单个geo point instances。
换句话说,虽然我们可以在 doc['locations.facility.address.coordinates']
上进行迭代,但被迭代的对象并没有实现 any geo distance methods。
这真是太糟糕了。所以我们必须实现我们自己的地理距离函数,也许是usinghaversine formula:
"stored_fields": [
"_source"
],
"script_fields":
"distance":
"script":
"inline": """
float distFrom(float lat1, float lng1, float lat2, float lng2)
double earthRadius = 6371000; // meters
double dLat = Math.toRadians(lat2-lat1);
double dLng = Math.toRadians(lng2-lng1);
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
Math.sin(dLng/2) * Math.sin(dLng/2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
float dist = (float) (earthRadius * c);
return dist;
return params._source.locations.stream().map(location ->
def lat = (float) location.facility.address.coordinates.lat;
def lon = (float) location.facility.address.coordinates.lon;
return distFrom(lat, lon, (float) params.lat, (float) params.lon) * 0.001;
).collect(Collectors.toList())
""",
"lang": "painless",
"params":
"lat": 2.27,
"lon": 50.3
屈服
"hits" :
...
"hits" : [
...
"_source" :
"locations" : [
... ,
...
]
,
"fields" :
"distance" : [
15894.470000000001,
13952.498
]
]
说实话,当需要编写这么多脚本时,有些事情出了问题。
一般来说,脚本should be avoided。
但更重要的是,当您不按这些地理距离排序时,整个计算工作应该在 Elasticsearch 外部完成 - 而不是在您所在的地方重新对搜索结果进行后处理。例如,我使用 Turf 进行 javascript 地理计算。
最后,当您将多个位置/设施存储在一个数组中时,我建议使用nested
fields。它们防止数组扁平化,并支持sorting that makes sense。
【讨论】:
以上是关于返回地理点数组的 Elasticsearch 距离的主要内容,如果未能解决你的问题,请参考以下文章
Elasticsearch:在 Elasticsearch 中按距离有效地对地理点进行排序
Elasticsearch:在 Elasticsearch 中按距离有效地对地理点进行排序