使用弹性搜索地理功能查找最常见的位置?
Posted
技术标签:
【中文标题】使用弹性搜索地理功能查找最常见的位置?【英文标题】:Using Elastic Search Geo Functionality To Find Most Common Locations? 【发布时间】:2016-08-21 04:28:44 【问题描述】:我有一个 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
..
其中许多位置将是相同的物理位置(例如用户的家),但显然经度和纬度可能不完全相同。
我想使用 Elastic Search 及其地理功能来生成最常见位置的排名列表,如果位置在彼此之间(例如 100m)之内,则这些位置被认为是相同的?
对于每个常见位置,如果可能的话,我还想要他们在该位置的所有时间戳的列表!
非常感谢一个示例查询让我开始!
非常感谢。
【问题讨论】:
您能否展示一个示例文档和您的映射?让人们更容易引导您的问题并尝试解决它。 嗨,瓦尔。好点子!我已经包含了上面的示例数据。 如果此 GeoJSON 数据被正确索引,那么您可以使用geohash_grid
聚合来查看每个位置在二维空间(约 100m 矩形)中的分布情况。您还可以将其与 date_histogram
聚合结合起来,看看这些点是如何及时分布的。
优秀的 Val,听起来很完美。我对 Elastic Search 和 Geo 的东西完全陌生,所以我会看看我是否可以提出一个查询并让你知道它是否有效。
首先,确保正确索引您的数据。这样的事情应该可以帮助您入门:"location":"lat":40,"lon":70, "timestamp": 1458432895726, "accuracy": 15
,其中location
是geo_point
,timestamp
和accuracy
是long
【参考方案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)非常容易。
这是按照我最初的回答中所述格式化每个事件的方法。
-
使用
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
运行后,您可以启动搜索查询,您应该会得到您所期望的结果。
【讨论】:
感谢 Val,太好了!获取每个桶中所有时间戳的列表不是一件容易的事吗? 你想要每个时间戳,还是想要按分钟、小时、天对它们进行分组,然后简单地按组获取有多少? 嗨 Val,关于分组的好主意。如果可以按星期几、小时和 15 分钟的间隔对它们进行分组,那就太棒了!例如星期一 06 15-29: 3 意味着在上午 6 点 15 分到 6 点 29 分之间的任何一个星期一都有 3 场活动,但我认为这很难吗? 由于我无法控制源数据,因此是否可以使用脚本将我的 E7 数字转换为传统的经纬度数据来获取数据。干杯! 我已经用date_histogram
子聚合更新了我的答案,它完全符合您的需要,即按 15 分钟的时间段存储所有时间戳以上是关于使用弹性搜索地理功能查找最常见的位置?的主要内容,如果未能解决你的问题,请参考以下文章