Analyze car traffic with Elasticsearch and Kibana

Posted by Markus Benning on June 14, 2016

There are currently a lot of construction sites on the my way to work. Therefor i wanted to know when the traffic jams start to occur and whats the best time to get to work.

Google Maps show current traffic on their routing service and “Hey!” there is a API for it: https://developers.google.com/maps/documentation/directions/. You just have to apply for API key there and they give you 2500 queries a day for free.

I started querying the data with curl. Since its a REST API thats really easy:

curl -X GET 'https://maps.googleapis.com/maps/api/directions/json?key=<your-key>&origin=<home>&destination=<work>&mode=driving&departure_time=now

That will output a lot of JSON data to your screen. And since elasticsearch is schema-less and also uses JSON getting the data into elasticsearch is also really easy. Just pipe the data into another curl command:

<previous-curl> | curl 'http://localhost:9200/traffic/work/' -d '@-'

That will already works, but to build up time series a timestamp is needed within each document. A small script was needed to reformat the document before pushing it to the elasticsearch index:

#!/usr/bin/env perl

use strict;
use warnings;

use LWP::UserAgent;
use JSON;
use Time::Piece;
use Search::Elasticsearch;
use URI;

sub usage {
  print "usage: $0 <from> <to>\n"
}

if( scalar(@ARGV) != 2 ) {
  usage;
  exit 1;
}

my $from = $ARGV[0];
my $to = $ARGV[1];

my $url = URI->new('https://maps.googleapis.com/maps/api/directions/json');
$url->query_form(
  key => '<your-key>',
  mode => 'driving',
  departure_time => 'now',
  origin => $from,
  destination => $to,
);

my $ua = LWP::UserAgent->new;

my $response = $ua->get($url);
if ( ! $response->is_success ) {
  die('could not retrieve data: '.$response->status_line);
}
my $data = from_json( $response->content );

my $es = Search::Elasticsearch->new( nodes => [ 'localhost:9200' ] );

$es->index(
  index   => 'traffic',
  type    => 'google_traffic',
  body    => {
    '@timestamp' => Time::Piece->gmtime->datetime,
    from => $from,
    to => $to,
    %$data,
  }
);

Next step was to run this script every 10 minutes in a cronjob:

*/10 * * * * perl <path>/google-traffic '<from>' '<to>'

And to create a simple visualization in kibana based on the routes.legs.duration_in_traffic.value field:

car traffic plot