Support medical cases with the Elastic Stack

November 8, 2018

In my previous article, I have introduced one of the geospatial capabilities of Elasticsearch. In this article, we continue with geo-distance analysis and geo-coverage in the area of Health in Switzerland.

The State of Health in Switzerland

Switzerland has one of the highest life expectancies in the world and provides high medical coverage. The number of doctors and nurses are also high, with 4.2 doctors and 18 nurses per 1'000 people (compared to respective OECD averages of 3.4 and 9).

Sources:

The Data

One thing that elastic and mimacom has in common is: We all come in different shapes with different interests and skills. This article is a co-production. My co-worker Riccardo Causo contributed to the data and idea. Riccardo is passionate about data science and GIS (Geographic Information System). Together we research and analyse the data for this use case.

We look for data on hospitals. Switzerland has an open government data initiative. We could find the most recent data set from 2016 from opendata.swiss. The data itself is from the Federal Office of Public Health. Before the import in Elasticsearch, we process (scrub and clean) the data.

Analysis in Kibana

The existing data is sufficient for our demonstration. Let's look at one document.

{
  "_index": "hospitals",
  "_type": "doc",
  "_id": "029ACB0036221C766371E0526A56CAC0118D9B83",
  "_version": 3,
  "_score": 4.359518,
  "_source": {
    "name": "Insel Gruppe AG (nicht-universitär)",
    "canton": "BE",
    "services": [
      "AMBULANCE",
      "STATION"
    ],
    "address": "Freiburgstrasse 18,3010 Bern",
    "location": {
      "lat": 46.9473414,
      "lon": 7.424962199999999
    },
    "typology": {
      "text_it": "Ospedali per cure generali, presa a carico centralizzata (livello 2)",
      "text_fr": "Hôpital de soins généraux, prise en charge centralisée (niveau 2)",
      "key": "K112",
      "text_de": "Allgemeinspital, Zentrumsversorgung (Niveau 2)"
    },
    "equipment": [
      "MRI",
      "CT",
      "Angio"
    ]
  }
}

First, we created a Coordinate Map, showing all hospitals in Switzerland on a map.

Hospitals in Switzerland

You can see that we have a high concentration in Zurich, Basel and Bern. If we aggregate the data by canton, a regional administrative unit in Switzerland, we see that canton Zurich and Bern have the highest amount of hospitals.

Swiss Hospitals per Canton

Kibana Coordinate Maps have pretty useful additional features. If we take the previous coordinate map and change the map type to Shaded Geohash Grid, we have a similar heat map view for medical coverage. In our case, we choose the colour schema green for coverage significance. We can see the medical coverage for emergencies by filtering for hospitals, that have an ambulance.

Hospital ambulance coverage in Switzerland

Geo-Distance Queries

Now imagine you have a mobile phone application called Mimacom Medical Finder. As a tourist in Bern, you visit the scenic Rose Garden. Your smartphone is telling you that you are at latitude 46.952014 and longitude 7.460467.

Now you have a medical emergency and need to know where the nearest ambulance stations within a 1 km radius are?

The application Mimacom Medical Finder is querying Elasticsearch.

GET hospitals/_search
{
  "_source": [
    "name",
    "address",
    "services"
  ],
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "services": "AMBULANCE"
          }
        }
      ],
      "filter": {
        "geo_distance": {
          "distance": "1km",
          "location": {
            "lat": 46.952014,
            "lon": 7.460467
          }
        }
      }
    }
  }
}

The response in JSON

{
  "took": 5,
  "hits": {
    "total": 4,
    "hits": [
      {
        "_index": "hospitals",
        "_source": {
          "address": "Moserstrasse 24,3014 Bern",
          "name": "Tagesstätte Ost, Ambulat. Ost",
          "services": [
            "AMBULANCE"
          ]
        }
      },
      {
        "_index": "hospitals",
        "_source": {
          "address": "Schänzlistrasse 33,3013 Bern",
          "name": "Ambulatorium Salem",
          "services": [
            "AMBULANCE"
          ]
        }
      },
      {
        "_index": "hospitals",
        "_source": {
          "address": "Schänzlistrasse 39,3013 Bern",
          "name": "Salem-Spital",
          "services": [
            "AMBULANCE",
            "STATION"
          ]
        }
      },
      {
        "_index": "hospitals",
        "_source": {
          "address": "Schänzlihalde 11,3013 Bern",
          "name": "Hirslanden Bern AG",
          "services": [
            "AMBULANCE",
            "STATION"
          ]
        }
      }
    ]
  }
}

Four hospitals are nearby. If you alter the distance to 500m (500 meters), you get only two results for one hospital:

{
  "hits": {
    "total": 2,
    "hits": [
      {
        "_index": "hospitals",   
        "_source": {
          "address": "Schänzlistrasse 33,3013 Bern",
          "name": "Ambulatorium Salem",
          "services": [
            "AMBULANCE"
          ]
        }
      },
      {
        "_index": "hospitals",     
        "_source": {
          "address": "Schänzlistrasse 39,3013 Bern",
          "name": "Salem-Spital",
          "services": [
            "AMBULANCE",
            "STATION"
          ]
        }
      }
    ]
  }
}  

Noteworthy to mention, that this is a simple radius search and a direct point to point distance. The distance for arrival or routing might be longer depending on the streets and actual traffic. See below illustration for the 500 meters radius search.

Rose Garden 500m radius search

Searching for Specialists

We used open data and utilised it in our application. It is a good start. A real added value is to search for medical specialists. You can search for any particular field in medicine, e.g. cardiology or psychiatry. For our case, we choose haematology, the branch of medicine concerned with the study of the cause, prognosis, treatment, and prevention of diseases related to blood. If we enrich our hospital data with their units and departments, we could query haematology or haematologists. A haematologist is a doctor who treats patients diagnosed with a blood disease.

There are several ways to accomplish that. One approach is to add for each hospital their departments or unit of clinical service. An example for the Inselspital in Bern:

GET hospitals/_search
{
  "query": {
    "fuzzy": {
      "description": {
        "value": "Hämatologie*"
      }
    }
  }
}

A response with the reduced listing of units.

{
  "hits": {
    "total": 1,
    "hits": [
      {
        "_index": "hospitals",    
        "_source": {
          "name": "Insel Gruppe AG (nicht-universitär)",
          "canton": "BE",
          "services": [
            "AMBULANCE",
            "STATION"
          ],
          "address": "Freiburgstrasse 18,3010 Bern",
          "equipment": [
            "MRI",
            "CT",
            "Angio"
          ],
          "unit": [   
            "Allgemeine Innere Medizin",
            ..
            "Augenheilkunde",
            ..
            "Dermatologie",
            ..
            "Herz- und Gefässchirurgie",
            ..
            "Hämatologie und Hämatologisches Zentrallabor",
            ..
            "Zentrum für Palliative Care"
          ]
        }
      }
    ]
  }
}

The challenge is to get the additional information for all hospitals.

Additional Stakeholders

Having hospital data is one of many medical aspects. The resident doctors, or in our case the haematologists, are also vital for our specialist search. As an example, I imported all haematologists near the city of Bern.

We choose to store the information in the index doctors. Let's look for the first 3 doctors.

GET doctors/_search
{
  "_source": ["name", "address", "tags"],
  "size": 3
}

A simplified response.

{
  "took": 6,
  "hits": {
    "total": 17,
    "max_score": 1,
    "hits": [
      {
        "_source": {
          "address": "Bubenbergplatz 8,3011 Bern",
          "name": "FMH Praxis Bubenberg, Rigamonti, Véronique",
          "tags": [
            "Doctors",
            "General internal medicine",
            "Haematology"
          ]
        }
      },
      {
        "_source": {
          "address": "Monbijoustrasse 130,3007 Bern",
          "name": "Dr. med. Allgemeine Innere Medizin, Blutkrankheiten, Rigamonti, Véronique",
          "tags": [
            "Doctors",
            "General internal medicine",
            "Haematology"
          ]
        }
      },
      {
        "_source": {
          "address": "Monbijoustrasse 10,3011 Bern",
          "name": "Dr. med. Onkologie/Hämatologie, Innere Medizin FMH, Gwerder, Christoph",
          "tags": [
            "Doctors",
            "General internal medicine",
            "Medical oncology",
            "Haematology"
          ]
        }
      }
    ]
  }
}

Query enhanced

We use the alias medical for the indices hospitals and doctors.

POST /_aliases
{
    "actions" : [
        { "add" : { "index" : "hospitals", "alias" : "medical" } },
        { "add" : { "index" : "doctors", "alias" : "medical" } }
    ]
}

If we query now the medical data, patients have more possibilities to get medical treatment from haematologists. They are not limited to hospitals anymore.

Now we can search for haematology from the same location (the Rose Garden in Bern) with a 3 km radius.

GET medical/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "description": "haematology"
          }
        }
      ],
      "filter": {
        "geo_distance": {
          "distance": "3km",
          "location": {
            "lat": 46.952014,
            "lon": 7.460467
          }
        }
      }
    }
  }
}

The results contain one hospital and five doctors. For the illustration we choose the nearest doctor from our location.

{
  "took": 5,
  "hits": {
    "total": 6,
    "hits": [
      {
        "_index": "hospitals",
        "_source": {
          "name": "Insel Gruppe AG (nicht-universitär)",
          "address": "Freiburgstrasse 18,3010 Bern",
          "unit": [
            "Haematology",
            "Oncology"
          ]
        }
      },
      {
        "_index": "doctors",
        "_source": {
          "canton": "BE",
          "name": "Dr. med. FMH Facharzt für Innere Medizin, Blutkrankheiten, Merlin, Daniel",
          "address": "Schönburgstrasse 19,3013 Bern",
          "location": {
            "lat": 46.95454460000001,
            "lon": 7.4570635
          },
          "tags": [
            "Haematology",
            "Doctors",
            "General internal medicine"
          ]
        }
      },
      { .. }
    ]
  }
}

Using aliases in Elasticsearch and Kibana is in general a wise choice. You can search for hospitals and doctors in the medical view (see below image).

Medical view in Kibana

Summary

Geo-distance queries and analysis are compelling methods within the Elastic Stack. They are very easy to use. The medical use case is an excellent start to train on geo-distance queries. In general geo-distance queries have a broad spectrum of use cases. Imagine you are a bank with several locations. You can guide new customers to the nearest institution for opening an account in person. Fleet Management, Logistics and Freight distribution, Public Transportation and a lot more are exciting areas for geo-distance optimisations. In the next article, I am going to elaborate a little bit more about geographical heat maps.

About the author: Vinh Nguyên

Loves to code, hike and mostly drink black coffee. Favors Apache Kafka, Elasticsearch, Java Development and 80's music.

Comments
Join us