Page tree

Date & Time

20:00 to 21:00 UTC Wednesday 2nd December 2020


Zoom meeting link (password: 764978)


  • Discuss a few ECL questions
  • Consider postcoordination use cases


Agenda and Meeting Notes




Welcome and agenda


  • This is the last meeting for 2020
  • Meetings will resume in 2021 on Wednesday 27th January.
ECL Quick Reference

On request, we have developed an ECL Quick Reference page with a summary of the ECL syntax and examples.

Could the SLPG please review this page, and provide feedback. We plan to publish this as soon as possible.

ECL and Concrete Values

For discussion:

Postcoordination Use Case ExamplesAll

Example 1 - Mapping

Example 2 - Terminology binding

Example 3 - Dentistry / Odontogram

Example 4 - Natural Language Processing

Postcoordination Guidance

Practical Guide to Postcoordination

  • Proposal - Use syntax (i.e. braces) to distinguish refinement vs new role group
  • Proposal: Expression forms needed for this (see 3.4 Transforming Expressions)
    • Close to user form - e.g. 83152002 |Oophorectomy|  405815000 |Procedure device|  =  122456005 |Laser device|
    • Canonical close to user form - e.g. 83152002:405815000=122456005
    • Classifiable form (SCG) - e.g. 83152002:{260686004=129304002,405813007=15497006,405815000=122456005}
      • PLUS Classifiable form (OWL) - e.g.  
        • EquivalentClasses(:123063
             ObjectIntersectionOf (:71388002
                 ObjectSomeValuesFrom(:609096000 ObjectIntersectionOf( ObjectSomeValuesFrom(:260686004 :129304002)
                 ObjectSomeValuesFrom(:405813007 :15497006))))
    • Necessary normal form - e.g. 83152002+416376001:{260686004=129304002,405813007=15497006,405815000=122456005}
      • PLUS Necessary normal form (tables)
        • Relationships:
          • (123063 116680003 83152002) - 0
          • (123063 260686004 129304002) - 0 
          • (123063 405813007 15497006) - 1
          • (123063 405815000 122456005) - 1
    • Primitive expressions - "<<<" (only useful in a mapping context) → .... relies on the assigned identifier (which are necessarily semantically unique).
The items below are currently on hold
Other Options for Future Progress
  1. URIs for draft editions
  2. ECL extensions
    1. Primitive/Defined filters → concept filter
    2. Concept+Description filters (e.g. effectiveTime, module, active)
    3. Accessing Refset attributes → (e.g. historical association refsets) → historical ECL
    4. OR use full syntax to be able to query any table (e.g. Relationship table) - ie expand ECL into something more verbose (e.g. SNOMED query language)
  3. Template extensions
URIs for Extended Editions

ON HOLD - How to refer to an 'extended edition' using a URI - e.g. "International Edition plus the following 2 nursing modules: 733983009  |IHTSDO Nursing Health Issues module|and 733984003 |IHTSDO Nursing Activities module|

Use Case - Need to execute an ECL, that refers to "^ 733991000 | Nursing Health Issues Reference Set (foundation metadata concept) |" and/or "^ 733990004 | Nursing Activities Reference Set (foundation metadata concept) |", where the substrate includes the international edition, plus the modules that include these reference sets

July 2020 International Edition URI:

July 2020 International Edition + nursing modules URI ?? - For example:

Querying Refset AttributesLinda Bird

ON HOLD - Proposed syntax to support querying and return of alternative refset attributes (To be included in the SNOMED Query Language)

  • Example use cases
    • Execution of maps from international substance concepts to AMT substance concepts
    • Find the anatomical parts of a given anatomy structure concept (in |Anatomy structure and part association reference set)
    • Find potential replacement concepts for an inactive concept in record
    • Find the order of a given concept in an Ordered component reference set
    • Find a concept with a given order in an Ordered component reference set
  • Potential syntax to consider (brainstorming ideas)
    • SELECT ??
      • SELECT 123 |referenced component|, 456 |target component|
        FROM 799 |Anatomy structure and part association refset|
        WHERE 123 |referenced component| = (< 888 |Upper abdomen structure| {{ term = "*heart*" }} )
      • SELECT id, moduleId
        FROM concept
        WHERE id IN (< |Clinical finding|)
        AND definitionStatus = |primitive|
      • SELECT id, moduleId
        FROM concept, ECL("< |Clinical finding") CF
        WHERE = CF.sctid
        AND definitionStatus = |primitive|
      • SELECT ??? |id|, ??? |moduleId|
        FROM concept ( < |Clinical finding| {{ term = "*heart*" }} {{ definitionStatus = |primitive| }} )
      • Question - Can we assume some table joins - e.g. = Description.conceptId etc ??
      • Examples
        • Try to recast relationships table as a Refset table → + graph-based extension
        • Find primitive concepts in a hierarchy
    • ROW ... ?
      • ROWOF (|Anatomy structure and part association refset|) ? (|referenced component| , |target component|)
        • same as: ^ |Anatomy structure and part association refset|
      • ROWOF (|Anatomy structure and part association refset|) . |referenced component|
        • same as: ^ |Anatomy structure and part association refset|
      • ROWOF (|Anatomy structure and part association refset|) {{ |referenced component| = << |Upper abdomen structure|}} ? |targetComponentId|
      • ROWOF (< 900000000000496009|Simple map type reference set| {{ term = "*My hospital*"}}) {{ 449608002|Referenced component| = 80581009 |Upper abdomen structure|}} ? 900000000000505001 |Map target|
        • (ROW (< 900000000000496009|Simple map type reference set| {{ term = "*My hospital*"}}) : 449608002|Referenced component| = 80581009 |Upper abdomen structure| ).900000000000505001 |Map target|
    • # ... ?
      • # |Anatomy structure and part association refset| ? |referenced component\
      • # (|Anatomy struture and part association refset| {{|referenced component| = << |Upper abdomen structure|) ? |targetComponentid|
    • ? notation + Filter refinement
      • |Anatomy structure and part association refset| ? |targetComponentId|
      • |Anatomy structure and part association refset| ? |referencedComponent| (Same as ^ |Anatomy structure and part association refset|)
        (|Anatomy structure and part association refset| {{ |referencedComponent| = << |Upper abdomen structure}} )? |targetComponentId|
      • ( |Anatomy structure and part association refset| {{ |targetComponentId| = << |Upper abdomen structure}} ) ? |referencedComponent|
      • ( |My ordered component refset|: |Referenced component| = |Upper abdomen structure ) ? |priority order|
      • ? |My ordered component refset| {{ |Referenced component| = |Upper abdomen structure| }} . |priority order|
      • ? |My ordered component refset| . |referenced component|
        • equivalent to ^ |My ordered component refset|
      • ? (<|My ordered component refset|) {{ |Referenced component| = |Upper abdomen structure| }} . |priority order|
      • ? (<|My ordered component refset| {{ term = "*map"}} ) {{ |Referenced component| = |Upper abdomen structure| }} . |priority order|
      • REFSETROWS (<|My ordered component refset| {{ term = "*map"}} ) {{ |Referenced component| = |Upper abdomen structure| }} SELECT |priority order|
    • Specify value to be returned
      • ? 449608002 |Referenced component|?
        734139008 |Anatomy structure and part association refset|
      • ^ 734139008 |Anatomy structure and part association refset| (Same as previous)
      • ? 900000000000533001 |Association target component|?
        734139008 |Anatomy structure and part association refset|
      • ? 900000000000533001 |Association target component|?
        734139008 |Anatomy structure and part association refset| :
        449608002 |ReferencedComponent| = << |Upper abdomen structure|
      • ? 900000000000533001 |Association target component|?
        734139008 |Anatomy structure and part association refset|
        {{ 449608002 |referencedComponent| = << |Upper abdomen structure| }}
      • (? 900000000000533001 |Association target component|?
        734139008 |Anatomy structure and part association refset| :
        449608002 |ReferencedComponent| = (<< |Upper abdomen structure|) : |Finding site| = *)
Returning AttributesMichael Lawley

ON HOLD - Proposal (by Michael) for discussion

  • Currently ECL expressions can match (return) concepts that are either the source or the target of a relationship triple (target is accessed via the 'reverse' notation or 'dot notation', but not the relationship type (ie attribute name) itself. 

For example, I can write: 

<< 404684003|Clinical finding| : 363698007|Finding site| = <<66019005|Limb structure| 

<< 404684003|Clinical finding| . 363698007|Finding site| 

But I can't get all the attribute names that are used by << 404684003|Clinical finding| 

    • Perhaps something like:
      • ? R.type ? (<< 404684003 |Clinical finding|)
    • This could be extended to, for example, return different values - e.g.
      • ? |Simple map refset|.|maptarget| ? (^|Simple map refset| AND < |Fracture|)
Reverse Member OfMichael Lawley

ON HOLD - Proposal for discussion

What refsets is a given concept (e.g. 421235005 |Structure of femur|) a member of?

  • Possible new notation for this:
    • ^ . 421235005 |Structure of femur|
    • ? X ? 421235005 |Structure of femur| = ^ X

Expression Templates

  • WIP version -
      • Added a 'default' constraint to each replacement slot - e.g. default (72673000 |Bone structure (body structure)|)
      • Enabling 'slot references' to be used within the value constraint of a replacement slot - e.g. [[ +id (<< 123037004 |Body structure| MINUS << $findingSite2) @findingSite1]]
      • Allowing repeating role groups to be referenced using an array - e.g. $rolegroup[1] or $rolegroup[!=SELF]
      • Allow reference to 'SELF' in role group arrays
      • Adding 'sameValue' and 'allOrNone' constraints to information slots - e.g. sameValue ($site), allOrNone ($occurrence)
      • See changes in red here: 5.1. Normative Specification


[[+id]]: [[1..*] @my_group sameValue(morphology)] { |Finding site| = [[ +id (<<123037004 |Body structure (body structure)| MINUS << $site[! SELF ] ) @site ]] , |Associated morphology| = [[ +id @my_morphology ]] }

  • Implementation feedback on draft updates to Expression Template Language syntax
    • Use cases from the Quality Improvement Project:
      • Multiple instances of the same role group, with some attributes the same and others different. Eg same morphology, potentially different finding sites.

Note that QI Project is coming from a radically different use case. Instead of filling template slots, we're looking at existing content and asking "exactly how does this concept fail to comply to this template?"

For discussion:

 [[0..1]] { [[0..1]]   246075003 |Causative agent|  = [[+id (<   410607006 |Organism| ) @Organism]] }

Is it correct to say either one of the cardinality blocks is redundant? What are the implications of 1..1 on either side? This is less obvious for the self grouped case.

Road Forward for SI

  1. Generate the parser from the ABNF and implement in the Template Service
  2. User Interface to a) allow users to specify template at runtime b) tabular (auto-completion) lookup → STL
  3. Template Service to allow multiple templates to be specified for alignment check (aligns to none-off)
  4. Output must clearly indicate exactly what feature of concept caused misalignment, and what condition was not met.

Additional note: QI project is no longer working in subhierarchies. Every 'set' of concepts is selected via ECL. In fact most reports should now move to this way of working since a subhierarchy is the trivial case. For a given template, we additionally specify the "domain" to which it should be applied via ECL. This is much more specific than using the focus concept which is usually the PPP eg Disease.

FYI Michael Chu

Description TemplatesKai Kewley
  • Previous discussion (in Malaysia)
      • Overview of current use
      • Review of General rules for generating descriptions
        • Removing tags, words
        • Conditional removal of words
        • Automatic case significance
        • Generating PTs from target PTs
        • Reordering terms
      • Mechanism for sharing general rules - inheritance? include?
      • Description Templates for translation
      • Status of planned specification
Query Language
- Summary from previous meetings


Examples: version and dialect


    • Allow nested where, version, language
    • Scope of variables is inner query

  • No labels


  1. Happy new year.

    Is there any chance someone could post a snapshot copy of the draft 'Postcoordination use cases' document? For whatever reason I'm unable to access the copy on Google docs. I know this means that I'll miss out on the 'live document' experience, but the alternative is that I can't see anything!

    Kind regards


    1. Hi Ed Cheetham, I've just updated the permissions so that no sign in is required to view the draft 'Postcoordination use cases' document.

  2. A few thoughts on the Post-coordination use cases document:

    This is a fair start, but as raised back in October, ‘post-coordination’ consists of several related activities and challenges including, at least:

    • Compositional expression creation
    • Composition expression analysis (including transformation and classification – the ‘coordination’ step)
    • Compositional expression communication

    The ongoing ‘close-to-user’ and ‘expression transformation’ debates indicate that the SI community appreciate this complexity, but the current document focuses largely on the first one. Until the ‘use cases’ actively consider the additional steps and activities, there remains a perception (with all attendant risks) that the ‘challenge’ of post-coordination is limited to the ‘compositional expression creation’ recording’ step.

    The mapping and terminology binding use cases, in particular, are framed in terms of compositional expression creation goals, but are (except for the ‘classifiable form’ column) silent on other stages.

    Introducing a use case worded as ‘as a clinician, I want the procedure I record in my operating theatre system to be available on the national summary record and used in the letter I send to the GP and patient’ might draw attention to communication and interoperability challenges, not least ‘what will the human-readable display name of the procedure be?’. In the ‘mapping’ example this could well be the interface term of the local coding scheme (so no problem), but if the procedure record has been constructed from components selected from several fields (as in the binding case), then although the dispersed form may be perfectly understandable when re-displayed in the creating system, no single serializable term is available for display in alternative contexts.

    Introducing a use case of ‘as a clinician, when recording a disorder or procedure, I only want to be offered the right and left variants of bilaterally symmetrical body structures where these exist (and have not been already selected)’ seems reasonable too. If SNOMED CT is expected drive this sort of interface behaviour, this use case shines a light on the reference data itself: although, I’m sure, almost perfect in its membership, there are still errors in the lateralisable body structure refset (e.g. 727986007 |Entire optic chiasma (body structure)| and 59011009 |Structure of basilar artery (body structure)| - both midline structures - are in the set, whilst 787050004 |Structure of joint region of lower extremity (body structure)| is not), but even if the refset were perfect, ideal interface behaviour depends upon the disorders and findings themselves being correctly modelled.

    I am pleased to see an early attempt to represent IF/THEN logic for the @temporalContext slot in the odontogram example. I expect that, for all but the simplest expression composition templates there will be plenty of boilerplate and authoring business rules that will need to be captured and distributed this way in order to create analysable data. I also note the notion of a ‘hidden’ slot in the data entry form selection – this is understandable to me, but all these extra layers of necessary complexity need to be available and understandable to implementers before ‘post-coordination’ can proceed in a risk managed way.

    We could introduce the use case of ‘as an analyst, I want to be able to retrieve compositional expressions alongside pre-coordinated content in a predictable way’. Just looking at the handful of examples in this document I can see trouble here:

    Based on their experience of working elsewhere in the terminology, an analyst may well base their query predicates on existing reference concepts and modelling. Let’s say they are interested in identifying all records containing ‘enthesopathy of foot’. They see that SNOMED CT already has 240028007 |Enthesopathy of foot region (disorder)| and base their retrieval predicate on the PPS and role modelling of this concept. They will not be able to retrieve the suggested expressions associated with the interface term ‘Enthesopathy of lower limb, foot’ in the mapping example, and would not know if they were missing them. How are they to know when to base their queries on the reference data and when to use alternative approaches?

    They will also say ‘as an analyst, I would like to retrieve compositional expressions that were recorded any time over the last ten years’. We are well aware that the reference data changes between releases, but compositional expressions – especially the ‘close-to-user’ ones will be fixed with the modelling that applied at the time of their creation (even if extraneous noise is limited by a close-to-user approach, the attribute=value pairs used may change). Should analysts construct families of queries based upon evolving reference definitions as attribute names, attribute values, role grouping and other modelling conventions change over time, or will these design variants be somehow tracked in the reference product?

    I appreciate these comments look very critical, but I hope they are taken in the constructive spirit with which they are intended.


    1. I agree with Ed here.  As I see it the issue we're wrestling with is not "do we support compositional expressions", it is about how we support it, and more specifically, whether one of those ways is view a close-to-user form.

      To that end, the use cases need to include sufficient detail that we understand whether or how a close-to-user form would be used.

      Taking the second case above "as a clinician, when recording a disorder or procedure, I only want to be offered the right and left variants of bilaterally symmetrical body structures where these exist (and have not been already selected)", I can see (e.g., as demonstrated in that this is possible without the clinician being exposed to any compositional expression.  However, that opens a different use case "as a developer, when a disorder or procedure is selected along with an appropriate laterality, I need to be able to record this information in a single field".  This use case is clearly different in nature to a clinician composing an expression because now the expression will be assembled by software, and that software can reasonably be assumed to have full access to (at least) the inferred form of the disorder or procedure being refined.