使用弹性搜索地理功能查找最常见的位置?

时间:2016-04-27 04:22:38

标签: amazon-web-services elasticsearch geolocation location geojson

我有一个geojson文件,其中包含每个都有经度,纬度和时间戳的位置列表。请注意经度和纬度乘以10000000。

{
  "locations" : [ {
    "timestampMs" : "1461820561530",
    "latitudeE7" : -378107308,
    "longitudeE7" : 1449654070,
    "accuracy" : 35,
    "junk_i_want_to_save_but_ignore" : [ { .. } ]
  }, {
    "timestampMs" : "1461820455813",
    "latitudeE7" : -378107279,
    "longitudeE7" : 1449673809,
    "accuracy" : 33
  }, {
    "timestampMs" : "1461820281089",
    "latitudeE7" : -378105184,
    "longitudeE7" : 1449254023,
    "accuracy" : 35
  }, {
    "timestampMs" : "1461820155814",
    "latitudeE7" : -378177434,
    "longitudeE7" : 1429653949,
    "accuracy" : 34
  }
  ..

这些位置中的许多位置将是相同的物理位置(例如用户的家)但显然经度和纬度可能不完全相同。

我想使用弹性搜索及其地理位置功能来生成最常见位置的排名列表,如果位置相距100米,那么位置被认为是相同的?

对于每个常见位置,如果可能的话,我也会喜欢他们在该位置的所有时间戳列表!

我非常感谢让我开始的示例查询!

非常感谢提前。

1 个答案:

答案 0 :(得分:1)

为了使其正常工作,您需要像这样修改映射:

PUT /locations
{
  "mappings": {
    "location": {
      "properties": {
        "location": {
          "type": "geo_point"
        },
        "timestampMs": {
          "type": "long"
        },
        "accuracy": {
          "type": "long"
        }
      }
    }
  }
}

然后,当您索引文档时,需要将纬度和经度除以10000000,并像这样索引:

PUT /locations/location/1
{
  "timestampMs": "1461820561530",
  "location": {
    "lat": -37.8103308,
    "lon": 14.4967407
  },
  "accuracy": 35
}

最后,您的搜索查询如下...

POST /locations/location/_search
{
  "aggregations": {
    "zoomedInView": {
      "filter": {
        "geo_bounding_box": {
          "location": {
            "top_left": "-37, 14",
            "bottom_right": "-38, 15"
          }
        }
      },
      "aggregations": {
        "zoom1": {
          "geohash_grid": {
            "field": "location",
            "precision": 6
          },
          "aggs": {
            "ts": {
              "date_histogram": {
                "field": "timestampMs",
                "interval": "15m",
                "format": "DDD yyyy-MM-dd HH:mm"
              }
            }
          }
        }
      }
    }
  }
}

...将产生以下结果:

{
  "aggregations": {
    "zoomedInView": {
      "doc_count": 1,
      "zoom1": {
        "buckets": [
          {
            "key": "k362cu",
            "doc_count": 1,
            "ts": {
              "buckets": [
                {
                  "key_as_string": "Thu 2016-04-28 05:15",
                  "key": 1461820500000,
                  "doc_count": 1
                }
              ]
            }
          }
        ]
      }
    }
  }
}

<强>更新

根据我们的讨论,这是一个可以为您服务的解决方案。使用Logstash,您可以调用API并检索大型JSON文档(使用http_poller input),提取/转换所有位置,并将它们很容易地汇入Elasticsearch(使用elasticsearch output)。

以下是我在初始答案中描述的格式化每个事件的方式。

  1. 使用http_poller您可以检索JSON位置(请注意,我已将轮询间隔设置为1天,但您可以将其更改为其他值,或者只需在每次需要时手动运行Logstash检索位置)
  2. 然后我们{locations 1}将locations数组转换为单个事件
  3. 然后我们将纬度/经度字段除以10,000,000以获得正确的坐标
  4. 我们还需要通过移动和删除一些字段来清理它
  5. 最后,我们只是将每个事件发送到Elasticsearch
  6. Logstash配置split

    locations.conf

    然后,您可以使用以下命令运行:

    input {
      http_poller {
        urls => {
          get_locations => {
            method => get
            url => "http://your_api.com/locations.json"
            headers => {
              Accept => "application/json"
            }
          }
        }
        request_timeout => 60
        interval => 86400000
        codec => "json"
      }
    }
    filter {
      split {
        field => "locations" 
      }
      ruby {
        code => "
          event['location'] = {
            'lat' => event['locations']['latitudeE7'] / 10000000.0,
            'lon' => event['locations']['longitudeE7'] / 10000000.0
          }
        "
      }
      mutate {
        add_field => {
          "timestampMs" => "%{[locations][timestampMs]}"
          "accuracy" => "%{[locations][accuracy]}"
          "junk_i_want_to_save_but_ignore" => "%{[locations][junk_i_want_to_save_but_ignore]}"
        }
        remove_field => [
          "locations", "@timestamp", "@version" 
        ]
      }
    }
    output {
      elasticsearch {
        hosts => ["localhost:9200"]
        index => "locations"
        document_type => "location"
      }
    }
    

    当它运行时,您可以启动搜索查询,您应该得到您期望的结果。