Monday, December 3, 2018

Thinking through FHIR Mapping dependencies and products

This is part of a continuing series on mapping to FHIR.  So far, we've explored some of the information that I need to handle mappings, and some ways to do inference and identify mappings, and how all of this could actually be stored more simply in ConceptMap (rather than StructureMap).  It's interesting to note that ConceptMap as originally designed in STU2 anticipated mapping StructureDefinitions.  I'm wondering why (or perhap not considering how complicated this stuff is) we have StructureMap as well.

Now, I'll delve into some features of ConceptMap, including two that started me down this path, dependsOn and product.  These are two sides of the same coin.  If X appears in dependsOn in a concept map, then then it will likely show up as a product reverse mapping, and vice versa.

Let's look at how we might use dependencies and products here. When mapping codes in the message to FHIR, you might need to go through a mapping table (another ConceptMap resource).  How you determine which concept map to go through varies based on context (the messaging being mapped, the channel or system configuration for mapping, et cetera).  That makes the ConceptMap a dependency of the mapping from source to destination.

So far so good.  But here's the next challenge: How do I represent that in ConceptMap?  I'm using ConceptMap in ways that it's not quite (but almost) intended to be used. We've almost got what we need, but figuring out how to use these fields right is important (at least to me).  So, let's look at the definitions for the required parts of dependsOn:

dependsOn PropertyDefinition
propertyA reference to an element that holds a coded value that corresponds to a code system property. The idea is that the information model carries an element somwhere that is labeled to correspond with a code system property.
codeIdentity (code or path) or the element/item/ValueSet that the map depends on / refers to.

Tricky definitions here.  Property says "where in the context do I find this", and code says what is its identity.  Ok, it's getting a little bit message, perhaps I should start simpler.  How would I normally use this?

A dependency could be a filter on the mapping element, in which case, it might address the question of when to use this mapping.  If property was MSH-9 (Message Type), then the code might identify a specific message type that this concept mapping element is to be used for.  If instead it was a ValueSet, it could identify a set of discrete values, which, if MSH-9 matched, might indicate activation of this concept mapping element (e.g., if building a mapping for specific types of ADT messages).

OK, so far, that makes sense.  Let's see how this works:

When the message is an ORM_O01, it's clearly an order, and it can produce DiagnosticOrder, ProcedureRequest, ReferralRequest and several others in STU2 with a slightly different list in STU3 and beyond.  MSH-9 doesn't always tell you what kind of thing to produce, but OBR and RXO segments might indicate what to produce based on the codes found in OBR-4, or RXO-1.

So, we might indicate that an OBR produces a ProcedureRequest when OBR-4 is in a particular value set (one containing inhalation treatment for example), and that RXO also produces ProcedureRequest based on RXO-1 being in a different value set (e.g., one containing inhalation therapy).  And that in both cases, the code will appear in ProcedureRequest.code as a product of this concept mapping (note, this might also be stated elsewhere as a mapping, where RXO-1 and OBR-4 produce value for ProcedureRequest.code). Thus, when doing the reverse mapping, ProcedureRequest might produce an OBR segment or an RXO segment, depending on the code found in ProcedureRequest.code, and the products of the reverse mapping will be a value in RXO-1 or OBR-4.  So, the reversal seems to work.

When a value set is given, that implies that the operation to be used as a condition for the mapping is to see if the value set given contains the code.  And when using fixed code values, it implies that the condition for mapping is an equality test.  So, code describes what the mapping depends on, and the type of thing depended on implies the operation to perform.  Extending from that logic, if what appears in code is a reference to a concept map, the implied dependency is to perform a concept map translation based on the property referenced.

Let's say that a requirement of my mapping is to translate local codes into standard ones, I could represent the code as a specific concept map used for translating the values, and then indicate that code depends on that concept map.  OK, that seems to work.  Except what if there isn't a mapping?  Looking to DSTU3 I can see they'e added a case to ConceptMap that handles unmapped codes, but this isn't present in DSTU2.  Ah well, I can fall back on my forward compatibility cheat.

Now it gets ugly.  OBR-4 could be a local code, in which case I can have two dependencies, one which says what to build, and another that says what to map.  Ahh, but recall that there's both model to model and instance to instance mappings.  Hmm.  Model to model says what to create, instance to instance says how to copy values.  OK, theory is being more clear, but closer to etched glass rather than painted black (where I started).  It's still fuzzy BUT, I think I have enough now to write some code.

   Keith

P.S. Welcome to my mind.  These last three posts are all part of a single stream of consciousness as I work out some of the details of this gnarly problem.



0 comments:

Post a Comment