微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

返回地理点数组的 Elasticsearch 距离

如何解决返回地理点数组的 Elasticsearch 距离

我需要在 Elasticsearch 数组中返回每个文档多个 地理点的距离。截至目前,我的结果仅返回为数组计算的一个距离。

我从以下 StackOverflow 问题中的代码开始: 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是一个数组。)

"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”中的每个条目返回一个值。

解决方法

这个很棘手。

根据 documentationsource codearcDistance 方法仅适用于 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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?