【问题标题】:Return Elasticsearch distance for array of geo points返回地理点数组的 Elasticsearch 距离
【发布时间】:2021-01-31 17:51:49
【问题描述】:

我需要返回 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": [
    {
      "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
      ]
    }

但在距离数组中,我需要为“位置”中的每个条目返回一个值。

【问题讨论】:

    标签: elasticsearch elasticsearch-painless elasticsearch-scripting


    【解决方案1】:

    这个很棘手。

    根据documentationsource codearcDistance 方法仅适用于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

    【讨论】:

      猜你喜欢
      • 2017-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-18
      • 2012-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多