Solid + FHIR is FAIR




Eric Prud'hommeaux



SWAT4LS Dec 2019

JD logo
JD logo
  • 10+ years of organic growth
  • 80+ visionaries; accomplished engineers and architects.
  • HQ in Boston, MA, offices in Charlotte, NC, France, and Costa Rica
  • Named a ‘Cool Vendor’ in Gartner’s Business and IT Services Report
  • Named a ‘Vendor To Watch’ by Gartner

Since 2009, Janeiro Digital has been executing some of the most complex technologies behind high-end, mission-critical digital transformations.

From ensuring that nuclear plants don’t melt down to rearchitecting and launching one of the largest online retailers, we’ve done it all.

W3C logo

Goals of Solid?

user Pods:

W3C logo

What is Solid?

What is Solid to you?

W3C logo

SemWeb Technologies

CategoryNameTypeDescriptionStatus
CoreURIProtocolUniversal Resource Identifier1998 Internet Standard
CoreHTTPProtocolHypertext Transport Protocol1999 Internet Standard
CoreRDF/XMLData FormatRDF serialization in XML2004 Recommendation
CoreTurtleData FormatAlternate, more human readable RDF serialization2011 Team Submission
Core+SPARQLQuery + UpdateSPARQL is to RDF what SQL is to RDBMS2008 1.0 Recommendation2011 1.1 Last Call Draft
Core+SPARQL Graph Store HTTP ProtocolProtocolHTTP/REST for managing RDF graphs2011 Last Call Draft
Semantic AnalysisRDFSSchemaSchema language for defining vocabularies2004 Recommendation
Semantic AnalysisOWLSchemaRicher schema language for defining ontologies2009 Recommendation
BridgeRDFaData FormatRDF serialization for embedding in HTML pages2008 1.0 Recommendation2011 1.1 Last Call Draft
BridgeR2RMLData FormatLanguage to define mappings of relational data to RDF2011 Working Draft
BridgeDirect Mapping of Relational Data to RDFData FormatStandard mapping of relational data to RDF2011 Working Draft

Resource-oriented architecture

Resource-oriented architecture

Five star data

"The spec on a cup"

LOD mug

★ Available on the web (whatever format) but with an open licence, to be Open Data
★★ Available as machine-readable structured data (e.g. excel instead of image scan of a table)
★★★ As (2) plus non-proprietary format (e.g. CSV instead of excel)
★★★★ All the above plus, Use open standards from W3C (RDF and SPARQL) to identify things, so that people can point at your stuff
★★★★★ All the above, plus: Link your data to other people’s data to provide context

Emphasizes Open data

SemWeb Technologies

LOD mug

What is LDP?

W3C logo

Cast of characters

Linked data plus:

LDP Resources (LDPRs)

GET simple example

Resource-oriented architecture

LDP Containers (LDPCs)

LDPC GET simple example

Resource-oriented architecture

LDPC GET updated

Resource-oriented architecture

Re-using application's membership

PREFIX ns0: <http://example.org/ontology/>
PREFIX dc: <http://purl.org/dc/terms/>
PREFIX ns1: <http://www.w3.org/ns/ldp#>

<http://example.org/netWorth/nw1>
  a <http://example.org/ontology/NetWorth> ;
  ns0:asset <http://example.org/netWorth/nw1/assetContainer/a1>, <http://example.org/netWorth/nw1/assetContainer/a2> .

<http://example.org/netWorth/nw1/assetContainer>
  a <http://www.w3.org/ns/ldp#DirectContainer> ;
  dc:title "The assets of JohnZSmith" ;
  ns1:membershipResource <http://example.org/netWorth/nw1> ;
  ns1:hasMemberRelation ns0:asset .

What about non-RDF data?

W3C logo

Some vestigial files still aren't RDF!

LDP-NRs in Indirect Containers

W3C logo

LDP-NRs in Platform-specific metadata

W3C logo

Authentication integration

Solid leverages OAuth2 / OpenID Connect

  1. Solid as the Resource Server and Identity Provider
  2. Solid as the Resource Server with separate Enterprise Identity Provider (e.g. Okta, Ping, Auth0)

Both work.

#1 works with e.g. Active Directory, LDAP.

FHIR

Resource-oriented architecture

simultaneous display of diagnosis-related resources

FHIR Resource Schemas

FHIR Observation resource

FHIR/RDF Resource Schemas

FHIR Observation ShEx

Many languagess

Reasoning

TermInfo Opportunity

image/svg+xml Diagnosis Evidence Evidence Rectord Target IsabellaJones NEXTGENMedicalPractice PATIENTRole recordTarget player scoper ClinicalDocument Diagnosis 282291009 20130605 20130602 SNOMED Encounter REFR DRIV DRIV 20130131 inpatient Information Model

TermInfo Opportunity

image/svg+xml Terminology Model Diagnosis 282291009

TermInfo Opportunity

image/svg+xml Diagnosis Evidence Evidence Rectord Target IsabellaJones NEXTGENMedicalPractice PATIENTRole recordTarget player scoper ClinicalDocument Diagnosis 282291009 20130605 20130602 SNOMED Encounter REFR DRIV DRIV 20130131 inpatient Information Model Terminology Model Diagnosis 282291009

TermInfo example

amy:Obs1 a fhir:Observation;
   fhir:Observation.code      [
      a fhir:CodeableConcept;
      fhir:CodeableConcept.coding [
         a fhir:Coding;
         fhir:Coding.system       [ fhir:value "http://snomed.info/sct" ];
         fhir:Coding.code         [ fhir:value "69896004" ]
      ]
   ]
.

Start with a rich predicate ontology

fhir:Patient a owl:Class ; rdfs:label "fhir patient" .
fhir:Observation.code a owl:ObjectProperty; rdfs:label "fhir:Observation.code" .
fhir:CodeableConcept.coding a owl:ObjectProperty; rdfs:label "fhir:CodeableConcept.coding" .
fhir:Coding.system a owl:ObjectProperty; rdfs:label "fhir:Coding.system" .
fhir:Coding.code a owl:ObjectProperty; rdfs:label "fhir:Coding.code" .
fhir:value a owl:DatatypeProperty; rdfs:label "fhir value" .

look for the code

fhir:Observation.code some (
  fhir:CodeableConcept.coding some (
    fhir:Coding.code some (fhir:value value "69896004") ) )

Data:

amy:Obs1 a fhir:Observation;
   fhir:Observation.code      [
      a fhir:CodeableConcept;
      fhir:CodeableConcept.coding [
         a fhir:Coding;
         fhir:Coding.system       [ fhir:value "http://snomed.info/sct" ];
         fhir:Coding.code         [ fhir:value "69896004" ]
      ]
   ] .

look for the code

fhir:Observation.code some (
  fhir:CodeableConcept.coding some (
    fhir:Coding.code some (fhir:value value "69896004") ) )

fhir:Observation-of-Rheumatoid_arthritis-disorder a owl:Class ;
    rdfs:label "fhir Observation of Rheumatoidarthritis (disorder)" ;
    owl:equivalentClass [
        owl:onProperty fhir:Observation.code ;
        owl:someValuesFrom [
            owl:onProperty fhir:CodeableConcept.coding ;
            owl:someValuesFrom [
                owl:onProperty fhir:Coding.code ;
                owl:someValuesFrom [
                    owl:onProperty fhir:value ;
                    owl:hasValue "69896004"
                ]
            ]
        ]
    ]
.

what about the system?

 fhir:Observation.code some (
   fhir:CodeableConcept.coding some (
     fhir:Coding.system some (fhir:value value "http://snomed.info/sct")
     and fhir:Coding.code some (fhir:value value "69896004") ) )
fhir:Observation-of-Rheumatoid_arthritis-disorder a owl:Class ;
    rdfs:label "fhir Observation of Rheumatoidarthritis (disorder)" ;
    owl:equivalentClass [
        owl:onProperty fhir:Observation.code ;
        owl:someValuesFrom [
            owl:onProperty fhir:CodeableConcept.coding ;
            owl:someValuesFrom [ owl:intersectionOf (
              [ owl:onProperty fhir:Coding.code ;
                owl:someValuesFrom
                  [ owl:onProperty fhir:value ;
                    owl:hasValue "69896004" ] ]
              [ owl:onProperty fhir:Coding.system ;
                owl:someValuesFrom
                  [ owl:onProperty fhir:value ;
                    owl:hasValue "http://snomed.info/sct"
                ] ]
            ) ]
        ]
    ]
.

can't reason about literals

[ owl:intersectionOf (
  [ owl:onProperty fhir:Coding.code ;
    owl:someValuesFrom
      [ owl:onProperty fhir:value ;
        owl:hasValue "69896004" ] ]
  [ owl:onProperty fhir:Coding.system ;
    owl:someValuesFrom
      [ owl:onProperty fhir:value ;
        owl:hasValue "http://snomed.info/sct"
    ] ]
) ] rdfs:subClassOf fhir:Codinng-of-Rheumatoid_arthritis-disorder .

later fixed with fhir:concept links

now we can look for Observations with that coding

 fhir:Observation.code some (
   fhir:CodeableConcept.coding some fhir:Codinng-of-Rheumatoid_arthritis-disorder )
    
fhir:Observation-of-Rheumatoid_arthritis-disorder a owl:Class ;
    rdfs:label "fhir Observation of Rheumatoidarthritis (disorder)" ;
    owl:equivalentClass [
        owl:onProperty fhir:Observation.code ;
        owl:someValuesFrom [
            owl:onProperty fhir:CodeableConcept.coding ;
            owl:someValuesFrom snomedct:Rheumatoid_arthritis-disorder
        ]
    ]
.

snomed subsumptions, either directly

 fhir:Observation.code some (
   fhir:CodeableConcept.coding some snomedct:Rheumatoid_arthritis-disorder )
    
fhir:Observation-of-Rheumatoid_arthritis-disorder a owl:Class ;
    rdfs:label "fhir Observation of Rheumatoidarthritis (disorder)" ;
    owl:equivalentClass [
        owl:onProperty fhir:Observation.code ;
        owl:someValuesFrom [
            owl:onProperty fhir:CodeableConcept.coding ;
            owl:someValuesFrom snomedct:Rheumatoid_arthritis-disorder
        ]
    ]
.

or via a connecting property

fhir:Observation.code some (
  fhir:CodeableConcept.coding some (
    fhir:concept some snomedct:Rheumatoid_arthritis-disorder ) )
    
fhir:Observation-of-Rheumatoid_arthritis-disorder a owl:Class ;
    rdfs:label "fhir Observation of Rheumatoidarthritis (disorder)" ;
    owl:equivalentClass [
        owl:onProperty fhir:Observation.code ;
        owl:someValuesFrom [
            owl:onProperty fhir:CodeableConcept.coding ;
            owl:someValuesFrom [
                owl:onProperty fhir:concept ;
                owl:someValuesFrom snomedct:Rheumatoid_arthritis-disorder
            ]
        ]
    ]
.

connect FHIR coding to SNOMED concept

fhir:Codinng-of-Rheumatoid_arthritis-disorder rdfs:subClassOf
  [ owl:onProperty fhir:concept ;
    owl:someValuesFrom snomedct:Rheumatoid_arthritis-disorder ].
    

now use SNOMED's hierarchy

by direct subclass:

fhir:Observation.code some (
  fhir:CodeableConcept.coding some (
    fhir:concept some snomedct:Arthritis-disorder ) )
    

by class restriction:

fhir:Observation.code some (
  fhir:CodeableConcept.coding some (
    fhir:concept some (snomedct:Inflammatory_disorder-disorder
      and (snomedct:role_group-attr some 
         (snomedct:Associated_morphology-attr some snomedct:Inflammatory_morphology-morph
          and snomedct:Finding_site-attr some snomedct:Structure_of_musculoskeletal_system-body))
    )))

importing with fhir:concept

axiom:

[ owl:intersectionOf (
  [ owl:onProperty fhir:Coding.code ;
    owl:someValuesFrom
      [ owl:onProperty fhir:value ;
        owl:hasValue "69896004" ] ]
  [ owl:onProperty fhir:Coding.system ;
    owl:someValuesFrom
      [ owl:onProperty fhir:value ;
        owl:hasValue "http://snomed.info/sct"
    ] ]
) ] rdfs:subClassOf fhir:Codinng-of-Rheumatoid_arthritis-disorder .

data:

amy:Obs1 a fhir:Observation;
  fhir:Observation.code [
    a fhir:CodeableConcept;
    fhir:CodeableConcept.coding [
      a fhir:Coding;
      fhir:Coding.system [ fhir:value "http://snomed.info/sct" ];
      fhir:Coding.code   [ fhir:value "69896004" ]
    ]
  ] .
amy:Obs1
  fhir:Observation.code [
    fhir:concept snomedct:Rheumatoid_arthritis-disorder # <-?
    fhir:CodeableConcept.coding [
      fhir:concept snomedct:Rheumatoid_arthritis-disorder
    ]
  ] .

get rid of some junk

recognizers:

[ owl:intersectionOf (
  [ owl:onProperty fhir:Coding.code ;
    owl:someValuesFrom
      [ owl:onProperty fhir:value ;
        owl:hasValue "69896004" ] ]
  [ owl:onProperty fhir:Coding.system ;
    owl:someValuesFrom
      [ owl:onProperty fhir:value ;
        owl:hasValue "http://snomed.info/sct"
    ] ]
) ] rdfs:subClassOf fhir:Coding-of-Rheumatoid_arthritis-disorder .

connective tissue:

fhir:Coding-of-Rheumatoid_arthritis-disorder rdfs:subClassOf
  [ owl:onProperty fhir:concept ;
    owl:someValuesFrom snomedct:Rheumatoid_arthritis-disorder ].

Seronegative_rheumatoid_arthritis

Seronegative_rheumatoid_arthritis

Rheumatoid_arthritis

Rheumatoid_arthritis

Discovery

example

github API

  • repos (slight misnomer)
    • group1
      • repo2
        • issues
          • issue3
          • issue4
  • users
    • user5

AppStore model

N AppStores

FAIR - Findable

F1. (Meta)data are assigned a globally unique and persistent identifier

F2. Data are described with rich metadata (defined by R1 below)

F3. Metadata clearly and explicitly include the identifier of the data they describe

F4. (Meta)data are registered or indexed in a searchable resource

FAIR - Accessible

A1. (Meta)data are retrievable by their identifier using a standardised communications protocol

A1.1 The protocol is open, free, and universally implementable

A1.2 The protocol allows for an authentication and authorisation procedure, where necessary

A2. Metadata are accessible, even when the data are no longer available

FAIR - Interoperable

I1. (Meta)data use a formal, accessible, shared, and broadly applicable language for knowledge representation.

I2. (Meta)data use vocabularies that follow FAIR principles

I3. (Meta)data include qualified references to other (meta)data

FAIR - Reusable

R1. Meta(data) are richly described with a plurality of accurate and relevant attributes

R1.1. (Meta)data are released with a clear and accessible data usage license

R1.2. (Meta)data are associated with detailed provenance

R1.3. (Meta)data meet domain-relevant community standards

Discussion

Can the discoverability mechansim work for scientific data?

Follow Up

Repeated properties

<BPShape> {
  :subject @<PatientShape> ;
  :code @<vs_BP-Code> ;
  :bodySite @<vs_BP-Site> ;
  :component { comp:code @<vs_BP-Systolic> } ?
  :component { comp:code @<vs_BP-Diastolic> } ?
}

<vs_BP-Systolic> @<CodeableConcept> AND {
  code:coding {
    cc:system [<http://loinc.org/>] ;
    cc:code ["8480-6"]
  }
}