6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 1/41
FHIR DATABASESFHIR DATABASES
Nikolai Ryzhikov @ Health Samurai
@niquola (tw, gm, gh)
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 2/41
LET'S IMPLEMENT YOURLET'S IMPLEMENT YOUR
IDEAS IN FHIRIDEAS IN FHIR
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 3/41
FHIR-NATIVE & FHIR-FIRSTFHIR-NATIVE & FHIR-FIRST
Use FHIR as platform to build next-generation systems
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 4/41
FHIR PERSISTENCE?FHIR PERSISTENCE?
How to store & query FHIR resources?
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 5/41
SQL/RELATIONAL DBSSQL/RELATIONAL DBS
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 6/41
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 7/41
SQL/RELATIONAL DBSSQL/RELATIONAL DBS
Normal form? > 1000 tables
CREATE TABLE patient (id, birthDate,...);
CREATE TABLE patient_name (pid, family, use, given?...);
CREATE TABLE patient_telecom (pid, system, value ...)
CREATE TABLE patient_address (pid, city...);
CREATE TABLE patient_photo (pid, ...);
CREATE TABLE patient_contact (pid, ...);
CREATE TABLE patient_contact_name (pid, p_cid ...);
CREATE TABLE patient_contact_address (pid, p_cid ...);
CREATE TABLE patient_communication (pid, ...);
.....
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 8/41
SQL/RELATIONAL DBSSQL/RELATIONAL DBS
DBs 10x inserts and joins
SELECT *
FROM patient
JOIN patient_name
JOIN patient_telecom
JOIN patient_address
JOIN patient_photo
JOIN patient_contact
JOIN patient_contact_name
JOIN patient_contact_address
JOIN patient_communication
.....
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 9/41
POPULAR SCHEMAPOPULAR SCHEMA - SAVE BLOB!- SAVE BLOB!
Grahame's Server, HAPI JPA, Vonk, MS FHIR
CREATE TABLE resource (
id,
resource blob,
...
);
create table string_idx(res_id, value, ...);
create table date_idx(res_id, value, ...);
create table token_idx(res_id, value, ...);
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 10/41
FHIR SEARCHFHIR SEARCH
GET /Patient?name=john&birthdate=lt1980&active=true
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 11/41
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 12/41
FHIR SEARCHFHIR SEARCH
resourceType: "SearchParameter"
id: "Patient.phone"
name: "phone"
type: "token"
expression: "Patient.telecom.where(system='phone')"
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 13/41
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 14/41
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 15/41
GET /PATIENT?PHONE=123GET /PATIENT?PHONE=123
SELECT resource
FROM resource r
JOIN token_idx s1
ON s1.res_id = id AND s1.name = 'phone'
WHERE
r.type = 'Patient'
AND s1.value = '123'
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 16/41
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 17/41
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 18/41
STORE 3 TIMES!STORE 3 TIMES!
as blob
as search param entry
as db idx
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 19/41
MULTIPLE SEARCH PARAMSMULTIPLE SEARCH PARAMS
GET /Patient?
name=john&
birthDate=lt1870&
address=LA&
...
&_sort=birthDate
SELECT resource
FROM resource r
JOIN string_idx s1
JOIN date_idx d1
JOIN address_idx d1
WHERE ...
SORT BY d1.value
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 20/41
PERFORMANCE & SELECITVITYPERFORMANCE & SELECITVITY
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 21/41
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 22/41
DOCUMENT DATABASES?DOCUMENT DATABASES?
monogodb
couchdb
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 23/41
MONGODBMONGODB
Search in db
db.Patient.find( {
status: active,
$or: [ { birthDate: { $lt: 1980 } } ]
})
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 24/41
DOCUMENT DBS +DOCUMENT DBS +
resources fit docs
in db search
clusters out of the box
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 25/41
DOCUMENT DBS -DOCUMENT DBS -
not mature as relational
transactional interity
query expressivenes (SQL)
but it's changing
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 26/41
FHIRBASE/AIDBOXFHIRBASE/AIDBOX
hybrid approach: doc + sql
Use JSONB
Search on db layer
Get the best from PostgreSQL
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 27/41
FHIRBASE/AIDBOX SCHEMAFHIRBASE/AIDBOX SCHEMA
table per resource type
CREATE TABLE patient (
id text primary key,
resource jsonb
...
);
CREATE TABLE encounter (
id text primary key,
resource jsonb
...
);
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 28/41
FHIRBASE/AIDBOX SEARCHFHIRBASE/AIDBOX SEARCH
search expressions in db
SELECT * FROM patient
WHERE
timestamp(res->>'birthDate') > '1950'
AND timestamp(res->>'birthDate') > '1950'
AND extract(res, 'identifier.where(system = "mrn"))' = '1234
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 29/41
FUNCTIONAL INDICESFUNCTIONAL INDICES
pg ext: jsonknife, jsquery, fhirpath.pg (beta)
CREATE index patient_mrn_idx
ON patient GIN (
extract(resource, 'identifier.where(system = "mrn"))'
);
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 30/41
INDEXING IN DBINDEXING IN DB
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 31/41
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 32/41
ADVANCED PG INDEXINGADVANCED PG INDEXING
SELECT *
FROM patient
WHERE
resource @> $${
"gender": "female",
"active": true,
"identifier": [{"system":"mrn", "value": "000000013"}]}
}$$
CREATE INDEX patient_jsonb_gin
ON patient USING GIN (
resource jsonb_path_ops
);
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 33/41
FHIRBASE/AIDBOXFHIRBASE/AIDBOX
indexing in db (up 10 times faster)
search any element any resource
more space for optimization
SQL as second API
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 34/41
FHIRBASE FOR OTHER DBSFHIRBASE FOR OTHER DBS
JSONpath in SQL standard
Oracle
PostgreSQL
MSSQL
MySQL
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 35/41
ANALYTICS ON FHIRANALYTICS ON FHIR
SQL on FHIR
Analytics on FHIR
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 36/41
SQL ON FHIRSQL ON FHIR
SELECT subject.reference,
AVG(value.quantity.value) avg_hdl
FROM observation o,
UNNEST(o.code.coding) c
WHERE c.system = 'http://loinc.org' AND
c.code = '2085-9' AND
o.effective.datetime > '2017'
GROUP BY subject.reference
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 37/41
IMPLEMENTATIONSIMPLEMENTATIONS
Bunsen: Spark SQL
BigQuery on FHIR
fhirbase: PostgreSQL
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 38/41
STORAGE FORMATSTORAGE FORMAT
structured references
fixed choice types
first class extensions
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 39/41
GETTING STARTEDGETTING STARTED
||
SQL on FHIR tutorials
fhirbase online aidbox online
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 40/41
WELCOME TOWELCOME TO
FHIR COMMUNITY!FHIR COMMUNITY!
6/6/2019 fhir db
https://niquola.github.io/fhir-devdays-2019-slides/?print-pdf#/ 41/41
THANK YOU!THANK YOU!
Nicola (RIO) in zulip
@niquola on github & twitter
niquola@health-samurai.io

FHIR databases by Nikolai Ryzhikov, PhD at ScaleLA