首页 文章

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

提问于
浏览
1

我有一个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
  }
  ..

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

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

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

我非常感谢一个让我入门的示例查询!

提前谢谢了 .

1 回答

  • 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
                    }
                  ]
                }
              }
            ]
          }
        }
      }
    }
    

    UPDATE

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

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

    • 使用 http_poller 您可以检索JSON位置(请注意,我已将轮询间隔设置为1天,但您可以将其更改为其他值,或者只是每次要检索位置时手动运行Logstash)

    • 然后我们将 split 位置数组转换为单个事件

    • 然后我们将纬度/经度字段除以10,000,000以获得正确的坐标

    • 我们还需要通过移动和移除一些字段来清理它

    • 最后,我们只是将每个事件发送给Elasticsearch

    Logstash配置 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"
      }
    }
    

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

    bin/logstash -f locations.conf
    

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

相关问题