w3c / hcls-fhir-rdf

Sketching out an RDF representation for FHIR
38 stars 15 forks source link

How should list ordering be preserved in R5? #76

Closed dbooth-boston closed 1 year ago

dbooth-boston commented 4 years ago

FHIR requires that item order be preserved in lists, but native RDF list support is terrible. How should FHIR RDF retain item ordering when a list is given?

Example JSON:

{
  "resourceType": "Patient",
  "id": "example",
  "name": [              # Outer list
    {
      "family": "Chalmers",
      "given": [           # Inner list
        "Peter",
        "James"
      ]
    }
  ]
}

Option 0: Do nothing. Keep the R4 representation, which uses fhir:index to indicate the relative ordering of items in a list.

Example Turtle:

ex:example a  fhir:Patient ;
    fhir:Resource.id  [ fhir:value  "example"  ] ;
    fhir:Patient.name  [        # Outer list item
        fhir:index  0
        fhir:HumanName.family  [ fhir:value  "Chalmers"  ] ;
        fhir:HumanName.given  [ # Inner list item
            fhir:index  1  ;
            fhir:value  "James"  ] ;
        fhir:HumanName.given  [ # Inner list item
            fhir:index  0  ;
            fhir:value  "Peter"  ] ;
        ] .

Note that if bnode and fhir:value are removed, per issue 77 option 3b, then fhir:value would still be needed for primitive list items, to attach the fhir:index:

ex:example a  fhir:Patient ;
    fhir:Resource.id  "example" ;
    fhir:Patient.name  [        # Outer list item
        fhir:index  0
        fhir:HumanName.family "Chalmers" ;
        fhir:HumanName.given  [ # Inner list item
            fhir:index  1  ;
            fhir:value  "James"  ] ;
        fhir:HumanName.given  [ # Inner list item
            fhir:index  0  ;
            fhir:value  "Peter"  ] ;
        ] .

Option 1: Set with parallel RDF list. See https://github.com/fhircat/fhir_rdf_validator/blob/master/tutorial/FHIRR5.md In this option, each JSON list is represented in RDF both as an unordered set of values and as an RDF list. Note that in this example, the outer set has only one item, so when it is repeated as a list, it looks almost identical.

Example Turtle:

ex:example a  fhir:Patient ;
    fhir:Resource.id  [ fhir:value  "example"  ] ;
    fhir:Patient.name  [                            # Outer set item
        fhir:HumanName.family  [ fhir:value  "Chalmers"  ] ;
        fhir:HumanName.given "James" ;              # Inner set item
        fhir:HumanName.given "Peter" ;              # Inner set item
        fhir:HumanName.given ( "James" "Peter" ) ;  # Inner list
        ] ;
    fhir:Patient.name  ( [      # Outer list
        fhir:HumanName.family  [ fhir:value  "Chalmers"  ] ;
        fhir:HumanName.given "James" ;              # Inner set item
        fhir:HumanName.given "Peter" ;              # Inner set item
        fhir:HumanName.given ( "James" "Peter" ) ;  # Inner list
        ] ) .

Pros:

Cons:

dbooth-boston commented 4 years ago

List ordering option 2: parallel explicit index list. Similar to option 1, but using an explicit index using OLO or other conventions instead of a standard RDF list.

# Option 2: Similar to option 1, but using OLO.
ex:example a  fhir:Patient ;
    fhir:Resource.id  [ fhir:value  "example"  ] ;
    fhir:Patient.name  [                            # Outer set item
        fhir:HumanName.family  [ fhir:value  "Chalmers"  ] ;
        fhir:HumanName.given "James" ;              # Inner set item
        fhir:HumanName.given "Peter" ;              # Inner set item
        fhir:HumanName.given [                      # Inner list
            a olo:OrderedList ;
            olo:slot [ olo:index 1 ; olo:item "James" ] ;
            olo:slot [ olo:index 2 ; olo:item "Peter" ] ;
            ]
        ] ;
    fhir:Patient.name  [        # Outer list
        a olo:OrderedList ;
        olo:slot [
            fhir:HumanName.family  [ fhir:value  "Chalmers"  ] ;
            fhir:HumanName.given "James" ;              # Inner set item
            fhir:HumanName.given "Peter" ;              # Inner set item
            fhir:HumanName.given [                      # Inner list
                a olo:OrderedList ;
                olo:slot [ olo:index 1 ; olo:item "James" ] ;
                olo:slot [ olo:index 2 ; olo:item "Peter" ] ;
                ]
            ]
        ] . 

Pros:

Cons:

schema.org uses an explicit 1-based position property:

dbooth-boston commented 4 years ago

List ordering option 3: Only use regular RDF lists

This example assumes that we also change to eliminate the extra bnode and fhir:value, per issue #77 option 3b.

ex:example a  fhir:Patient ;
    fhir:Resource.id  [ fhir:value  "example"  ] ;
    fhir:Patient.name  ( [                          # Outer list 
        fhir:HumanName.family "Chalmers" ;
        fhir:HumanName.given ( "James" "Peter" ) ;  # Inner list
        ] ) .
dbooth-boston commented 4 years ago

List ordering option 4: parallel indexed list, but using a separate attribute. Similar to option 1, but instead of putting the parallel index list under the same attribute, put it under an ordered attribute. This would be analogous to extension option 1 (Put extensions under a sibling extension property: https://github.com/fhircat/FHIRCat/issues/31#issuecomment-589277765

ex:example a  fhir:Patient ;
    fhir:Resource.id  [ fhir:value  "example"  ] ;
    fhir:Patient.name  [                            # Outer set item
        fhir:HumanName.family  [ fhir:value  "Chalmers"  ] ;
        fhir:HumanName.given "James" ;              # Inner set item
        fhir:HumanName.given "Peter" ;              # Inner set item
        fhir:HumanName.givenList ( "James" "Peter" ) ;  # Inner list
        ] ;
    fhir:Patient.nameList  ( [  # Outer list
        fhir:HumanName.family  [ fhir:value  "Chalmers"  ] ;
        fhir:HumanName.given "James" ;              # Inner set item
        fhir:HumanName.given "Peter" ;              # Inner set item
        fhir:HumanName.givenList ( "James" "Peter" ) ;  # Inner list
        ] ) .

Pros:

Cons:

balhoff commented 2 years ago

Discussion on call on 2021-10-21:

An open question is whether the redundant information is worth it in this case, given that the indexed version will always be present.

Todo: Ensure that it is explicitly stated somewhere that the indexes need to be in sequence, starting from 0 (in the event this applies to the selected model).

dbooth-boston commented 2 years ago

Link to minutes: https://www.w3.org/2021/11/11-hcls-minutes.html#t01

dbooth-boston commented 2 years ago

See Turtle examples:

balhoff commented 2 years ago

In the last meeting, we discussed whether using native RDF lists would interfere with treating the RDF rendering as an OWL document. I think that may be the case: the OWL 2 Web Ontology Language Structural Specification and Functional-Style Syntax says:

In order to use an OWL reasoner on the contents of lists we would need to treat rdf:first and rdf:rest as object properties.

balhoff commented 2 years ago

Some previous discussions touching on use of rdf:List within OWL data:

balhoff commented 2 years ago

Notes on OWL compatibility with RDF lists: https://docs.google.com/document/d/1kNkP0EHfUiEj9GwO4NtzHXQD4kVTViphV0ngGfHBnBI/edit?usp=sharing

csisc commented 2 years ago

Just a side proposal: What do you think of using rdf:bag and rdf:seq.

csisc commented 2 years ago

As a medical student, I probably should evocate the significance of order in certain situations.

csisc commented 2 years ago

Symptoms can change their characteristics according to the evolution of the condition:

dbooth-boston commented 2 years ago

Just a side proposal: What do you think of using rdf:bag and rdf:seq.

That could be a possibility in theory, but the motivation behind this issue is to enable conventional RDF lists (a/k/a RDF Collections) to be used in FHIR RDF, using the Turtle short-hand syntax.

dbooth-boston commented 2 years ago

Symptoms can change their characteristics according to the evolution of the condition: . . .

Yes, the order of events is crucial in healthcare. However, from what I've seen, most of the time-ordered events that are recorded in medical records have individual timestamps on them anyway -- allowing them to be unambiguously ordered -- so they are usually stored as separate events rather than storing them as a list per se. However, some properties allow a list of entries to be provided -- such as a patient contact or address -- and the order of items in the list is sometimes used to indicate precedence.

ericprud commented 2 years ago

Just a side proposal: What do you think of using rdf:bag and rdf:seq.

I don't think that helps. The prob is not the first/rest ladder, but instead the expression of axioms on properties in the rdf: namespace. I think we have to roll our own property.

dbooth-boston commented 2 years ago

Discussed on 04-Aug-2022, 09-Aug-2022, 11-Aug-2022

dbooth-boston commented 2 years ago

To summarize my view, I think we'd be losing more than we're gaining by switching to RDF lists, because:

  1. They don't play well with OWL
  2. They don't play well with SPARQL
  3. They don't add much syntactic benefit, because elements in FHIR lists are always complex objects anyway, so the list syntax gets visually lost. The only visual clue is the lack of semicolons between items. See example below.
  4. We don't have RDF lists in R4, so there would be less change to R5.

Example JSON:

##### Example exJson:
      "coding": [
        {
          "system": "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation",
          "code": "H",
          "display": "High"
        },
        {
          "system": "http://example.com/Observation",
          "code": "Hi",
          "display": "High"
        },
        {
          "system": "http://example.orgObs",
          "code": "H",
          "display": "Highest"
        }

With RDF lists:

##### Example exWithListsTurtle
... fhir:coding (
        [
          a <http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation/H>;
          fhir:system [
            notrdf:value "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation"^^xsd:anyURI
          ];
          fhir:code [
            notrdf:value "H"
          ];
          fhir:display [
            notrdf:value "High"
          ]
        ]
        [
          a <http://example.com/Observation/Hi>;
          fhir:system [
            notrdf:value "http://example.com/Observation"^^xsd:anyURI
          ];
          fhir:code [
            notrdf:value "Hi"
          ];
          fhir:display [
            notrdf:value "High"
          ]
        ]
        [
          a <http://example.orgObs/H>;
          fhir:system [
            notrdf:value "http://example.orgObs"^^xsd:anyURI
          ];
          fhir:code [
            notrdf:value "H"
          ];
          fhir:display [
            notrdf:value "Highest"
          ]
        ]
      )

Without RDF lists:

##### Example exWithoutListsTurtle
... fhir:coding [
      a <http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation/H>;
      fhir:system [
        notrdf:value "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation"^^xsd:anyURI
      ];
      fhir:code [
        notrdf:value "H"
      ];
      fhir:display [
        notrdf:value "High"
      ];
      fhir:index 0
    ], [
      a <http://example.com/Observation/Hi>;
      fhir:system [
        notrdf:value "http://example.com/Observation"^^xsd:anyURI
      ];
      fhir:code [
        notrdf:value "Hi"
      ];
      fhir:display [
        notrdf:value "High"
      ];
      fhir:index 1
    ], [
      a <http://example.orgObs/H>;
      fhir:system [
        notrdf:value "http://example.orgObs"^^xsd:anyURI
      ];
      fhir:code [
        notrdf:value "H"
      ];
      fhir:display [
        notrdf:value "Highest"
      ];
      fhir:index 2
    ];
csisc commented 2 years ago

I have seen the W3C discussions. I found https://lists.w3.org/Archives/Public/public-owl-wg/2008Jun/0070.html as a solution.

csisc commented 2 years ago

To explain the proposal, there are slides proposed by Drummond at https://protege.stanford.edu/conference/2006/submissions/slides/7.1_Drummond.pdf. Please see the part about OWL lists.

dbooth-boston commented 2 years ago

Thanks, @csisc , for finding that. David Wood and James Leigh also made a proposal at the 2009 W3C RDF Next Steps workshop to add ordered lists to RDF as a fundamental concept, instead of the makeshift first/rest ladder that RDF currently has for them. I personally think that ordered lists should be a fundamental concept in RDF, rather than continuing to try to retrofit onto a first/rest ladder. It is a blatant gap in RDF. To quote Manu Sporny (inventor of JSON-LD):

RDF is a shitty data model. It doesn’t have native support for lists. LISTS for fuck’s sake! The key data structure that’s used by almost every programmer on this planet and RDF starts out by giving developers a big fat middle finger in that area.

But I think RDF lists as a built-in type will have to wait until RDF 2.0. :)

dbooth-boston commented 2 years ago

On today's call we reached consensus to go ahead with RDF lists in R5:

AGREED: Adopt RDF lists

dbooth-boston commented 1 year ago

Done in R5.