Clinical Decision Support and Measure Reporting in FHIR

Davison Kimigho
November 18, 2021

Through clinical decision support (CDS) and measure reporting, FHIR gives us powerful tools to encode algorithms for healthcare workflows and define metrics that track patient care. The HL7 standards of Clinical Quality Language (CQL) and FHIRPath expressions let us express both our CDS and measures in a portable way. Thanks to Ona’s work on Android FHIR SDK and FHIR Core, we can run these standards on smartphone apps.

What is clinical decision support?

CDS provides clinicians, health staff, or patients with person-specific, intelligently filtered, and timely information to enhance health and health care. CDS encompasses a variety of tools to enhance decision-making in the clinical workflow. These tools include computerized alerts and reminders for care providers and patients; clinical guidelines; condition-specific order sets; focused patient data reports and summaries; documentation templates; diagnostic support, and contextually relevant reference information, among other tools.
CQL and FHIRPath give us an expressive query and transversable language respectively, that we can use to guide healthcare workers through CDS. For example, we can run CQL code or a FHIRPath expression on a FHIR Observation resource to determine whether a patient has hypertension or not. We can then use this qualitative result to aid the clinician in deciding on how to provide care.

What is measure reporting?

In FHIR, measure reporting allows us to define specific indicators, optionally linked to relevant indicator codes (e.g. SNOMED, ICD, LOINC, etc). The FHIR MeasureReport resource links this indicator and their calculation formula to the relevant subject or population subject filter, and stores the results of performing the calculation. In FHIR, we can write both CQL queries and FHIRPath expressions to generate measure reports from FHIR Resources.
For a single patient, we can run measure reporting on a FHIR Observation resource related to the patient we are interested in. For example, we can use a MeasureReport to define the results of patient specific laboratory test indicators, such as blood sugar level, haemoglobin level, and bile level. For a population, that is to say a group of patients defined by a characteristic age, gender, condition, etc., measure reporting returns a population count for each of the criteria in the measure. Some examples of measures are how many pregnant women missed their first ANC visit and how many pregnant women were screened for syphilis. The HL7 FHIR MeasureReport resource documentation contains additional examples.

Introducing CQL

Clinical Quality Language (CQL) is a high-level, domain-specific language focused on clinical quality and targeted at measure and decision support artifact authors. In addition, this specification describes a machine-readable canonical representation called Expression Logical Model (ELM) targeted at implementations and designed to enable sharing of clinical knowledge. For analogy purposes, think of it as SQL targeted at the health community.
CQL has matured as a computer programming language executed against FHIR resources. Here we will not go deeply into the CQL language definition, but you can find additional information concerning that on the HL7 CQL release page. Note that below we include snippets of CQL code that you can run in this online CQL IDE.

CQL Example Evaluating Patient Hypertension

The below CQL defines hypertension using its SNOMED codes and then determines whether based on FHIR Observation resources the associated Patient is hypertensive.

library TestArtifact version '1'
using FHIR version '4.0.0'
include "FHIRHelpers" version '4.0.0' called FHIRHelpers
codesystem "SNOMED": ''
codesystem "CONDCLINSTATUS": ''
codesystem "CONDVERSTATUS": ''
code "Essential hypertension (disorder) code": '59621000' from "SNOMED" display 'Essential hypertension (disorder)'
code "Malignant hypertensive chronic kidney disease (disorder) code": '285831000119108' from "SNOMED" display 'Malignant hypertensive chronic kidney disease (disorder)'
code "Condition Active code": 'active' from "CONDCLINSTATUS" display 'Active'
code "Condition Confirmed code": 'confirmed' from "CONDVERSTATUS" display 'Confirmed'  
concept "Condition Active": { "Condition Active code" } display 'Active'
concept "Condition Confirmed": { "Condition Confirmed code" } display 'Confirmed'  
context Patient
define "AgeRange-548":   
AgeInYears() >= 60 and AgeInYears() <= 85  
define "Essential hypertension (disorder)":   exists(ActiveCondition([Condition: "Essential hypertension (disorder) code"]))  
define "Malignant hypertensive chronic kidney disease (disorder)":   exists(Confirmed([Condition: "Malignant hypertensive chronic kidney disease (disorder) code"]))  
define "MeetsInclusionCriteria":
  and "Essential hypertension (disorder)"  
define "MeetsExclusionCriteria":
  "Malignant hypertensive chronic kidney disease (disorder)"
define "InPopulation":   "MeetsInclusionCriteria" and not "MeetsExclusionCriteria"
define "Recommendation":
  if "InPopulation" then ''
  else null  
define "Rationale":
  if "InPopulation" then null
  else null
 define "Errors":
define function Confirmed(CondList List):
  CondList C where C.verificationStatus ~ "Condition Confirmed code"
define function ActiveCondition(CondList List):
  CondList C
    where C.clinicalStatus ~ "Condition Active code"
      and C.abatement is null

Running the above CQL in an evaluator produces the following results:

>Patient [19:1] {"resourceType":"Patient","id":"P48","meta":{"versionId":"1","lastUpdated":"2021-10-22T03:39:11.401+00:00","source":"#DP5g5aScIQt7YCpE"},"text":{"status":"generated","div":"<div xmlns=\"\"><div class=\"hapiHeaderText\">Adam <b>EVERYMAN </b></div><table class=\"hapiPropertyTable\"><tbody><tr><td>Identifier</td><td>1000</td></tr><tr><td>Address</td><td/></tr><tr><td>Date of birth</td><td><span>03 November 1950</span></td></tr></tbody></table></div>"},"identifier":[{"use":"official","value":"1000"}],"active":true,"name":[{"use":"official","family":"Everyman","given":["Adam"]}],"telecom":[{"system":"phone","value":"555-555-2003","use":"mobile"}],"gender":"male","birthDate":"1950-11-03","address":[{"use":"home","text":"2222 Home Street"}]}
>> AgeRange-548 [21:1] true
>> ActiveCondition [56:1] Definition successfully validated
>> Essential hypertension (disorder) [24:1] true
>> Confirmed [53:1] Definition successfully validated
>> Malignant hypertensive chronic kidney disease (disorder) [27:1] false
>> MeetsInclusionCriteria [30:1] true
>> MeetsExclusionCriteria [34:1] false
>> InPopulation [37:1] true
>> Recommendation [40:1] undefined
>> Rationale [45:1] null
>> Errors [49:1] null

The example above loads the below FHIR resources:

  • The library – The base library that contains FHIR value sets, definitions, and terminologies to run against the CQL context
  • The data model – The data model to reference, in this case FHIR
  • The dependencies – Other library dependencies. In this case FHIR Helpers
  • The terminologies – Terminologies to use while running evaluation
  • The context – In this case patient
  • The definition – Evaluations to obtain results

Then it uses a CQL engine to evaluate the CQL code in the referenced context—in this case the Patient—to produce coded qualitative output for hypertension and malignant hypertensive chronic kidney disease.

Introducing FHIRPath expressions

FHIRPath is a path based navigation and extraction language, somewhat like XPath. Operations are expressed in terms of the logical content of hierarchical data models, and support traversal, selection and filtering of data. FHIRPath can be applied to measure reporting as well as CQL evaluation. You can think of FHIRPath as a language to transverse a JSON or XML tree and apply operations at different levels. Clinicians can use FHIRPath for CDS, e.g. when we have an expression that looks for a pregnancy code system in a FHIR Observation resource of a particular patient to determine if they are pregnant.

Below is a FHIR Patient resource as JSON. We will give a couple examples of evaluating FHIRPath expressions against this resource.

         "system": ""
         "value": "123"
          "system": "",
          "value": "456"
"name":[ { "family":"Scott", "given":[ "Michael", "Gary" ] },
  "given":[ "Astrid" ]
  "line":[ "#4 Privet Drive", "Under the staircase" ],
  "city":"Little Whinging", "district":"Surrey", "postalCode":"ABC 123"

The below code snippet shows the FHIRPath expressions and output when run against the above FHIR Patient resource. You can run these expressions through a web browser or HTTP request to view the output yourself. =["Michael", "Gary", "Astrid"]'').value = ["123"]

If you are interested in the FHIRPath language definition it is available in the HL7 FHIRPath release documentation.

CQL compared to FHIRPath

In the below table we look at how CQL compares to FHIRPath.



Learning curve steep Easy to learn

Programming language features, like reusable expressions, functions, and parameter definitions

Not a programming language
SQL Like syntax XPath like Syntax
Mainly used for complex expressions. e.g. foreach Mainly used for simple queries
Targeted at developers with typical development knowledge on languages such as Java, C#, and SQL Users with little programming experience can use it.
Cannot be run on browser URL Can be run on browser URL
Needs an external CQL Engine No external engine necessary as its is embedded in FHIR

Wrapping up

CDS and measure reporting are both crucial for effective healthcare delivery by practitioners. FHIR provides support for this through CQL and FHIRPath expressions. Developers can leverage this to provide health interoperability by developing web and native apps which implement the FHIR standard.

Further reading and references