如何解决返回地理点数组的 Elasticsearch 距离
我需要在 Elasticsearch 数组中返回每个文档多个 地理点的距离。截至目前,我的结果仅返回为数组计算的一个距离。
我从以下 StackOverflow 问题中的代码开始: Return distance in elasticsearch results?
{
"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是一个数组。)
"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
},"state_province": "Florida","postal_code": "33613"
}
}
}
]
目前,我的结果返回类似于以下内容:
"fields": {
"distance": [
13952.518249603361
]
}
但是在距离数组中,我需要为“locations”中的每个条目返回一个值。
解决方法
这个很棘手。
根据 documentation 和 source code,arcDistance
方法仅适用于 doc values,而不适用于这些文档值背后的单个 geo point instances .
换句话说,虽然我们可以在 doc['locations.facility.address.coordinates']
上迭代,但迭代器并没有实现 any geo distance methods。
那是一个无赖。所以我们必须实现我们自己的地理距离函数,也许 using haversine 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。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。