Series by Stefan Spiska, Senior Backend Developer, PEN, vitagroup HIP
Part 4 of the series "Vendor neutral interoperability with openEHR and HL7 FHIR"
In the previous sections, it was explored how to create patients and store data in HIP. One of the most significant advantages of an open data platform with standardized formats is the ability to search for data flexibly - not just by ID but using various clinical or administrative criteria.
Example use case: Searching for systolic blood pressure in a specific Encounter
Let’s assume one wants to find all systolic blood pressure measurements in a specific Encounter, where the value is ≥ 100 mmHg.
FHIR Approach
In FHIR, one would search for Observation components with:
- code = 8480-6 (Systolic Blood Pressure)
- valueQuantity.value ≥ 100
- encounter = Encounter/74aa52fc-6aff-46aa-9848-e37b013354
So the FHIR search request would be :
Observation/?component-code-value-quantity=8480-6$ge100&encounter=74aa52fc-6aff-46aa-9848-e37b013354
Translating FHIR Search to openEHR Query
Since the FHIR Observation components was mapped to the openEHR archetype openEHR-EHR-OBSERVATION.blood_pressure.v2, the FHIR search has to be translated into an openEHR query.
Thankfully, EHRbase, as an openEHR server, provides a powerful standardised query language called AQL (Archetype Query Language).
Think of AQL as a combination of XPath and SQL, allowing us to query structured clinical data based on openEHR's Reference Model (RM).
Basic AQL Queries
Selecting Compositions:
SELECT c FROM COMPOSITION c
would retrieve all Compositions.
Selecting Observations:
SELECT o FROM OBSERVATION o
This retrieves all Observations wich in openEHR are part of a Composition.
Selecting specific data fields:
SELECT c/uid/value,c/context/start_time/value COMPOSITION c
As we can see from the RM-model definition EHR Information Model
- c/uid/value: Navigate to uid field which is of type UID_BASED_ID and thus we can navigate the value field which contains a String containing the uid of this composition
- c/context/start_time/value: Is the display of start time of the composition
For archetypes objects like openEHR-EHR-OBSERVATION.blood_pressure.v1 one has to look up the archetypes to get the parts.
SELECT
o/data[at0001]/events[at0006]/data[at0003]/items[at0004]/value/magnitude,
o/data[at0001]/events[at0006]/data[at0003]/items[at0004]/value/units
FROM OBSERVATION o[openEHR-EHR-OBSERVATION.blood_pressure.v1]
Previously it was shown that /data[at0001]/events[at0006]/data[at0003]/items[at0004] in the archetype openEHR-EHR-OBSERVATION.blood_pressure.v2 points to the element containing the DV_QUANTITY with the systolic blood pressure and thus we add the relative parts.
- value/magnitude
- value/units
To get the magnitude and unit.
Note that
o[openEHR-EHR-OBSERVATION.blood_pressure.v1]
is just a shorthand for
o[archetype_node_id ='openEHR-EHR-OBSERVATION.blood_pressure.v1']
which ensures that only Blood Pressure observations are queried.
Joining data across multiple structures
We can also “join“ objects which are contained in each other using the the CONTAINS clause:
SELECT
c/uid/value,
c/context/start_time/value,
o/data[at0001]/events[at0006]/data[at0003]/items[at0004]/value/magnitude
FROM EHR e
CONTAINS COMPOSITION c
contains OBSERVATION o[openEHR-EHR-OBSERVATION.blood_pressure.v1]
CONTAINS defines hierarchical relationships within an EHR, similar to a structured join in SQL. In this query, it ensures that Compositions are selected from the EHR, and only Observations within those Compositions are retrieved. This allows querying structured clinical data while maintaining the context of where it is stored.
So each row
{
"rows": [
[
"635775de-84fb-4ce4-bf65-71249f28953a::cdr-core-sanity-check.hip-cdr-core-ehrbase-enterprise-cdr-core-dev1.dev3.vg-hip.dev::1",
"2022-02-03T04:05:06",
120.0
],
[
"7d99ae32-64e3-40a7-a11f-5c5fb1aafbc0::cdr-core-sanity-check.hip-cdr-core-ehrbase-enterprise-cdr-core-dev1.dev3.vg-hip.dev::1",
"2022-03-03T00:00:00",
123.0
]
]
}
will represent a systolic blood pressure measurement together with the ehr id (patient identifier ) and start time.
Searching by Encounter
In the last part ist was shown how encounters are represented as Folders in the HIP, containing Compositions. Thus encounter = encounter/74aa52fc-6aff-46aa-9848-e37b013354 can be represented as
SELECT c
FROM FOLDER f [openEHR-EHR-FOLDER.episode_of_care.v1]
contains COMPOSITION c
WHERE
f/uid/value = '74aa52fc-6aff-46aa-9848-e37b013354'
Putting everything together
Since component-code was mapped to data[at0001]/events[at0006]/data[at0003]/items[at0004] in the Archetype openEHR-EHR-OBSERVATION.blood_pressure.v2 and the Composition was stored in an Encounter with Id = 74aa52fc-6aff-46aa-9848-e37b013354 the FHIR search
Observation/?component-code-value-quantity=8480-6$ge100&encounter=74aa52fc-6aff-46aa-9848-e37b013354
can be represented as the following AQL query:
SELECT DISTINCT c
FROM FOLDER f [openEHR-EHR-FOLDER.episode_of_care.v1]
contains COMPOSITION c
contains OBSERVATION o[openEHR-EHR-OBSERVATION.blood_pressure.v2]
WHERE
f/uid/value = '74aa52fc-6aff-46aa-9848-e37b013354'
AND
o/data[at0001]/events[at0006]/data[at0003]/items[at0004]/magnitude >= 100
The HIP-Bridge will read the mappings to automatically transform FHIR search Request to AQL, and transforming the resulting data back to FHIR.
Thus through the capabilities of the HIP Bridge, users can query data in two ways: using FHIR Search or the Archetype Query Language. This ensures to meet the needs to system integrations and application developers alike with different views and access mechanisms on the data.
Conclusion
In this blog series, we have explored how HIP (Health Intelligence Platform) enables vendor neutral interoperability by integrating legacy healthcare data into openEHR and HL7 FHIR. We have seen how data can be transformed into FHIR and openEHR formats, ensuring structured, standardised, and semantically rich data storage.
By leveraging PSPL (Protocol Specific Path Language) and AQL (Archetype Query Language), we demonstrated how data can be mapped, stored, and efficiently queried, allowing healthcare providers to move beyond simple ID-based searches and perform complex, criteria-driven queries. This level of data accessibility and interoperability empowers organizations to build advanced health applications, enhance clinical decision making, and improve patient outcomes.
With a vendor neutral and standards based approach, HIP provides a future proof foundation for seamless data exchange between healthcare systems. As healthcare continues to evolve, adopting open data models and interoperability frameworks like openEHR and FHIR will be essential for achieving truly connected and patient centric healthcare ecosystems.
About the Author – Stefan Spiska
Stefan Spiska is a Senior Software Developer at vitagroup, specializing in interoperability and open platform development in the E-Health sector. With extensive experience in healthcare IT, he is a core developer for the open source openEHR platform, EHRbase (ehrbase.org).
Top comments (0)