首页 > 解决方案 > Elasticsearch 自定义地理距离过滤器

问题描述

从 Elasticsearch 查询中,我想检索可变距离内的所有点。假设我有 2 家商店,一家愿意在最长 3 公里的范围内送货,另一家愿意在最长 5 公里的范围内送货:

PUT /my_shops/_doc/1
{
    "location": {
      "lat": 40.12,
      "lon": -71.34
    },
    "max_delivery_distance": 3000
}

PUT /my_shops/_doc/2
{
    "location": {
      "lat": 41.12,
      "lon": -72.34
    },
    "max_delivery_distance": 5000
}

对于给定的位置,我想知道哪些商店可以送货。如果给定位置在 3 公里以内,IE 查询应该返回 shop1,如果给定位置在 5 公里以内,则返回 shop2

GET /my_shops/_search
{
  "query": {
    "bool": {
      "must": {
        "match_all": {}
      },
      "filter": {
        "geo_distance": {
          "distance": max_delivery_distance,
          "location": {
            "lat": 40,
            "lon": -70
          }
        }
      }
    }
  }
}

标签: elasticsearchfilterdistance

解决方案


我认为您需要使用脚本才能使用另一个字段作为参数。经过一番研究,我得出了这个答案:

GET my_shops/_search
{
  "query": {
    "script": {
      "script": {
        "params": {
          "location": {
            "lat": 40,
            "lon": -70
          }
        },
        "source": """
      return doc['location'].arcDistance(params.location.lat, params.location.lon)/1000 <= doc['max_delivery_distance'].value"""
      }
    }
  }
}

基本上,我们利用与 GEO 点相关的类在无痛https://github.com/elastic/elasticsearch/pull/40180/中列入白名单的事实,并且脚本接受其他参数(您的固定位置)。

根据 arcDistance 的文档,我们以米为单位检索大小,因此您需要将该值除以 1000 转换为 km。

附加说明

我假设 location 和 max_delivery_distance 总是(对于每个文档)定义的。如果不是这种情况,您需要覆盖这种情况。

参考


推荐阅读