{"id":2154,"date":"2020-04-12T19:30:17","date_gmt":"2020-04-12T16:30:17","guid":{"rendered":"http:\/\/www.void.gr\/kargig\/blog\/?p=2154"},"modified":"2020-04-25T21:14:47","modified_gmt":"2020-04-25T18:14:47","slug":"graphing-covid-19-related-data-for-greece-using-elastic-elasticsearch-service","status":"publish","type":"post","link":"https:\/\/www.void.gr\/kargig\/blog\/2020\/04\/12\/graphing-covid-19-related-data-for-greece-using-elastic-elasticsearch-service\/","title":{"rendered":"Graphing Covid-19 related data for Greece using Elastic&#8217;s ElasticSearch Service"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">TL;DR<\/h2>\n\n\n\n<p><a href=\"https:\/\/covid19.void.gr\" class=\"aioseop-link\">https:\/\/covid19.void.gr<\/a><\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Intro<\/h2>\n\n\n\n<p>A few weeks ago I started converting the Covid-19 daily reports from <a aria-label=\" (opens in a new tab)\" href=\"https:\/\/eody.gov.gr\" target=\"_blank\" rel=\"noreferrer noopener\" class=\"aioseop-link\">Greek National Public Health Organization (EODY)<\/a> to json documents, and publishing them to Github in a repository called <a aria-label=\" (opens in a new tab)\" href=\"https:\/\/github.com\/kargig\/covid19-gr-json\/\" target=\"_blank\" rel=\"noreferrer noopener\" class=\"aioseop-link\">covid19-gr-json<\/a>. Reasoning behind this effort was that EODY does not publish their data in a reusable format, one that &#8220;machines&#8221; can easily read and parse. There are many websites that have created their own Covid-19 graphs but most of them have very basic stats (cases\/day, deaths\/day) and they state that their data sources are coming from media sources, without letting you access and re-use their original data. I haven&#8217;t been able to locate any other open data set regarding Covid-19 data for Greece that is not based on media sources but from official data coming out of EODY.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Report frequency and data consistency<\/h2>\n\n\n\n<p>After a few days of trying to convert these daily reports to json, EODY stopped publishing them. 3 days later EODY published another report with a different set of metrics than the previous reports. This new report did not have a per region analysis of cases and EODY also stopped publishing data for the number of hospitalized people or how many people have recovered. 4 more days passed without a report. Then EODY started publishing daily reports again, we&#8217;re now at 9 days in a row, but the metrics are again different than the previous ones published. There&#8217;s now a drill down by age and gender regarding cases, deaths and people in intensive care (IC). Still no mention of how many people have recovered though or how many are hospitalized but are not in IC. The result is that json files in the repository cannot be consistent since the original sources are not consistent. Such is life.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Visualizing data<\/h2>\n\n\n\n<p>A few days had passed since I started converting pdf reports to json and I wanted to see how easy it is to visualize some of it. Since data were in json format, the easiest thing for me to do was to store them to an Elasticsearch cluster and create visualizations using Kibana. Working at Elastic has its perks, I created a new Elastic stack deployment in <a href=\"https:\/\/www.elastic.co\/elasticsearch\/service\" class=\"aioseop-link\">ElasticSearch Service (ESS)<\/a>, and posted the json documents to it. I had to make a tough decision though, which graph tool from Kibana to use to visualize data. I started using <a href=\"https:\/\/www.elastic.co\/guide\/en\/kibana\/7.6\/most-frequent.html\" class=\"aioseop-link\">line graphs<\/a> but soon switched to <a aria-label=\" (opens in a new tab)\" href=\"https:\/\/www.elastic.co\/guide\/en\/kibana\/7.6\/TSVB.html\" target=\"_blank\" rel=\"noreferrer noopener\" class=\"aioseop-link\">Time Series Visual Builder (TSVB)<\/a> as it&#8217;s easier to use and allows to visualize multiple metrics\/time series in the same graph. I believe it&#8217;s producing way more beautiful visualizations anyway. After creating some visualizations I also created a dashboard, took some screenshots and shared them with friends.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Allowing access to dashboards<\/h2>\n\n\n\n<p>As people took notice of the json files in the repo they started pinging me to create some visualizations from them. I created a Kibana readonly user and shared the password with a few of them. That worked well for a couple of days, but sharing a password for a readonly view is a bit meeeh.  I wondered if I could create a password-less version of it and post the URL publicly. Publishing a URL in the form of <a href=\"https:\/\/abc123fe48752997c2da3b19.eu-central-1.aws.cloud.es.io:9243\/\" class=\"aioseop-link\">https:\/\/abc123fe48752c2da3b19.eu-central-1.aws.cloud.es.io:9243<\/a> is not exactly memorable either. I googled if it&#8217;s possible to post credentials to Kibana, and indeed it is. So nginx to the rescue!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Reverse proxy to ESS<\/h2>\n\n\n\n<p>I first tried to use a URL within <code>void.gr<\/code>, eg <code>void.gr\/covid19<\/code> to point directly to Kibana hosted on ESS. Because of the various <code>location<\/code> rules already used in my <code>void.gr<\/code> nginx config this quickly became more complicated than it had to, so I created a new subdomain for it, <code>covid19.void.gr<\/code>. Here&#8217;s the reverse proxy config:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><pre><code2>&nbsp;&nbsp;&nbsp;&nbsp;location \/ {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_pass https:\/\/abc123fe48752997c2da3b19.eu-central-1.aws.cloud.es.io:9243;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_http_version 1.1;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_set_header Upgrade $http_upgrade;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_set_header Connection &#039;upgrade&#039;;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_set_header Host $proxy_host;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_cache_bypass $http_upgrade;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_set_header&nbsp;&nbsp;X-Real-IP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $remote_addr; # pass on real client&#039;s IP\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_set_header&nbsp;&nbsp;X-Forwarded-For&nbsp;&nbsp; $proxy_add_x_forwarded_for;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_set_header&nbsp;&nbsp;X-Forwarded-Proto $scheme;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;auth_basic &quot;Basic Auth&quot;;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_set_header Authorization &quot;Basic bXl1c2VyOm15cGFzcw==&quot;; # base64-encoded username:password to pass in header\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_set_header x-forwarded-user $remote_user;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_hide_header kbn-license-sig;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_hide_header kbn-xpack-sig;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_hide_header kbn-name;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_hide_header x-found-handling-server;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_hide_header x-found-handling-instance;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_hide_header x-found-handling-cluster;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_hide_header x-cloud-request-id;\n&nbsp;&nbsp;&nbsp;&nbsp;}<\/code2><\/pre><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Authorization header<\/h3>\n\n\n\n<p>Authentication is based on the base64 encoded output of <code>username:password<\/code> combination which is to be posted to Kibana.  Create it via:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><pre><code2>$ echo -n myuser:mypass | base64\nbXl1c2VyOm15cGFzcw==<\/code2><\/pre><\/pre>\n\n\n\n<p>Adding these 2 config options is enough for nginx reverse proxy to authenticate to Kibana:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><pre><code2>auth_basic &quot;Basic Auth&quot;;\nproxy_set_header Authorization &quot;Basic bXl1c2VyOm15cGFzcw==&quot;;<\/code2><\/pre><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Header removal<\/h3>\n\n\n\n<p>While not strictly necessary, I think it&#8217;s a good practice to remove non-essential headers being sent back to the browser via the reverse proxy.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">End Result<\/h2>\n\n\n\n<p>One Let&#8217;s Encrypt certificate later and tada! <a href=\"https:\/\/covid19.void.gr\" class=\"aioseop-link\">https:\/\/covid19.void.gr<\/a> is live!<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/covid19.void.gr\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"535\" src=\"https:\/\/www.void.gr\/kargig\/blog\/wp-content\/image-1024x535.png\" alt=\"\" class=\"wp-image-2160\" srcset=\"https:\/\/www.void.gr\/kargig\/blog\/wp-content\/image-1024x535.png 1024w, https:\/\/www.void.gr\/kargig\/blog\/wp-content\/image-300x157.png 300w, https:\/\/www.void.gr\/kargig\/blog\/wp-content\/image-768x401.png 768w, https:\/\/www.void.gr\/kargig\/blog\/wp-content\/image.png 1254w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/covid19.void.gr\/app\/kibana#\/dashboard\/167ac6b0-6cef-11ea-a176-abf156a6badf\"><img loading=\"lazy\" decoding=\"async\" width=\"863\" height=\"1024\" src=\"https:\/\/www.void.gr\/kargig\/blog\/wp-content\/covid19-void-gr-app-kibana-dashboard-863x1024.png\" alt=\"\" class=\"wp-image-2161\" srcset=\"https:\/\/www.void.gr\/kargig\/blog\/wp-content\/covid19-void-gr-app-kibana-dashboard-863x1024.png 863w, https:\/\/www.void.gr\/kargig\/blog\/wp-content\/covid19-void-gr-app-kibana-dashboard-253x300.png 253w, https:\/\/www.void.gr\/kargig\/blog\/wp-content\/covid19-void-gr-app-kibana-dashboard-768x912.png 768w, https:\/\/www.void.gr\/kargig\/blog\/wp-content\/covid19-void-gr-app-kibana-dashboard-1294x1536.png 1294w, https:\/\/www.void.gr\/kargig\/blog\/wp-content\/covid19-void-gr-app-kibana-dashboard-1725x2048.png 1725w, https:\/\/www.void.gr\/kargig\/blog\/wp-content\/covid19-void-gr-app-kibana-dashboard.png 1918w\" sizes=\"auto, (max-width: 863px) 100vw, 863px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Contribution<\/h2>\n\n\n\n<p>Do you want to contribute either by converting EODY&#8217;s reports to json or by improving the above visualizations dashboards ? leave a comment, <a aria-label=\" (opens in a new tab)\" href=\"https:\/\/www.void.gr\/kargig\/blog\/contact\/\" target=\"_blank\" rel=\"noreferrer noopener\" class=\"aioseop-link\">send an email<\/a> or <a aria-label=\"ping me via twitter (opens in a new tab)\" href=\"https:\/\/twitter.com\/kargig\" target=\"_blank\" rel=\"noreferrer noopener\" class=\"aioseop-link\">ping me via twitter<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>TL;DR https:\/\/covid19.void.gr Intro A few weeks ago I started converting the Covid-19 daily reports from Greek National Public Health Organization (EODY) to json documents, and publishing them to Github in a repository called covid19-gr-json. Reasoning behind this effort was that EODY does not publish their data in a reusable format, one that &#8220;machines&#8221; can easily [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ep_exclude_from_search":false,"footnotes":""},"categories":[1,11],"tags":[625,624,628,630,627,631,626,632,629],"class_list":["post-2154","post","type-post","status-publish","format-standard","hentry","category-general","category-greek","tag-covid-19","tag-covid19","tag-data","tag-elastic","tag-eody","tag-ess","tag-greece","tag-tsvb","tag-visualizations"],"aioseo_notices":[],"views":11389,"_links":{"self":[{"href":"https:\/\/www.void.gr\/kargig\/blog\/wp-json\/wp\/v2\/posts\/2154","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.void.gr\/kargig\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.void.gr\/kargig\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.void.gr\/kargig\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.void.gr\/kargig\/blog\/wp-json\/wp\/v2\/comments?post=2154"}],"version-history":[{"count":30,"href":"https:\/\/www.void.gr\/kargig\/blog\/wp-json\/wp\/v2\/posts\/2154\/revisions"}],"predecessor-version":[{"id":2190,"href":"https:\/\/www.void.gr\/kargig\/blog\/wp-json\/wp\/v2\/posts\/2154\/revisions\/2190"}],"wp:attachment":[{"href":"https:\/\/www.void.gr\/kargig\/blog\/wp-json\/wp\/v2\/media?parent=2154"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.void.gr\/kargig\/blog\/wp-json\/wp\/v2\/categories?post=2154"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.void.gr\/kargig\/blog\/wp-json\/wp\/v2\/tags?post=2154"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}