{"id":2425,"date":"2015-07-24T11:18:34","date_gmt":"2015-07-24T09:18:34","guid":{"rendered":"https:\/\/test.viaboxx.de\/2015\/07\/24\/easily-generate-live-heatmaps-for-geolocations-with-elk\/"},"modified":"2021-08-10T21:38:55","modified_gmt":"2021-08-10T21:38:55","slug":"easily-generate-live-heatmaps-for-geolocations-with-elk","status":"publish","type":"post","link":"https:\/\/www.viaboxx.de\/en\/blog\/easily-generate-live-heatmaps-for-geolocations-with-elk\/","title":{"rendered":"Easily generate live heatmaps for geolocations with ELK"},"content":{"rendered":"<p>Here at Viaboxx we are using the ELK Stack (<a href=\"https:\/\/www.elastic.co\/products\/elasticsearch\">Elasticsearch<\/a>, <a href=\"https:\/\/www.elastic.co\/products\/logstash\">Logstash<\/a> and <a href=\"https:\/\/www.elastic.co\/products\/kibana\">Kibana<\/a>) to have a centralised but scalable logging infrastructure. In this blog you will learn how to use this stack to easily have a heat map for geo coordinates.<\/p>\n<p><strong>Context<\/strong><\/p>\n<p>In our software we are using \u00a0the <a href=\"https:\/\/github.com\/logstash\/logstash-logback-encoder\">Logstash-Logback encoder\u00a0<\/a>\u00a0to directly have JSON\u00a0logs ready for logstash. Those are either directly send to Logstash (behind a Redis queue) or saved to a file and send via the Logstash-Forwarder, depending on the infrastructure and firewalls.<\/p>\n<p>Those logs are then preprocessed in Logstash and stored in the Elasticsearch document store. We are using the new Kibana 4 web interface to allow searching through the logs of all hosts or visualise log metrics.<\/p>\n<p>One of our products is a <strong>route optimizer<\/strong>, which uses\u00a0geodata for tour optimization. Kibana 4 provides a heatmap visualization right out of the box, one just needs to have the data prepared for it to work.<\/p>\n<p>If you don&#8217;t have the geodata already in Elasticsearch, don&#8217;t hesitate!\u00a0If you have the ELK stack and you have a CSV files of geolocations you can generate your heatmap in a few lines of code.<\/p>\n<p><strong>Tutorial<\/strong><\/p>\n<p>Let&#8217;s say you have a simple CSV &#8216;test.csv&#8217; with just latitudes and longitudes, the heatmap should indicate how often a geolocation was found in the data (within a distance).<\/p>\n<pre>[codesyntax lang=\"text\"]<\/pre>\n<pre>#Latitude, Longitude\n50.98474812, 7.47645034\n50.98474812, 7.47645034\n50.98474812, 7.47645034\n50.62703234,7.74493172\n50.96807514, 6.99762216\n50.78432438,7.64722746\n51.13014686,7.01966161\n50.55503241,6.56177651\n50.68262437,7.5592885\n50.59502431,6.46768414\n50.59502431,6.46768414\n50.55442372,7.60962654\n50.66100656,6.45276664\n50.66100656,6.45276664\n51.05079311,6.77458391\n50.93658508,6.70941164\n50.50670651,6.69422478<\/pre>\n<pre>[\/codesyntax]<\/pre>\n<p>We will process this data with\u00a0a small Logstash configuration, which stores the data into Elasticsearch. Kibana 4 does not directly visualise the latitude and longitude of a document, but requires a geohash instead (nicely described \u00a0in <a href=\"https:\/\/www.elastic.co\/guide\/en\/elasticsearch\/guide\/current\/geohash-mapping.html\">this documentation<\/a>). This geohash needs to be mapped in advance before storing data.<\/p>\n<p>At first, we will\u00a0create the index in Elasticsearch and define the geohash mapping. Let&#8217;s name the index &#8220;<em>geostore<\/em>&#8221; and the document will be named &#8220;<em>locality<\/em>&#8221; with a property named &#8220;<em>location<\/em>&#8220;. We will assume the you are on the ELK host and are using the default ports (maybe you have it run locally via Docker).<\/p>\n<pre>$ curl -XPUT 'http:\/\/localhost:9200\/geostore'<\/pre>\n<pre>$ curl -XPUT 'http:\/\/localhost:9200\/geostore\/_mapping\/locality' -d '\n{\n   \"locality\" : {\n       \"properties\" : {\n              \"location\" : {\n                  \"type\" : \"geo_point\",\n                  \"geohash_prefix\":     true,\n                  \"geohash_precision\":  \"1km\"\n              }\n          }\n       }\n}'<\/pre>\n<p>This mapping of location defines that it is of type <em>geo_point<\/em>, and it defines the precision of the geohash. If you want to have a finer or coarse comparison, change this value accordingly to your needs.<\/p>\n<p>If later you need to restart configuring the mapping, delete the index and start again. This is the easiest way in this example, don&#8217;t do this in production. This command deletes the index:<\/p>\n<pre>$ curl -XDELETE 'http:\/\/localhost:9200\/geostore'\n<\/pre>\n<p>Now that we have the Elasticsearch index ready, we can configure Logstash to directly store the data of the &#8220;<em>test.csv<\/em>&#8221; into the &#8220;<em>geostore<\/em>&#8221; \u00a0index.<\/p>\n<p>This is the config (named &#8220;<em>geostore.conf<\/em>&#8220;) required for \u00a0our Logstash setup:<\/p>\n<pre>[codesyntax lang=\"text\"]<\/pre>\n<pre>input {\n    stdin {}\n}\nfilter {\n  # Step 1, drop the csv header line\n  if [message] =~ \/^#\/ {\n    drop {}\n  }\n  \n  # Step 2, split latitude and longitude\n  csv {\n    separator =&gt; ','\n    columns =&gt; [ 'lat', 'lon' ]\n  }\n\n  # Step 3\n  # move lat and lon into location object \n  # for defined geo_point type in ES\n  mutate {  \n    rename =&gt; [ \"lat\", \"[location][lat]\", \"lon\", \"[location][lon]\" ]\n  }\n}\noutput {\n  elasticsearch {\n    host =&gt; 'localhost'\n    index =&gt; 'geostore'\n    document_type  =&gt; \"locality\"\n    flush_size =&gt; 1000\n    protocol =&gt; 'http'\n  }\n}<\/pre>\n<pre>[\/codesyntax]<\/pre>\n<p>This will parse the csv (given as standard input), drop the header line and parse the latitude and longitude values.<\/p>\n<p>The mutate moves <em>lat<\/em>\u00a0and <em>lon<\/em>\u00a0into the location object that we have predefined to be a <em>geo_type<\/em>. This is the most important line, as this is already the correct structure that Elasticsearch and Kibana 4 expect.<\/p>\n<p>On the host, with Logstash just execute:<\/p>\n<pre>$ cat test.csv | \/opt\/logstash\/bin\/logstash -f geostore.conf<\/pre>\n<p>This will take a few seconds to startup logstash, parse the input and store the result into Elasticsearch.<\/p>\n<p>Now that we have the data in Elasticsearch, let&#8217;s move to Kibana 4. After logged into Kibana, you need to add the index to Kibana.<\/p>\n<p>Go to: <em>Settings -&gt; Indices -&gt; Add New -&gt; Write<\/em>\u00a0&#8220;<em>geostore<\/em>&#8221; in the index name field.<\/p>\n<p>After you add the index, you&#8217;ll see all fields in \u00a0the documents of the index, especially you should check if the property <em>location<\/em>\u00a0is \u00a0classified as geo_point.<\/p>\n<figure id=\"attachment_2426\" aria-describedby=\"caption-attachment-2426\" style=\"width: 300px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.viaboxx.de\/wp-content\/uploads\/2015\/07\/Kibana-IndicesSettings.png\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-2426 size-medium\" src=\"http:\/\/www.viaboxx.de\/wp-content\/uploads\/2015\/07\/Kibana-IndicesSettings-300x225.png\" alt=\"Kibana-IndicesSettings\" width=\"300\" height=\"225\" \/><\/a><figcaption id=\"caption-attachment-2426\" class=\"wp-caption-text\">Properties identified in the defined geostore Index of Elasticsearch<\/figcaption><\/figure>\n<p>Now we are nearly done, go to<em> Visualize -&gt; Tile map -&gt; From a new search -&gt; Select &#8220;geostore&#8221;<\/em> index.<\/p>\n<p>The default value as metric is count, this counts how often a geohash is counted in the index with the given time interval.<\/p>\n<p>Select as bucket type &#8220;<em>Geo coordinates<\/em>&#8221; and then already <em>geohash<\/em>\u00a0should be selected as aggregation and <em>location<\/em>\u00a0as field. The default visualisation for a Tile map is a circled view. As we want to have a heatmap, \u00a0select &#8220;<em>options<\/em>&#8221; and change the map type to &#8220;<em>heatmap<\/em>&#8220;. \u00a0After pressing &#8220;<em>Apply \u00a0changes<\/em>&#8221; you will already see the map and can zoom in to \u00a0see the different locations as a heat map! Congratulations!<\/p>\n<figure id=\"attachment_2427\" aria-describedby=\"caption-attachment-2427\" style=\"width: 604px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.viaboxx.de\/wp-content\/uploads\/2015\/07\/kibana4-exampleheatmap.png\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-2427 size-large\" src=\"http:\/\/www.viaboxx.de\/wp-content\/uploads\/2015\/07\/kibana4-exampleheatmap-1024x617.png\" alt=\"kibana4-exampleheatmap\" width=\"604\" height=\"364\" \/><\/a><figcaption id=\"caption-attachment-2427\" class=\"wp-caption-text\">Kibana 4 showing the geostore heatmap.<\/figcaption><\/figure>\n<p>If you don&#8217;t see the data, make sure the change the time interval that Kibana uses for its query (on the top right). The default is 15 minutes into the past. Depending on when you imported the data into Elasticsearch. This feature really shines if you have geo locations in your production data and for example want to see which areas where the focus of deliveries in the last week.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Here at Viaboxx we are using the ELK Stack (Elasticsearch, Logstash and Kibana) to have a centralised but scalable logging infrastructure. In this blog you will [&hellip;]<\/p>\n","protected":false},"author":4,"featured_media":6952,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_uag_custom_page_level_css":"","site-sidebar-layout":"default","site-content-layout":"default","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"default","adv-header-id-meta":"","stick-header-meta":"default","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[76],"tags":[84,85,86,87,88],"class_list":["post-2425","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-code","tag-elasticsearch","tag-geolocation","tag-heatmap","tag-kibana","tag-logstash"],"uagb_featured_image_src":{"full":["https:\/\/www.viaboxx.de\/wp-content\/uploads\/2015\/07\/Blog-Post-easily-generate-live-heatmaps-for-geolocations-with-elk.jpg",2200,700,false],"thumbnail":["https:\/\/www.viaboxx.de\/wp-content\/uploads\/2015\/07\/Blog-Post-easily-generate-live-heatmaps-for-geolocations-with-elk-150x150.jpg",150,150,true],"medium":["https:\/\/www.viaboxx.de\/wp-content\/uploads\/2015\/07\/Blog-Post-easily-generate-live-heatmaps-for-geolocations-with-elk-300x95.jpg",300,95,true],"medium_large":["https:\/\/www.viaboxx.de\/wp-content\/uploads\/2015\/07\/Blog-Post-easily-generate-live-heatmaps-for-geolocations-with-elk-768x244.jpg",768,244,true],"large":["https:\/\/www.viaboxx.de\/wp-content\/uploads\/2015\/07\/Blog-Post-easily-generate-live-heatmaps-for-geolocations-with-elk-1024x326.jpg",1024,326,true],"1536x1536":["https:\/\/www.viaboxx.de\/wp-content\/uploads\/2015\/07\/Blog-Post-easily-generate-live-heatmaps-for-geolocations-with-elk-1536x489.jpg",1536,489,true],"2048x2048":["https:\/\/www.viaboxx.de\/wp-content\/uploads\/2015\/07\/Blog-Post-easily-generate-live-heatmaps-for-geolocations-with-elk-2048x652.jpg",2048,652,true]},"uagb_author_info":{"display_name":"Jan Nonnen","author_link":"https:\/\/www.viaboxx.de\/en\/blog\/author\/jan-nonnenviaboxx-de\/"},"uagb_comment_info":2,"uagb_excerpt":"Here at Viaboxx we are using the ELK Stack (Elasticsearch, Logstash and Kibana) to have a centralised but scalable logging infrastructure. In this blog you will [&hellip;]","_links":{"self":[{"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/posts\/2425"}],"collection":[{"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/comments?post=2425"}],"version-history":[{"count":6,"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/posts\/2425\/revisions"}],"predecessor-version":[{"id":6950,"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/posts\/2425\/revisions\/6950"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/media\/6952"}],"wp:attachment":[{"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/media?parent=2425"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/categories?post=2425"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/tags?post=2425"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}