使用弹性搜索地理功能从XML原始数据中查找最常见的位置

时间:2016-05-03 15:58:42

标签: xml amazon-web-services elasticsearch geolocation logstash

我想使用弹性搜索及其地理位置功能来生成最常见位置的排序有序列表,如果位置在一周中的某一天内彼此相距100米,则认为这些位置相同

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

在一周中的每一天考虑的数据应该是整个数据期间(一个月)的一周中的同一天。例如,在恰好是星期二的日期搜索公共位置,我们应该查询上周二,周二之前,周二之前和周二之前的数据(!)[也许这可以通过使用ES来实现索引?]。

对于每个搜索日,我还想要一个直方图,它在距离该位置100米的所有时间内的准确度为15分钟,包括一周中同一天的最后4周数据。

我们只能在一天内制作API原始数据请求(因此需要多次请求才能获得最后四周的数据)。我们控制之外的第三方API将以下列格式返回XML - 所有这些都在一行上并且未格式化(我手动格式化下面的示例)。坐标是(经度,纬度)格式。最后一位(下例中为0)表示高度,如果可能,应存储。

<?xml version="1.0" encoding="UTF-8"?>
<kml>
   <Document>
      [stuff we don't care about]
      <Day>
         [stuff we don't care about]
         <Locations>
        [stuff we don't care about]
            <time>2016-04-30T19:35:01.558+10:00</time>
            <coord>142.9987247 -37.328203799999996 0</coord>
            <time>2016-05-02T12:29:21.233+10:00</time>
            <coord>142.96122699999998 -37.921569999999996 0</coord>
            ....
         </Locations>
      </Day>
   </Document>
</kml>

非常感谢。

1 个答案:

答案 0 :(得分:1)

other question类似,可以很容易地解析给定的XML并将结果位置索引到elasticsearch中。有一些XML解析要做,然后执行一些数据按钮以提取数据,但这是可能的。

我在下面提出了非常简单的Logstash配置:

input {
  http_poller {
    urls => {
      get_locations => {
        method => get
        url => "http://your-api.com/locations.xml"
        headers => {
          Accept => "application/xml"
        }
      }
    }
    request_timeout => 60
    interval => 60
    codec => "plain"
  }
}
filter {
  # 1. parse XML
  xml {
    source => "message"
    force_array => false
    target => "parsed"
  }

  # 2. parse time/coord arrays and rebuild pairs
  ruby {
    code => "
      event['locations'] = []
      event['parsed']['Document']['Day']['Locations']['time'].each { |time|
        event['locations'].push({'time' => time, 'location' => nil})
      }
      event['parsed']['Document']['Day']['Locations']['coord'].each_with_index { |coord, i|
        event['locations'][i]['location'] = {
          'lon' => coord.split(' ')[0],
          'lat' => coord.split(' ')[1]
        }
      }
    "
  }

  # 3. produce one event per time/coord pair
  split {
    field => "locations"
  }

  # 4. Some renaming and clean-ups    
  mutate {
    rename => {
      "[locations][time]" => "timestampMs"
      "[locations][location]" => "location"
    }
    remove_field => [
      "parsed", "message", "@timestamp", "@version", "locations"
    ]
  }
}
output {
  elasticsearch {
    hosts => ["localhost:9200"]
    index => "locations"
    document_type => "location"
  }
}

首先,我使用http_poller输入来提取XML数据

然后,我使用xml过滤器将XML解析为JSON。您提供的XML将产生以下JSON:

 {
    "Document" => {
        "Day" => {
            "Locations" => {
                 "time" => [
                    [0] "2016-04-30T19:35:01.558+10:00",
                    [1] "2016-05-02T12:29:21.233+10:00"
                ],
                "coord" => [
                    [0] "142.9987247 -37.328203799999996 0",
                    [1] "142.96122699999998 -37.921569999999996 0"
                ]
            }
        }
    }

正如您所看到的,由于笨拙的XML组织,timecoord值都在各自的数组中粘合在一起。

然后我利用ruby过滤器将其全部拆分,并将每个time重新统一到其相应的coord值。我基本上迭代每个数组并重新构造正确的time/coord对并将它们存储到新的locations数组中。请注意,当前版本的Elasticsearch中的高度部分为not yet supported

然后我split新的locations数组,以便为​​每time/coord对生成一个事件。

最后,我正在进行一些清理工作,将被编入Elasticsearch索引的事件如下所示:

{
 "timestampMs" => "2016-04-30T19:35:01.558+10:00",
    "location" => {
         "lon" => "142.9987247",
         "lat" => "-37.328203799999996"
    }
}
{
 "timestampMs" => "2016-05-02T12:29:21.233+10:00",
    "location" => {
         "lon" => "142.96122699999998",
         "lat" => "-37.921569999999996"
    }
}

然后,您可以运行bin/logstash -f locations.conf以运行管道。

有了这个,您就可以重复使用与other question中相同的聚合,这样就可以了。

相关问题