Wir betreiben Master Data Management in MDMbox seit zwei Jahren in Produktivumgebungen â wir deduplizieren Patienten, fĂŒhren Organisationen zusammen und gleichen Leistungserbringer ĂŒber Einrichtungen hinweg ab. Dabei haben wir gelernt, dass jede Organisation anders zusammenfĂŒhrt und kein einzelner serverseitiger Algorithmus die Vielfalt realer Merge-Richtlinien abdecken kann.
FHIR R5 hat Patient/$merge eingefĂŒhrt â eine lang erwartete Operation, mit der Sie doppelte PatientendatensĂ€tze zusammenfĂŒhren können. Sie definiert Eingabeparameter (source-patient, target-patient, result-patient), erwartet, dass der Server die Referenzaktualisierungen ĂŒbernimmt, und gibt das zusammengefĂŒhrte Ergebnis zurĂŒck. Die Operation befindet sich derzeit auf Reifegrad 0 und wurde seit ihrer EinfĂŒhrung nicht weiterentwickelt.
Das ist ein guter Anfang. Nach der Implementierung von Merge in der Produktion haben wir jedoch festgestellt, dass die Spezifikation nicht weit genug geht.
Das Problem mit servergesteuertem Merge
Die FHIR-$merge-Spezifikation setzt voraus, dass der Server weiĂ, wie zusammenzufĂŒhren ist. Der Server deaktiviert die Quelle, kopiert Identifikatoren und aktualisiert Referenzen. Die Merge-Logik variiert jedoch erheblich zwischen Organisationen:
- Krankenhaus A löscht den Quellpatienten vollstÀndig und schreibt alle Referenzen neu
- Krankenhaus B behĂ€lt die Quelle inaktiv und erstellt eine Linkage-Ressource fĂŒr die Provenienz
- Krankenhaus C fĂŒhrt Encounters und Observations in das Ziel zusammen, bewahrt aber separate AllergyIntolerance-DatensĂ€tze zur manuellen ĂberprĂŒfung
- Gesundheitsinformationsverbund D muss Organizations und Practitioners zusammenfĂŒhren, nicht nur Patients
Die Spezifikation deckt nichts davon ab â sie beschrĂ€nkt sich auf Patient, und der Schritt âalle Referenzen aktualisieren" wird nur vage beschrieben.
Was wir benötigten, war eine Merge-Operation, bei der:
- Der Client entscheidet, was geschieht (welche Ressourcen aktualisiert, erstellt oder gelöscht werden)
- Der Server AtomaritĂ€t gewĂ€hrleistet, einen Audit-Trail erstellt und SicherheitsprĂŒfungen durchsetzt
- Sie fĂŒr beliebige Ressourcentypen funktioniert, nicht nur fĂŒr Patient
Unser Ansatz: der plan-Parameter
Wir haben ein FHIR-konformes $merge entwickelt, das ein Standard-Transaction-Bundle als zusÀtzlichen plan-Parameter akzeptiert:
POST $merge
{
"resourceType": "Parameters",
"parameter": [
{"name": "source", "valueReference": {"reference": "Patient/123"}},
{"name": "target", "valueReference": {"reference": "Patient/456"}},
{"name": "preview", "valueBoolean": false},
{
"name": "plan",
"resource": {
"resourceType": "Bundle",
"type": "transaction",
"entry": [
{
"resource": {"resourceType": "Patient", "id": "456", "...": "merged state"},
"request": {"method": "PUT", "url": "Patient/456", "ifMatch": "W/\"3\""}
},
{
"resource": {"resourceType": "Encounter", "id": "789",
"subject": {"reference": "Patient/456"}},
"request": {"method": "PUT", "url": "Encounter/789", "ifMatch": "W/\"1\""}
},
{
"request": {"method": "DELETE", "url": "Patient/123", "ifMatch": "W/\"2\""}
}
]
}
}
]
}
Der Client sendet jeden PUT, POST und DELETE explizit. Der Server ergĂ€nzt den Plan um Audit-Ressourcen (Task + Provenance) und fĂŒhrt alles als einzelne FHIR-Transaktion aus. Entweder gelingt alles â einschlieĂlich des Audit-Trails â oder nichts.
Beachten Sie die ifMatch-Header bei jedem Eintrag â dies ist optimistisches Locking. Wenn eine Ressource zwischen dem Zeitpunkt, zu dem der Client den Plan erstellt hat, und dem Zeitpunkt der AusfĂŒhrung geĂ€ndert wurde, schlĂ€gt die Transaktion fehl. Keine stillen Ăberschreibungen, keine verlorenen Aktualisierungen.
Eine Obermenge, keine Abspaltung
Sie werden bemerken, dass wir source, target und result anstelle der spezifikationsgemĂ€Ăen Bezeichnungen source-patient, target-patient und result-patient verwenden. Das ist beabsichtigt â die Operation ist ressourcenagnostisch, daher wĂ€re eine patientenspezifische Benennung irrefĂŒhrend. Doppelte Organizations zusammenfĂŒhren? Practitioners? Dieselbe Operation, derselbe Audit-Trail.
Lassen Sie den plan-Parameter weg und ĂŒbergeben Sie stattdessen result â Sie erhalten das Standardverhalten von FHIR $merge. Die identifikatorbasierte Suche nach Quelle und Ziel wird unterstĂŒtzt. Der plan ist das, was die Operation streng leistungsfĂ€higer macht: Wenn er vorhanden ist, ĂŒbernimmt der Client die vollstĂ€ndige Kontrolle ĂŒber die Merge-Logik.
Das fehlende Element: $referencing
Um einen guten Merge-Plan zu erstellen, muss der Client eine Frage beantworten: âWelche Ressourcen referenzieren Patient/123?"
FHIR bietet _revinclude fĂŒr Suchergebnisse und $everything fĂŒr Patient, aber keine generische Operation, die besagt: âGib mir jede Ressource in der Datenbank, die auf diese Referenz verweist." Wir haben eine solche entwickelt.
Intern handelt es sich um eine PostgreSQL-Abfrage, die JSONPath verwendet, um ĂŒber Ressourcentabellen zu suchen:
SELECT id, resource_type, resource
FROM <resource_table>
WHERE jsonb_path_query_array(resource, '$.** ? (@.reference == "Patient/123")')
!= '[]'::jsonb
Die obige Abfrage ist zur Verdeutlichung vereinfacht, aber der Kerngedanke bleibt: $.** durchsucht rekursiv die gesamte Ressourcenstruktur und findet jedes verschachtelte Objekt, bei dem reference dem Ziel entspricht â unabhĂ€ngig davon, wo es im Ressourcenbaum vorkommt. Keine fest kodierten Pfade, keine ressourcentypspezifische Konfiguration. Eine einzige Abfrage findet Referenzen in Encounter.subject, Observation.performer, Claim.provider oder jedem anderen Referenzfeld.
Zur Performance: Diese Abfrage verwendet einen GIN-Index auf der JSONB-Spalte, sodass die rekursive Traversierung gegen den Index erfolgt â nicht als vollstĂ€ndiger Tabellen-Scan. Bei einem typischen Merge schlieĂt die Operation in Millisekunden ab. Bei Ressourcentypen mit Millionen von Zeilen parallelisieren wir die Suche ĂŒber Tabellen hinweg und streamen die Ergebnisse an den Client zurĂŒck.
Wir haben dies als eigenstĂ€ndige $referencing-Operation in MDMbox bereitgestellt â ein Baustein, den jeder Merge- (oder Impact-Analysis-)Workflow nutzen kann.
Task + Provenance: mehr als nur Audit
Jeder Merge erstellt einen Task und eine Provenance innerhalb derselben Transaktion. Das geht ĂŒber bloĂe Compliance hinaus:
Subscriptions. Externe Systeme können die Erstellung von Merge-Tasks abonnieren und sofort reagieren â ihre Caches aktualisieren, nachgelagerte Workflows auslösen, Benutzer benachrichtigen. Standard-FHIR-Subscriptions, ohne benutzerdefinierte Infrastruktur.
Versionierte Snapshots. Die Provenance erfasst fĂŒr jede durch den Merge geĂ€nderte oder gelöschte Ressource eine versionierte Referenz (z. B. Patient/456/_history/3). In Kombination mit der FHIR History API ist der vollstĂ€ndige Zustand vor dem Merge jederzeit wiederherstellbar.
Lifecycle-Tracking. Der Task protokolliert den Merge-Status (requested â in-progress â completed oder failed), wer ihn initiiert hat, wann er stattfand, und verknĂŒpft ihn mit Quelle und Ziel. Die Abfrage âZeig mir alle Merges, die diesen Patienten betroffen haben" ist eine einzelne FHIR-Suche auf Task.
Ausblick: $unmerge
FHIR definiert noch keine Unmerge-Operation. Betrachten Sie folgendes Szenario: Ein Merge wird am Montag ausgefĂŒhrt, und am Mittwoch stellt jemand fest, dass es sich um zwei tatsĂ€chlich verschiedene Patienten handelte. Zu diesem Zeitpunkt wurden 50 Ressourcen geĂ€ndert â Encounters wurden umgezeigt, Observations neu zugewiesen, der Quellpatient gelöscht.
Da Task den Merge-Lifecycle verfolgt, Provenance jede betroffene Ressource mit ihrer Version vor dem Merge erfasst und die History API alle vorherigen ZustĂ€nde bewahrt â haben wir alles, was nötig ist, um einen Merge zuverlĂ€ssig rĂŒckgĂ€ngig zu machen. Die $unmerge-Operation liest die Provenance, ruft die Versionen vor dem Merge aus der History ab und erstellt ein umgekehrtes Transaction-Bundle, das jede Ressource in ihren vorherigen Zustand zurĂŒckversetzt.
Wir werden $unmerge im nĂ€chsten Beitrag behandeln â jetzt veröffentlicht: Designing $unmerge: Reversing the FHIR Patient Merge. Der zweite Beitrag der Serie, MPI Vendors Couldn't Agree. We Solved Patient Merge, erlĂ€utert, warum ein einzelnes servergesteuertes $merge nicht alle Produktionsrichtlinien abdecken kann. Hintergrundinformationen zu den zugrundeliegenden Master Patient Index-Grundlagen finden Sie unter Master Patient Index (MPI): How It Works + Examples.
Möchten Sie clientgesteuertes Merge in Ihrem Projekt ausprobieren? MDMbox ist heute verfĂŒgbar.



