Chuyển đến nội dung chính

FHIR ↔ OMOP: bridging the operational and analytics layers

Duy Tran14 min
FHIR ↔ OMOP: bridging the operational and analytics layers

FHIR is the operational standard. OMOP is the analytical standard. Both coexist in a mature 2026 organization. This article shows how to bridge the two worlds: mapping, tooling, and pipelines.

1. Why you need both

Why you need both

FHIR is strong for real-time, JSON, and REST. OMOP is strong for batch SQL, standardized vocabularies, and network studies. They each own a front — bridge them, don't replace one with the other.

2. Resource ↔ table mapping

The FHIR-OMOP-on-FHIR community (a joint HL7 + OHDSI working group) maintains the official mapping.

2.1 Core mapping table

FHIR ResourceOMOP TableNote
PatientPERSONidentifier → person_source_value, gender → gender_concept_id
EncounterVISIT_OCCURRENCEclass → visit_concept_id
Encounter (subVisit)VISIT_DETAIL (CDM 5.4+)hospital ward, dept
ConditionCONDITION_OCCURRENCEcode (SNOMED) → condition_concept_id
MedicationRequest / MedicationStatement / MedicationDispenseDRUG_EXPOSUREcode (RxNorm) → drug_concept_id
MedicationAdministrationDRUG_EXPOSUREdrug_type_concept_id = Inpatient admin
ProcedurePROCEDURE_OCCURRENCEcode → procedure_concept_id
Observation (lab)MEASUREMENTcode (LOINC) + valueQuantity
Observation (vital)MEASUREMENTcode + valueQuantity
Observation (social, family hx)OBSERVATIONcode → observation_concept_id
AllergyIntoleranceOBSERVATIONconcept = "Allergy to"
ImmunizationDRUG_EXPOSURE / PROCEDURE_OCCURRENCEdepends
SpecimenSPECIMENCDM 5.4
DocumentReference / CompositionNOTEtext → note + NOTE_NLP
CoveragePAYER_PLAN_PERIODBHYT, supplementary BHYT
PractitionerPROVIDER
Organization (provider)CARE_SITE
LocationLOCATION

2.2 Detailed mapping: Encounter → Visit_Occurrence

Detailed mapping: Encounter → Visit_Occurrence

Code:

def encounter_to_visit(enc):
    return {
        'visit_occurrence_id': hash_to_bigint(enc['id']),
        'person_id': lookup_person(enc['subject']['reference']),
        'visit_concept_id': map_class(enc['class']['code']),
        'visit_start_date': enc['period']['start'][:10],
        'visit_start_datetime': enc['period']['start'],
        'visit_end_date': enc['period'].get('end', enc['period']['start'])[:10],
        'visit_type_concept_id': 32817,  # EHR encounter
        'care_site_id': lookup_care_site(enc.get('serviceProvider')),
        'visit_source_value': enc['id']
    }

def map_class(class_code):
    return {
        'IMP': 9201,  # Inpatient
        'AMB': 9202,  # Outpatient
        'EMER': 9203, # ER
        'HH': 581476, # Home health
        'VR': 5083    # Virtual / telehealth
    }.get(class_code, 0)

3. Coding system map FHIR ↔ OMOP

FHIR code system URL → OMOP vocabulary_id:

FHIR System URLOMOP vocabulary_id
http://snomed.info/sctSNOMED
http://hl7.org/fhir/sid/icd-10-cmICD10CM
http://hl7.org/fhir/sid/icd-10ICD10
http://www.nlm.nih.gov/research/umls/rxnormRxNorm
http://loinc.orgLOINC
http://www.ama-assn.org/go/cptCPT4
urn:oid:2.16.840.1.113883.6.96SNOMED (OID)

Vietnam:

Vietnam FHIR System URLOMOP vocabulary
https://terminology.kcb.vn/CodeSystem/icd10vnCustom ICD10VN
https://terminology.kcb.vn/CodeSystem/danhmucthuocVN_DRUG (custom)

4. Pipeline patterns

4.1 Bulk Export → ETL → CDM

Bulk Export → ETL → CDM

Benefit: standard FHIR; you don't need the FHIR backend to support custom export. See FHIR Bulk Data Export & CDS Hooks.

4.2 Real-time CDC pattern

Real-time CDC pattern

Pros: FHIR stays fresh; OMOP aggregates nightly.

5. Pathling — query FHIR like OMOP

Pathling (CSIRO Australia) lets you query FHIR data analytics-style:

-- Bulk Pathling query
SELECT 
  patient.id, 
  patient.gender,
  count(condition) AS n_conditions
FROM patient
LEFT JOIN condition ON condition.subject = patient
WHERE condition.code.subsumes('SNOMED|73211009')  -- Diabetes
GROUP BY patient.id, patient.gender;

Pathling stores FHIR in Parquet and queries with SparkSQL — analytics speed approaches OMOP. It can serve as a temporary bridge if you don't yet want to build a full OMOP CDM.

6. FHIR-OMOP-on-FHIR

Joint HL7 + OHDSI working group since 2020. 2026 deliverables:

  • Official Implementation Guide (ig.fhir.org/...)
  • Maintained mapping tables
  • HAPI FHIR plugin → query OMOP CDM as FHIR
  • OMOP-on-FHIR reference server (Georgia Tech)

→ A single server can serve OMOP data through a FHIR interface, or convert FHIR → OMOP automatically.

7. OHDSI Sql On FHIR (SOF)

Sql On FHIR (SOF) is a newer project (2024-2026) that exposes FHIR resources as SQL views. Similar to Pathling, but the spec is open:

  • ViewDefinition resource (R4 / R5)
  • Reference implementations: HAPI, Aidbox
  • Output: flat tabular views → easy to load into OMOP

8. Deploying in Vietnam

8.1 Recommended pattern

Recommended pattern

8.2 Adapters you need to build

  • ICD-10 VN → SNOMED (USAGI with manual review)
  • MoH drug catalog → RxNorm
  • DVKT (medical service) catalog → SNOMED procedure
  • 54 ethnicities → custom vocabulary
  • BHYT type → Payer concept (custom)

See OMOP for Vietnam — BHYT, HSDT, ICD-10 VN, 54 ethnicities.

9. Mapping pitfalls

  • ❌ A MedicationRequest that hasn't been filled → don't push it into DRUG_EXPOSURE (don't confuse with MedicationStatement = the patient actually took it)
  • ❌ Encounters with status cancelled → exclude from VISIT
  • ❌ Observations marked not-done → don't push into MEASUREMENT
  • ❌ FHIR Subscription notifications → DO NOT push into OMOP (operational only)
  • ❌ Provenance / AuditEvent → don't map to OMOP
  • ❌ Multiple Patient.identifier values → pick one as person_source_value (pseudonymized national ID)
  • ❌ Many-to-one mappings (e.g., 3 MedicationAdministrations in one day) → must be grouped by clinical logic

10. Validating the bridge

Checks to run:

  • patients in FHIR == # rows in PERSON

  • Total Encounters == total VISIT_OCCURRENCE
  • Total Conditions == total CONDITION_OCCURRENCE
  • DQD passes on the new CDM
  • Sample 100 patients: trace forward (FHIR → OMOP) and backward

11. Hybrid pattern

Hybrid pattern

Start small and scale up. You don't have to build OMOP from day one — Pathling can carry phase 1.

12. Further reading

  • HL7 FHIR-to-OMOP Implementation Guide
  • Pathling docs: pathling.csiro.au
  • OMOP-on-FHIR Georgia Tech: github.com/Georgia-Tech-CSE
  • OHDSI Working Group "FHIR and OMOP"
  • SOF (SQL on FHIR) spec
  • Vietnam: community FHIR profiles and mappings (in progress)

Conclusion

FHIR + OMOP isn't a choice — it's the standard 2026 pattern. A solid bridge enables real-time operations and multi-source RWE analytics in the same organization. Vietnam has the opportunity to build an integrated stack from day one, with no legacy migration to worry about.

Next up: OMOP for Vietnam — BHYT, HSDT, ICD-10 VN, 54 ethnicities.