2021-09-23 - SLPG Meeting

2021-09-23 - SLPG Meeting

Date & Time

20:00 to 21:00 UTC Thursday 23rd September 2021

Location

Zoom meeting link (password: 764978)

Goals

  • Agree to publish ECL v1.6 (last week was final chance for feedback)

  • Progress ECL enhancements - access to historical refsets

Attendees 

  • Chair: @Former user (Deleted)

  • Project Group: @Daniel Karlsson@roger.jane (Unlicensed)@Kai Kewley, @michael lawley , @Feikje Hielkema (Unlicensed) , @Alejandro Lopez Osornio , @Anne Randorff Højen , @Rob Hausam

 

Agenda and Meeting Notes

Description

Owner

Notes

Description

Owner

Notes

Welcome and agenda

@Former user (Deleted)

Welcome to new attendees

ECL v1.6 - Concept Filters

@Former user (Deleted) 

  • PLAN - To publish ECL v1.6.

    • Any further feedback before v1.6 is published?

    • Question - Should we allow a subExpressionConstraint for the value of the following filters:

      • C definitionStatusId

      • C moduleId

      • D typeId

      • D dialectId

    • For example

      • <  64572001 |Asthma|  {{ C moduleId =  << 19481000087107 | Canada Health Infoway maintained module | }}

ECL v1.7 - Access to historical refsets

 

Under consideration (brainstorming)

To leverage the existing memberOf (^) function, which currently only brings back the 'referencedComponentId', rather than the whole 'member' (i.e. row) as you might expect a 'memberOf' function to do. If we defined an expanded form of the current 'memberOf' function, which explicitly shows that by default we're selecting attributeOrder = 0 from the member, then the following 2 ECL would be equivalent.

  1. ^ 447562003 |ICD-10 complex map refset|

  2. ^ [referencedComponentId] 447562003 |ICD-10 complex map refset|

This would allow us to select other columns  of the refset using the same memberOf function - e.g.

  • ^ [mapTarget] 447562003 |ICD-10 complex map refset|

And we could then introduce a 'Member filter' with a similar attribute reference - e.g.

  • ^ [referencedComponentId] 447562003 |ICD-10 complex map refset| {{ M mapTarget = "L56.2" }} 

Additional Examples

  • Find all the inactive concepts associated by any historical association to a subtype of 195967001 | Asthma (disorder) |

    • ^ < 900000000000522004 | Historical association refset| {{ M targetComponentId =  < 195967001 |Asthma| }}

  • Find all the SNOMED CT concepts that map to ICD-10 code "L56.2"

    • ^ 447562003 |ICD-10 complex map refset| {{ M mapTarget = "L56.2" }}

    • ^ [referencedComponentId] 447562003 |ICD-10 complex map refset| {{ M mapTarget = "L56.2" }}

  • Find the SNOMED CT concept that maps to ICD-10 code "L56.2" with a mapRule = 1 and mapGroup = 1

    • ^ [referencedComponentId] 447562003 |ICD-10 complex map refset| {{ M mapGroup = #1, mapPriority = #1, mapTarget = "L56.2" }}

  • Find the reason that concept 67415000 |Hay asthma| was inactivated (answer: 900000000000482003 |Duplicate component|)

    • ^ [valueId] 900000000000489007 |Concept inactivation indicator attribute value refset| {{ M referencedComponentId = 67415000 |Hay asthma| }}

  • Find the active concept that is the 'same as' inactivated concept 67415000 |Hay asthma|

    • ^ [targetComponentId] 900000000000527005 |SAME AS association refset| {{ M referencedComponentId = 67415000 |Hay asthma| }}

Questions

  1. Should we allow the column headers (ie fields) from the file name and/or the refset attribute concept to be used and/or the attributeOrder?
    ANSWER: OPTION 2 only 

    • OPTION 1: ^ < 900000000000522004 | Historical association refset| {{ M [1] =  < 195967001 |Asthma| }}

      • ^ [0] < 900000000000522004 | Historical association refset| {{ M [1 /* targetComponentId */ ]=  < 195967001 |Asthma| }}

    • OPTION 2: ^ < 900000000000522004 | Historical association refset| {{ M targetComponentId =  < 195967001 |Asthma| }}

      • ^ [referencedComponentId] < 900000000000522004 | Historical association refset| {{ M targetComponentId =  < 195967001 |Asthma| }}

    • OPTION 3: ^ < 900000000000522004 | Historical association refset| {{ M [900000000000533001 |Association target component|] =  < 195967001 |Asthma| }}

      • ^ [ 449608002 ] < 900000000000522004 | Historical association refset| {{ M [900000000000533001 |Association target component|] =  < 195967001 |Asthma| }}

  2. Should we allow a 'or self' operator, to make it more efficient to create historical subsets - e.g. the following expression constraint would return all the inactive concepts that were replaced by an equivalent subtype of |Asthma| PLUS all the subtypes of |Asthma| as well. This would be useful for finding all the matches that you may need to look for in a health record.

    • FULL: < 195967001 |Asthma| OR ^ 900000000000527005 |SAME AS association refset|  {{ M targetComponentId = < 195967001 |Asthma| }}

    • SYNTACTIC SUGAR OPTIONS

      1. ^  900000000000527005 |SAME AS association refset| {{ [targetComponentId] += < 195967001 |Asthma| }}

      2. < 195967001 |Asthma| {{ += ^ [referencedComponentId] 900000000000527005 |SAME AS association refset| {{ [targetComponentId] = this }} }}

      3. < 195967001 |Asthma| {{ +M (^ 900000000000527005 |SAME AS association refset| ) targetComponentId = C }}

        1. < 195967001 |Asthma|  OR (^ 900000000000527005 |SAME AS association refset| ){{ M  targetComponentId = C }}

      4. Asthmas OR ^ 900000000000527005 |SAME AS association refset| ) {{ M targetComponentId = X}} WHERE Asthmas = < 195967001 |Asthma| 

      5. <<|asthma| ADD_TO ^ 900000000000527005 |SAME AS association refset| {{ M targetComponentId = <some keyword> }}

      6. < 195967001|Asthma| as X OR ^  900000000000527005 |SAME AS association refset|  {{ M targetComponentId = X }}

      7. [[< 195967001 @asthma]]OR ^  900000000000527005 |SAME AS association refset|  {{ M targetComponentId = @asthma }}

      8. ^  900000000000527005 |SAME AS association refset| {{ M targetComponentId = $asthma }} OR (@asthma = < 195967001)

      9. (@asthma = < 195967001) OR ^  900000000000527005 |SAME AS association refset|  {{ M targetComponentId = $asthma }}

      10.  LET X = < 196967001, Y = < 1234 IN X OR Y

      11. <<|asthma| {{ +HISTORY  90000000527005|SAME_AS|, 1234|POSSIBLY_EQUIVALENT_TO|, .... }}

      12. <<|asthma| {{ +HISTORY  < 900000000000522004 | Historical association refset|  }}

      13. <<|asthma| {{ +HISTORY }}     /* adds inactive referencedComponents with matching targetComponentId */

      14. <<|asthma| {{ +HISTORY (SAME_AS, POSSIBLY_EQUIVALENT_TO) }}

      15. <<|asthma| {{+HISTORY-A }} 

      16. <<|asthma| {{+HISTORY-B }} 

        1. ALTERNATIVE = ALTERNATIVE

        2. MOVED_FROM – not useful (but don't hurt)

        3. MOVED_TO – not useful (but don't hurt)

        4. POSSIBLY_EQUIVALENT_TO = POSS_EQUIV_TO

        5. REFERS_TO – not included??

        6. REPLACED_BY = REPLACED_BY

        7. SAME_AS = SAME_AS

        8. SIMILAR_TO  = SIMILAR_TO

        9. WAS_A  – not included??

      17. << |asthma| {{+MAP}}

  3. Should we allow more than one column in a refset to be selected? What should the rules be about using this inside a subExpressionConstraint? e.g.

    • ^ [*] 447562003 |ICD-10 complex map refset|

    • ^ [referencedComponentId, mapTarget] 447562003 |ICD-10 complex map refset|

  4. Should we allow filters to be nested inside other filters? e.g.

    • ^ 434532547 {{ M annotation = (* {{ D term = "chronic" }}) }}

    • ^ [annotation] 434532547 {{ M referencedComponent = (<< 4756478567 {{ C moduleId = 546576478 }}) }}

Suggestions from previous meetings:

  • mapOrSelfOf {{ refset = 900000000000527005 }} (<< 197710000)

  • mapOrSelfOf(sameAs, << 197710000)

  • mapOrSelfOf {{ refset = 281000036105, match = #2, result=#0 }} (386938006 OR 100005 OR 70570002)

  • mapOf {{ refset = 281000036105, match = #2, result=#0 }} (386938006 OR 100005 OR 70570002)

Reference set descriptor templates (for easy reference)

See discussion below "Querying Refset Attributes"

 onlyThe items below are currently on hold

Postcoordination Topics

 

  • Discuss feedback on transformation implementation

    • Resources

    • Recap of SNOMED on FHIR discussions

      • What is the functionality scope of a terminology server that supports postcoordination? For example, does it include:

        • Classifying multiple expressions in a single substrate? What are the use cases for this?

        • Assigning (local) identifiers to expressions? What are the use cases for this?

        • Autogenerating or assigning a term to an expression? What are the use cases for this?

      • Does a terminology server that supports postcoordination, include all the functions of an expression repository?

      • What is the relationship between a terminology server that supports postcoordination, and an expression repository?

    • Outstanding questions

      • What are the pros and cons of extending SCG to allow an expression as the focus of a postcoordinated expression?

        • Note: This was raised in context of a NNF generated over a postcoordinated substrate, where the proximal parent is an expression

      • Example of using expressions in focus concept

        • 125605004 |Fracture of bone|:363698007 |finding site| = 84167007 |Foot bone| )
          272741003 |Laterality| = 7771000 |Left|

        • 125605004 |Fracture of bone|:363698007 |finding site| = 84167007 |Foot bone| , 
          272741003 |Laterality| = 7771000 |Left|

      • What is the expected NNF when classifying an expression that is equivalent to a precoordinated concept? For example:

        • Expression that is equivalent to 111273006 |Acute respiratory disease|

        • 64572001 | Disease (disorder) | :
          {263502005 |Clinical course (attribute)| = 424124008 |Sudden onset AND/OR short duration (qualifier value)|}
          {363698007 |Finding site (attribute)| = 89187006 |Airway structure (body structure)|}

        • Options:

          1. 111273006 |Acute respiratory disease| :
            {263502005 |Clinical course| = 424124008 |Sudden onset AND/OR short duration|}
            {363698007 |Finding site| = 89187006 |Airway structure|}

          2. 50043002 |Disorder of respiratory system (disorder)| +
            2704003 |Acute disease (disorder)| :
            {263502005 |Clinical course| = 424124008 |Sudden onset AND/OR short duration|}
            {363698007 |Finding site| = 89187006 |Airway structure|}

          3. Other?

    • Recap of internal discussions with Content Team

      • Inter-attribute dependencies

      • Grouping rules

Dynamic Templates

 

  • Continue discussion on dynamic templates

    • Inter-attribute dependencies

      • Acute/Chronic and Inflammation - Adding a clinical course requires specializing the inflammation morphology 

        • E.g. |Pyelonephritis| : |Clinical course| = |Chronic|
          should be
          |Pyelonephritis| : |Clinical course| = |Chronic|, |Associated morphology| = |Chronic inflammation|

        • E.g. |Pyelonephritis| : |Clinical course| = |Sudden onset AND/OR short duration|
          should be
          |Pyelonephritis| : {|Clinical course| = |Sudden onset AND/OR short duration||, |Associated morphology| = |Acute inflammation|

      • Infectious Causative Agents - Adding a |causative agent| = |Domain Bacteria| or |Virus| requires adding a |Pathological process| = |Infectious process|

        • E.g. |Nephritis|: |Causative agent| = |Domain bacteria|
          should be
          |Nephritis|: |Causative agent| = |Domain bacteria|, |Pathological process| = |Infectious process|

      • Congenital and Acquired - Adding an |Occurrence| of |Congenital| to a focus concept with an abnormal morphology, requires adding a |Pathological process| of |Pathological development process|

        • E.g. |Koilonychia|: |Occurrence| = |Congenital|
          should be
          |Koilonychia|: |Occurrence| = |Congenital|, |Pathological process| = |Pathological developmental process|

      • Situations with Explicit Context 

      1. if the procedure context = |Planned|, then the temporal context should be << |Current of specified time|

        1. If the procedure context = |In progress|, then the temporal context should be << |Current|

        2. If the procedure context = |Performed| or |Done|, then the temporal context should be << |Current or past (actual)|

      • Note: for this use case (of |Procedure with explicit context|) perhaps we just recommend (or require) that the full role group is spelled out.

      • Next steps

        • Representation of the content rules

          • Who creates the complete list of rules and how?

            • What formalism?

            • Determine which are mandatory and which are optional

          • Implementation of content rules - e.g.

            • Guided data entry by pre-populating role groups in expression template based on definition of focus concepts (for design-time use, such as mapping)

            • Mandatory content rules could be added to transform process

Postcoordination Use Case Examples

All

Example 1 - Dentistry / Odontogram

  • Requires an expression template to create expressions.

  • Resulting expression still requires a transformation to make it classifiable

Example 2 - Terminology binding

  • Uses a fixed expression template to combine codes entered into separate fields

  • The procedure+laterality example still requires a transformation to make it classifiable

Example 3 - Mapping

  • Design-time activity

  • Map targets may not be able to be fully represented using concept model attributes

  • In many cases, an extension (with primitive concepts) should be recommended where there are gaps in the mapping

  • There may be some cases in which postcoordination is helpful (e.g. LOINC to SNOMED CT map)

Example 4 - Natural Language Processing

  • Usually run-time activity.

  • May require manual confirmation of coding suggestions (unless low clinical risk, eg for suggesting relevant patient records for manual review)

Postcoordination Guidance

@Former user (Deleted) , @Anne Randorff Højen , @Kai Kewley

Practical Guide to Postcoordination

Copyright © 2026, SNOMED International