Sémantický web

Úvod

W3 Consorcium v roce 2001 zakládá skupinu Semantic Web Activity, která mimo jiné definuje sémantický web (semantic web) tak, že:

K tomuto účelu bylo nezbytné popisovat zdroje na webu, např.:

Tyto uvedené představy jso už dnes historie, přesto si tato myšlenka nalezla své místo v jiných oblastech:


Vrstvy sémantického webu

  1. Unicode + Jednoznačné identifikátory (URI, IRI) – lokalizace a jméno
  2. XML + jmenné prostory + XML Schema
  3. RDF + RDF Schema
  4. Ontologie (OWL)
  5. Logika, usuzování, odvozování znalostí (tvrzení) – odvozovací pravidla (rules)
  6. Důkaz a dokazatelnost (proof)
  7. Důvěra (trust, digital signature, cryptography)
  8. Uživatelské rozhraní a aplikace

RDF

Zkratka RDF odkazuje na Resource Description Framework, což můžeme přeložit jako rámec popisu zdrojů. Jeho autorem je W3 Consorcium a byl převážně navržen pro popis zdrojů na webu. RDF není jen rámec, ale také datový model či slovník. RDF je navržen maximálně obecně, aby mohl být čten a pochopen strojem (počítačem, ale zobrazení informace témto jazykem nebylo pochopitelné pro lidi.

Zápis RDF využívá pro zápis:

RDF má tyto silné stránky:


Princip a popis RDF trojice

RDF je založeno na atomickém prvku označovaném trojice (triple). Trojice popisuje vlastnost zdroje. Trojice se skládá ze tří částí:

Trojice tvoří vždy jedno platné tvrzení. Máme-li více tvrzení zapisujeme je jako odpovídající počet trojic. Spojením trojic nám vzniká popis reálného světa v podobě orientovaného grafu:

Vše jsou trojice (triples) resp. čtveřice (quads). Datové úložiště označujeme jako:


Ilustrace převodu tvrzení do RDF

Příklad tvrzení: Rozvrhovou akci v pondělí 9.20 vede Petr. lze zapsat do trojice:

Vidíme, že tam jsou i další tvrzení, které se vztahují k rozvrhové akci a blíže ji specifikují. Jak budou vypadat další tvrzení?

Další tvrzení přepsaná RDF trojicemi:

<zdroj>                         <vlastnost> <objekt>  .
=======================================================
<Rozvrhová akce v pondělí 9.20> <vede>      <Petr>    .
<Rozvrhová akce v pondělí 9.20> <den>       <pondělí> .
<Rozvrhová akce v pondělí 9.20> <zacina>    <9.20>    .
<9.20>                          <hodin>     <9>       .
<9.20>                          <minut>     <20>      .
...

Výše uvedený zápis (bez prvních dvou řádek) se označuje N-TRIPLE notace a každá trojice je vždy na samostatném řádku ukončená znakem tečky. Zdroje jsou uzavřeny ve špičatých závorkách a text je v uvozovkách.


Identifikátory

Výše uvedený zápis tvrzení byl ilustrační a v této podobě by neměl odpovídající přínos/význam. Zdroje musí být jednoznačně identifikovatelné buď jako URI (Uniform Resource Identifier) nebo jako IRI (Internationalized Resource Identifier). URI nebo IRI má tento obecný tvar:

scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]

IRI umožňuje oproti URI v řetězci použít Unicode znaky splňující pravidla dle RFC 3987. URI nebo IRI nabízí známé specializace:

Z důvodu možnosti propojení dat (v budoucnosti) na webu je doporučeno použití schéma/protokolu HTTP(S).

V našem příkladě použijeme např. jmenný prostor http://zcu.cz/rdf/ a zdroje i vlastnosti jím identifikujeme:

<zdroj>               <vlastnost>                 <objekt>              .
=========================================================================
<http://zcu.cz/rdf/1> <http://zcu.cz/rdf/vede>    "Petr"                .
<http://zcu.cz/rdf/1> <http://zcu.cz/rdf/den>     "pondělí"             .
<http://zcu.cz/rdf/1> <http://zcu.cz/rdf/zacina>  <http://zcu.cz/rdf/2> .
<http://zcu.cz/rdf/2> <http://zcu.cz/rdf/hodin>   "9"                   .
<http://zcu.cz/rdf/2> <http://zcu.cz/rdf/minut>   "20"                  .
...

Datový typ a jazyk hodnoty

Pro hodnoty lze definovat datový typ nebo jazyk. V notacích N-TRIPLE a Turtle:


Slovníky a jmenné prostory

Ilustrační příklad ukazuje popis několika tvrzení, ale rozumíme mu (pravděpodobně) pouze my. Pro zajištění shody a pochopení ostatními lidmi i stroji je popis (zatím) nevhodný, resp. nedostatečný. Vlastnosti, které jsme si zavedli jsou naše a lokální. Kdokoliv jiný se na ně podívá, nemusí pochopit jejich správný význam nebo je správně interpretovat:

Takto uvedené vlastnosti jsou „vytrženy z kontextu“, chybí nám kontext nebo spíše význam – sémantika vlastností. Zjednodušeně řečeno, proto vznikají slovníky nebo ontologie, které definují a současně dokumentují potřebný kontext, vztahy, doménu, obor hodnot, ...

Vytvoříme-li si odpovídající slovník (resp. ontologii) a zveřejníme jej – data a informace může využít už i někdo další a mohou se sdílet na webu. Problém?! Když si úplně každý vytvoří svůj vlastní slovník, pak bude výsledek nepoužitelný, protože data budou sdílená, ale možnosti využití a interpretace ostatními budou minimální.

Řešením tohoto problému jsou existující základní RDF slovníky a ontologie, které přináší rámec jak nad RDF popisovat zdroje jednotným způsobem:

Závěr: RDF definuje jak psát popis a OWL definuje co psát.


Používané notace RDF dat

Pro účely přehlednějšího a stručnějšího (úspornějšího) zápisu se používají prefixy i další notace. Pro stejný příklad popisu pondělní rozvrhové akce použijeme další zápisy.


Notace Turtle

Přímo výše uvedený příklad zapíšeme v notaci Turtle:

<http://zcu.cz/rdf/1> 
 http://zcu.cz/rdf/:vede    "Petr"    ;
 http://zcu.cz/rdf/:den     "pondělí" ;
 http://zcu.cz/rdf/:zacina  http://zcu.cz/rdf/2     .

<http://zcu.cz/rdf/2> 
 http://zcu.cz/rdf/:hodin   "9"       ;
 http://zcu.cz/rdf/:minut   "20"      .

Tvrzení patřící stejnému subjektu oddělujeme středníkem, více hodnot u stejné vlastnosti oddělujeme čárkou a za posledním tvrzením je tečka.

Ke zvolenému jmennému prostoru nadefinujeme prefix zcu a data ve výše uvedené notaci Turtle budou:

@prefix zcu: <http://zcu.cz/rdf/> .

<http://zcu.cz/rdf/1> 
 zcu:vede    "Petr"    ;
 zcu:den     "pondělí" ;
 zcu:zacina  zcu:2     .
​
<http://zcu.cz/rdf/2> 
 zcu:hodin   "9"       ;
 zcu:minut   "20"      .

Ve formátu Turtle může být na začátku deklarace prefixů začínající znakem zavináče a slovem prefix, za nímž následuje vlastní prefix a za dvojtečkou úplné URI/IRI jmenného prostoru za kterým je tečka.


Notace RDF/XML

Stejný zápis v provedení notace RDF/XML:

<rdf:RDF xmlns:zcu="http://zcu.cz/rdf/">
  <rdf:Description rdf:about="http://zcu.cz/rdf/1">
    <zcu:vede>Petr</zcu:vede>
    <zcu:den>pondělí</zcu:den>
    <zcu:zacina>
      <rdf:Description rdf:about="http://zcu.cz/rdf/2">
        <zcu:hodin>9</zcu:hodin>
        <zcu:minut>20</zcu:minut>
      </rdf:Description>
    </zcu:zacina>
  </rdf:Description>
</rdf:RDF>

Používá se jmenný prostor rdf, který je rezervovaný. Prefixy jsou definovány v kořenovém elementu rdf:RDF.

Příklad v základní RDF/XML notaci včetně použitého RDF jmenného prostoru:

<?xml version="1.0"?>
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:zcu="http://zcu.cz/rdf/">
  <rdf:Description rdf:about="http://zcu.cz/rdf/1">
    <zcu:vede>Petr</zcu:vede>
    <zcu:den>pondělí</zcu:den>
    <zcu:zacina rdf:resource="http://zcu.cz/rdf/2" />
  </rdf:Description>
  <rdf:Description rdf:about="http://zcu.cz/rdf/2">
    <zcu:hodin>9</zcu:hodin>
    <zcu:minut>20</zcu:minut>
  </rdf:Description>
</rdf:RDF> 

Uvedené serializace RDF dat jsou vzájemně převoditelné – bezztrátově.


Přidání tvrzení

Nová tvrzení/trojice stačí k původním jen přidat.

<zdroj>                         <vlastnost> <objekt>      .
===========================================================
<Petr>                           <je>       <Jméno>       .
<Petr>                           <je>       <Osoba>       .
<Petr>                           <je>       <Muž>         .
<pondělí>                        <je>       <Den v týdnu> .
...

Tyto trojice mohou pocházet např. z jiného zdroje, slovníku nebo ontologie.

Lze se dotazovat u více zdrojů současně, a to prostřednictvím distribuované prostředí webu – SPARQL Endpoint. Pokud zdroj používá jiné identifikátory, slovníky nebo ontologie, lze je propojit (merge) přidáním tvrzení s vlastnostmi owl:sameAs, owl:differentFrom a owl:AllDifferent.


Porovnání OOP s RDF

Kocept RDF a OWL je velmi obecný, avšak lze najít podobnost s OOP přístupem.


Porovnání s relační databází

Zásadní rozdíl je ve způsobu přístupu k datům.

Schéma databáze = datový model je pevně definován

Tabulka = entita

Sloupec tabulky = atribut entity

Datový typ atributu = povolený datový typ hodnot

Záznam = řádek tabulky


Vývoj a vývojové nástroje

RDF úložiště

Programovací jazyky

Seznam dalších nástrojů souvisejících s RDF: https://www.w3.org/RDF/


SPARQL – dotazovací jazyk

Historie jazyka

SPARQL 1.0 (2008)

SPARQL 1.1 (W3C Recommendation 21 March 2013)


Popis jazyka

Jazyk umožňuje:

Výběrové typy dotazu:

Formát výsledku výběrových dotazů – závisí na typu dotazu:

Aktualizace grafu:

Správa grafu:


Schéma dotazu

# deklarace prefixů
PREFIX foo: <http://example.com/resources/>
...
​
# definice datasetu/grafu/zdroje
FROM ...
​
# výsledek dotazu
SELECT ...
​
# podmínka — vzor dotazu (query pattern)
WHERE {
    ...
}
# modifikátory dotazu
ORDER BY ...

V části SELECT:

Proměnná začíná prefixem otazníku (dolaru): ?s ?p ?o.

V části WHERE:

Filtrování hodnot:

FILTER (?hodnota > 1000 && langMatches(lang(?nazev), "EN")) .

Ukázková data

# https://www.w3.org/TR/2013/REC-sparql11-query-20130321/#construct
@prefix  foaf:  <http://xmlns.com/foaf/0.1/> . # Friend-of-a-Friend
​
<abc> foaf:name "Alice" .
<abc> foaf:mbox <mailto:alice@example.org> .

Typy dotazů jsou:

SELECT všechny nebo podmnožinu proměnných z podmínkové části

# příklad 1 - všechny trojice
SELECT ?s ?p ?o
WHERE {
 ?s ?p ?o .
}
​
# příklad 1 - všechny vlastnosti a jejich hodnoty
SELECT ?p ?o
WHERE {
 <abc> ?p ?o .
}

CONSTRUCT vrací RDF graf sestavený dle šablony trojic

# https://www.w3.org/TR/2013/REC-sparql11-query-20130321/#construct
PREFIX foaf:    <http://xmlns.com/foaf/0.1/>
PREFIX vcard:   <http://www.w3.org/2001/vcard-rdf/3.0#>
​
# příklad 1 - jen filtrování
CONSTRUCT WHERE { ?x foaf:name ?name . }
​
# příklad 2 - transformace schéma
CONSTRUCT {
  ?x vcard:FN ?name
}
WHERE {
  ?x foaf:name ?name .
}

ASK odpověď je datového typu boolean;

# https://www.w3.org/TR/2013/REC-sparql11-query-20130321/#ask
# příklad 1 - odpověď bude ’true’ nebo ’false’?
PREFIX foaf:    <http://xmlns.com/foaf/0.1/>
ASK { ?x foaf:name  "Alice" }
​
# příklad 2 - odpověď bude ’true’ nebo ’false’?
PREFIX vcard:   <http://www.w3.org/2001/vcard-rdf/3.0#>
ASK { ?x vcard:FN  "Alice" }

DESCRIBE vrací RDF graf popisující zdroj

# https://www.w3.org/TR/2013/REC-sparql11-query-20130321/#describe
​
# příklad 1 - známe URI
DESCRIBE <abc>
​
# příklad 2 - neznáme konkrétní URI
PREFIX foaf:   <http://xmlns.com/foaf/0.1/>
DESCRIBE ?x
WHERE {
  ?x foaf:name "Alice" .
}

SPARQL – řešené příklady

Schéma dat v systému MRE

Data vychází z datového formátu DASTA (DAtový STAndard) spravovaný Ministerstvem zdravotnictví ČR

V systému MRE používané ontologie jsou dokumentovány: https://mre.zcu.cz/ontology/ontologies.html V našem případě jsou:

Schéma vybraných tříd a vlastností v systému MRE

figure mre-lite.png

Připravená RDF data

patient1-medical

patient6-medical

patient7-medical

patient7-imaging

Použité datové formáty (koncovka):

nt N-TRIPLE

ttl TURTLE

xml RDF/XML


Používané jmenné prostory

PREFIX id:    <http://mre.zcu.cz/id/>
PREFIX ds:    <http://mre.zcu.cz/ontology/dasta.owl#>
PREFIX dscl:  <http://mre.zcu.cz/ontology/dscl.owl#>
PREFIX dcm:   <http://mre.zcu.cz/ontology/dcm.owl#>
PREFIX sits:  <http://mre.zcu.cz/ontology/sits.owl#>
PREFIX nihss: <http://mre.zcu.cz/ontology/nihss.owl#>
PREFIX mre:   <http://mre.zcu.cz/ontology/mre.owl#>
​
PREFIX acl:   <http://www.w3.org/ns/auth/acl#>
PREFIX dc:    <http://purl.org/dc/elements/1.1/>
PREFIX nfo:   <http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#>
PREFIX owl:   <http://www.w3.org/2002/07/owl#>
PREFIX rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs:  <http://www.w3.org/2000/01/rdf-schema#>
PREFIX xsd:   <http://www.w3.org/2001/XMLSchema#>

Kompletní výčet a detaily viz https://mre.zcu.cz/ontology/ontologies.html.


SPARQL Server – Apache Fuseki

Stáhněte si program z adresy https://jena.apache.org/download/, rozbalte jej a z rozbaleného adresáře spusťte

a následně v konzoli uvidíme start serveru. Server běží ve výchozím nastavení na portu 3030. Ve webovém prohlížeči zadáme adresu: http://localhost:3030 a vše je připraveno k nahrání dat a zkoušení příkladů.


Data příkladů – pacient Anon_666

id:cd3f0c85b158c08a2b113464991810cf2cdfc387
  a                 ds:Patient , ds:Male ;
  ds:address        id:3840aecb9edac9f7d7c9172f2f4be82b08ab3ddf ;
  ds:clinicalEvent  id:be8d011f882326495f8d06c58f22db51d95cc7bf ;
  ds:datetimeBirth  "1938-08-13"^^xsd:date ;
  ds:lastName       "Anon_666" ;
  ds:patientID      "666" ;
  ds:sex            "M" ;
  ds:sexNCLPTPS     dscl:NCLPTPS_M ;
  ds:sexPOHLAV      dscl:POHLAV_1 ;
  dc:title          "Anon_666 (M) * 1938-08-13" .
​
id:3840aecb9edac9f7d7c9172f2f4be82b08ab3ddf
  a               ds:PermanentAddress ;
  ds:addressCity  "Město 1" ;
  ds:addressZIP   "00001" ;
  dc:title        "Město 1 (00001)" .
​
id:be8d011f882326495f8d06c58f22db51d95cc7bf
  a                          ds:MedicalExamination ;
  ds:datetimeEvent           "2012-09-19T23:20:00+0200"^^xsd:dateTime ;
  ds:diagnosis               id:2c545600eb7a2722809d64c2753de714a5154b6b ,
                             id:2285692c932c88f8673a162ef7b5c997993da41c ;
  ds:dsclExaminationContent  dscl:LZSOZ_NL ;
  ds:dsclExaminationOrigin   dscl:LZTOZV_J ;
  ds:dsclExaminationRequest  dscl:LZTZOV_D ;
  ds:dsclExaminationState    dscl:LZSZZ_K ;
  ds:imagingStudyNumber      "00000078" ;
  ds:originator              id:44040e7024d5a4cc177bf0ed29683c2185dbd05b ;
  ds:reportText              "CT mozku:..." ;
  ds:reportTitle             "032/002 - CT mozku: s k.l. iv." ;
  dc:title                   "2012-09-19 23:20: 032/002 - CT mozku: s k.l. iv." .
​
id:2c545600eb7a2722809d64c2753de714a5154b6b
  a                 ds:ActualDiagnosis ;
  ds:datetimeEvent  "2012-04-18"^^xsd:date ;
  ds:diagCode       dscl:MKN10_5_J180 ;
  ds:diagDetail     "Bronchopneumonie NS" ;
  ds:diagOrder      1 ;
  ds:patient        id:cd3f0c85b158c08a2b113464991810cf2cdfc387 ;
  dc:title          "2012-04-18 (1) J18.0 - Bronchopneumonie NS" .
​
id:2285692c932c88f8673a162ef7b5c997993da41c
  a                 ds:ActualDiagnosis ;
  ds:datetimeEvent  "2012-04-18"^^xsd:date ;
  ds:diagCode       dscl:MKN10_5_I639 ;
  ds:diagDetail     "Mozkový infarkt" ;
  ds:diagOrder      2 ;
  ds:patient        id:cd3f0c85b158c08a2b113464991810cf2cdfc387 ;
  dc:title          "2012-04-18 (2) I63.9 - Mozkový infarkt" .
​
id:44040e7024d5a4cc177bf0ed29683c2185dbd05b
  a                  ds:OriginatorDepartment ;
  ds:departmentName  "Nemocnice na ..." ;
  dc:title           "Nemocnice na ..." .

Jednoduché dotazy

Všechny existující trojice

Níže uvedené dotazy budou aplikovány nad datovou sadou patient1-medical. Chceme-li získat všechny trojice, musíme v části WHERE mít vzor trojice se třemi proměnnými. Ty vyhovují všem trojicím. V části SELECT je uvedeme.

# základní forma dotazu SELECT
# 01a
SELECT ?subject ?predicate ?object
WHERE {
  ?subject ?predicate ?object .
}
# na názvech proměnných nezáleží, jsou oddělovány jen mezerou
# 01b
SELECT ?s ?p ?o
WHERE {
  ?s ?p ?o .
}

Dotaz vrátí všechny trojice, tj. tři sloupce s hodnotami dle celkového počtu trojic v datasetu. Omezení počtu lze provést použitím klíčového slova LIMIT.

# 02
SELECT ?s ?p ?o
WHERE {
  ?s ?p ?o 
}
LIMIT 10

Dotaz vrátí 10 trojic ve třech sloupcích odpovídajících trojicím. Vedle LIMIT, lze použít také OFFSET.


Všechny vlastnosti a hodnoty pro zadané URI

# získání všech vlastností a jejich hodnot SELECTem
# 03a
SELECT ?p ?o
WHERE {
  <http://mre.zcu.cz/id/cd3f0c85b158c08a2b113464991810cf2cdfc387> ?p ?o .
}
# s využitím prefixu v zápisu
# 03b
PREFIX id: <http://mre.zcu.cz/id/>

SELECT ?p ?o
WHERE {
  id:cd3f0c85b158c08a2b113464991810cf2cdfc387 ?p ?o .
}

Výsledkem dotazu je 11 dvojic (pár vlastnost a její hodnota) pro výše uvedené URI. V podobě grafu lze prakticky totéž získat prostřednictvím DESCRIBE:

# získání všech vlastností a jejich hodnot příkazem DESCRIBE
# 03c
PREFIX id: <http://mre.zcu.cz/id/>

DESCRIBE id:cd3f0c85b158c08a2b113464991810cf2cdfc387

Vrátí RDF graf s 11 trojicemi, které mají jako subjekt uvedené URI.


Rodné číslo pacienta pro známé URI

# získání hodnot(y) vybrané vlastnosti
# 04a
PREFIX id: <http://mre.zcu.cz/id/>
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT ?o
WHERE {
  id:cd3f0c85b158c08a2b113464991810cf2cdfc387 ds:patientID ?o .
}
# přejmenování proměnné na ?rc
# 04b
PREFIX id: <http://mre.zcu.cz/id/>
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT ?rc
WHERE {
  id:cd3f0c85b158c08a2b113464991810cf2cdfc387 ds:patientID ?rc .
}

Dotaz vrátí jeden řádek s jednou hodnotou (jeden sloupec). V části WHERE může být i celé URI bez zkrácení prefixem. Hodnota vlastnosti ds:patientID bude svázána (bind) s proměnnou ?rc a dostupná jako výsledek v části SELECT.


URI pacienta pro známé rodné číslo

# získání subjectu (pacienta) na základě znalosti jeho rč
# 05
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT ?patient
WHERE {
  ?patient ds:patientID "666" .
}

Výsledkem dotazu je jedna hodnota URI.


URI všech pacientů a jejich rodných čísel

Níže uvedené dotazy budou aplikovány nad datovou sadou patient6-medical.

# získání identifikace pacienta a jeho rč
# 06
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT ?pacient ?rc
WHERE {
  ?pacient ds:patientID ?rc .
}

Výsledkem dotazu je šest hodnot URI a rodných čísel.


Rodné číslo a jméno pro zadané URI pacienta

# každá vlastnost tvoří jednu RDF trojici ve WHERE
# 07a
PREFIX id: <http://mre.zcu.cz/id/>
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT ?rc ?jmeno
WHERE {
  id:cd3f0c85b158c08a2b113464991810cf2cdfc387 ds:patientID ?rc    .
  id:cd3f0c85b158c08a2b113464991810cf2cdfc387 ds:lastName  ?jmeno .
}
# vlastnosti ke stejnému zdroji jsou oddělené středníkem
# 07b
PREFIX id: <http://mre.zcu.cz/id/>
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT ?rc ?jmeno
WHERE {
  id:cd3f0c85b158c08a2b113464991810cf2cdfc387 
    ds:patientID ?rc    ;
    ds:lastName  ?jmeno .
}

V obou příkladech dostaneme stejný výsledek.


Jméno a rodné číslo všech pacientů

# v dalších dotazech budeme využívat zkráceného zápisu
# 08a 
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT ?pacient ?rc ?jmeno
WHERE {
  ?pacient ds:patientID ?rc    ;
           ds:lastName  ?jmeno .
}

a použijeme hvězdičku (*), chceme-li zobrazit všechny proměnné:

# použitá * pro vypsání všech proměnných
# 08b
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT *
WHERE {
  ?pacient ds:patientID ?rc    ;
           ds:lastName  ?jmeno .
}

Datum narození a úmrtí pacientů

# nejdříve dohledáme datum narození
# 09a
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni .
}
# a potom datum úmrtí
# 09b
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni ;
           ds:datetimeDeath ?umrti    .
}

Jaký je výsledek dotazu? Proč? Správné řešení:

# datum úmrtí je nepovinný - přidáme konstrukci OPTIONAL
# 09c
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni .

  OPTIONAL {
    ?pacient ds:datetimeDeath ?umrti .
  }	
}

Výsledek (počet řádek) dle zvoleného příkladu:

# pozor - pokud je proměnná prvně zavedena v konstrukci OPTIONAL
# a až následně použita ve zbytku vzoru, výsledek se změní.
# 09d
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT *
WHERE {
  OPTIONAL {
    ?pacient ds:datetimeDeath ?umrti .
  }	

  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni .

}

Význam klíčového slova OPTIONAL – ovlivní počet výsledků.


Rodná čísla a jména pacientů s rodným číslem větším než 200

Filtrování hodnoty rodného čísla:

# filtrační podmínka - volání funkce FILTER
# 10a
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni .

  OPTIONAL {
    ?pacient ds:datetimeDeath ?umrti .
  }	
  
  FILTER ( ?rc > 200 )
}

Všechny hodnoty rodného čísla porovná s filtrem. Funguje? Hodnota ds:patientID je string, nikoliv číslo, porovnáváme text s číslem.

# převedem hodnotu rc na číslo
# 10b
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni .

  OPTIONAL {
    ?pacient ds:datetimeDeath ?umrti .
  }	
  
  FILTER ( ?rc > "200" )
}

Asi to funguje. Opravdu?

# změního hodnotu rc na 20
# 10c
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni .

  OPTIONAL {
    ?pacient ds:datetimeDeath ?umrti .
  }	
  
  FILTER ( ?rc > "20" )
}

Proč to přestalo fungovat? Odpovědí je lexikografické řazení. Řešení: musíme na číslo přetypovat hodnotu rc.

# nutné přetypování rc na číslo
# 10d
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni .

  OPTIONAL {
    ?pacient ds:datetimeDeath ?umrti .
  }	
  
  FILTER ( xsd:int(?rc) > 200 )
}

Pacienti seřazeni dle rodného čísla

Obdoba předchozích příkladů, jen je navíc požadováno řazení:

# řazení pacientů podle jejich rc - ORDER BY
# 11a
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni .
		   
  OPTIONAL {
    ?pacient ds:datetimeDeath ?umrti .
  }	
		   
}
ORDER BY DESC (?rc)
# stejný problém jako u funkce FILTER
# 11b
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni .

  OPTIONAL {
    ?pacient ds:datetimeDeath ?umrti .
  }			   
}
ORDER BY DESC ( xsd:int(?rc) )

Vhodné použít data patient6-medical nebo patient7-medical. Výsledek dotazu (počet řádek) dle zvoleného příkladu:

Porovnejte různé varianty části ORDER BY – rozdíl mezi znakovým a číselným řazením:

ORDER BY ?rc
ORDER BY ASC ( ?rc )
ORDER BY DESC ( ?rc )
ORDER BY DESC ( xsd:int(?rc) )
ORDER BY ?jmeno DESC ( ?rc )

Výsledek dotazu lze ovlivnit modifikátorem ORDER BY pro řazení, ASC, DESC určují směr řazení. V případě chybějícího datového typu se jedná obecně o string:


Pacienti s datem narození v určeném období

Pacienti narozeni od 1. ledna 1930 do současnosti.

# pacienti narozeni 1.1.1930 a dříve
# 12a
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni .

  OPTIONAL {
    ?pacient ds:datetimeDeath ?umrti .
  }	
  
  FILTER ( ?narozeni >= "1930-01-01" )  
}

Ve filtru uvedeme i datový typ hodnoty:

# funguje s uvedením datového typu hodnoty
# 12b
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni .

  OPTIONAL {
    ?pacient ds:datetimeDeath ?umrti .
  }	
  
  FILTER ( ?narozeni >= "1930-01-01"^^xsd:date )
}

Pacienti narozeni ve 30. letech 20. století.

# více FILTERů je spojeno implicitně AND
# 13a
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni .

  OPTIONAL {
    ?pacient ds:datetimeDeath ?umrti .
  }	
  
  FILTER ( ?narozeni >= "1930-01-01"^^xsd:date )
  FILTER ( ?narozeni <= "1939-12-31"^^xsd:date )
}
# složitější logická podmínka ve FILETRu
# 13b
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni .

  OPTIONAL {
    ?pacient ds:datetimeDeath ?umrti .
  }	
  
  FILTER ( ?narozeni >= "1930-01-01"^^xsd:date && 
           ?narozeni <= "1939-12-31"^^xsd:date )
}

Pacienti bez uvedeného data úmrtí

Konstrukcí EXISTS můžeme testovat, zda daný grafový vzor lze najít v datech. Chceme-li výsledek negovat, aplikujeme operátor NOT.

# pacienti, kteří nemají uveden datum úmrtí - NOT EXISTS
# 14a
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni .		 

  FILTER ( NOT EXISTS {
    ?pacient ds:datetimeDeath ?umrti .	
  } )
}

Srovnatelného výsledku dosáhneme voláním logické funkce BOUND, která testuje, zda proměnná má hodnotu nebo ne. Negaci funkce dosáhneme operátorem !

# pacienti, kteří mají uveden datum úmrtí - BOUND
# 14b
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni .		 

  OPTIONAL {
    ?pacient ds:datetimeDeath ?umrti .
  }	
  
  FILTER (BOUND (?umrti))
}
# pacienti, kteří nemají uveden datum úmrtí - negace BOUND
# 14c
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni .		 

  OPTIONAL {
    ?pacient ds:datetimeDeath ?umrti .
  }	
  
 FILTER (! BOUND (?umrti))
}

Dožitý věk pacientů

Z předchozích dotazů víme, že 2 pacienti jsou již po smrti. Proto jim můžeme spočítat věk, kterého se dožili. Každý výraz v klauzuli SELECT musí být doplněn o alias a celý zápis odvozeného sloupce musí být uzavřen v závorce.

# u pacienta chceme spočítat, jakého věku se dožil
# potřebujeme odvozený sloupec
# 15a
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT ?rc
       ?jmeno
       ?narozeni
       ?umrti
       ((?umrti - ?narozeni) AS ?vek)
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni ;
           ds:datetimeDeath ?umrti    .
}

Vypočtený výsledek je ve dnech, chceme spočítat léta.

# spočítáme dožitý věk v letech
# 15b
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT ?rc
       ?jmeno
       ?narozeni
       ?umrti
       (FLOOR (DAY (?umrti - ?narozeni) / 365) AS ?vek)
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni ;
           ds:datetimeDeath ?umrti    .
}

Pokud bychom chtěli filtrovat jen ty pacienty, kteří se dožili 80 let a více, tak máme smůlu. Potom je potřeba využít funkce BIND.

# u pacienta chceme spočítat, jakého věku se dožil
# potřebujeme odvozený sloupec - BIND
# 15c
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni ;
           ds:datetimeDeath ?umrti    .

  BIND (FLOOR (DAY (?umrti - ?narozeni) / 365) AS ?vek)  
}

Filtrace 80 letých pacientů je snadná funkcí FILTER.

# nad takto odvozenou hodotou můžeme stanovit filtrační podmínku
# 15d
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT *
WHERE {
  ?pacient ds:patientID     ?rc       ;
           ds:lastName      ?jmeno    ;
           ds:datetimeBirth ?narozeni ;
           ds:datetimeDeath ?umrti    .

  BIND (FLOOR (DAY (?umrti - ?narozeni) / 365) AS ?vek)  
  
  FILTER ( ?vek > 80 )
}

URI všech instancí třídy aktuálního pacienta

# získání URI patřící jen pacientům
# 16a
PREFIX ds:  <http://mre.zcu.cz/ontology/dasta.owl#> 
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

SELECT ?pacient
WHERE {
  ?pacient rdf:type ds:Patient .
}

Vlastnost rdf:type lze zkracovat na prosté písmeno „a“.

# existuje zkratka, nevyžadující prefix rdf - a
# 16 b
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT ?pacient
WHERE {
  ?pacient a ds:Patient .
}

Třídy instancí pacientů

# ověřme, do jakých tříd (typů) nám spadají všechny uzly (URI), které mají jméno
# 17
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT ?uzel ?trida
WHERE {
  ?uzel a           ?trida ;
        ds:lastName ?jmeno .
}

Zjistili jsme, že každý pacient je navíc instancí třídy ds:Male nebo ds:Female, což odpovídá pohlaví pacienta. Zjistěme, který pacient ma jaké pohlaví prostřednictvím dané třídy.

# získat identifikátory uzlů, které mají jméno a spadají do třídy ds:Male nebo ds:Female
# 18a
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT ?uzel ?jmeno ?trida
WHERE {
  ?uzel a           ?trida ;
        ds:lastName ?jmeno .
  FILTER (?trida = ds:Female || ?trida = ds:Male)
}

Konstrukcí VALUES lze naplnit proměnnou nebo n-tici proměnných s přesně definovanou sadou hodnot. Pokud je takto zavedená proměnná dále použita ve WHERE klauzuli, nemůže nabývat jiných hodnot.

# to samé pomocí VALUES
# 18b
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT ?uzel ?jmeno ?pohlavi
WHERE {
  VALUES ?pohlavi { ds:Female ds:Male }
  ?uzel a           ?pohlavi ;
        ds:lastName ?jmeno .
}
# místo názvu třídy vypíšeme statický řetězec
# 18c
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT ?uzel ?jmeno ?pohlavi
WHERE {
  VALUES (?typ ?pohlavi) { (ds:Female "Žena") (ds:Male "Muž") }
  ?uzel a           ?typ ;
        ds:lastName ?jmeno .
}

Četnosti pacientů dle pohlaví

Na základě znalosti, jaké pohlaví má který pacient, můžeme s využitím agregačních funkcí spočítat, kolik pacientů je žen a kolik je mužů.

# následně si uděláme malou statistiku pacientů podle jejich pohlaví - GROUP BY
# 19
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT ?pohlavi
       (COUNT (?uzel) AS ?pocet)
WHERE {
  VALUES (?typ ?pohlavi) { (ds:Female "Žena") (ds:Male "Muž") }
  ?uzel a           ?typ ;
        ds:lastName ?jmeno .
}
GROUP BY ?pohlavi

Ověření získaných znalostí

Použijte zejména data patient7-medical a ověřte, že vaše dotazy vrací správné výsledky pro níže uvedené příklady.

  1. Příklad 20-1a – Pro všechny pacienty vypište hodnoty sloupců:
  2. Příklad 20-1b – Upravte příklad 20-1a omezením výčtu pacientů pouze na jednoho explicitním zadáním URI.
  3. Příklad 20-1c – Upravte příklad 20-1a omezením výčtu pacientů na min. dva nebo tři pacienty zadané prostřednictvím známého URI.
  4. Příklad 20-2 – Upravte příklad 20-1a omezením na pacienty mužského pohlaví prostřednictvím:
    1. filtru hodnoty (20-2a),
    2. instance pacientů třídy ds:Male (20-2b).

Průchod grafu

Doporučená data: patient7-medical.


Jméno a rodné číslo pacientů společně s datem a časem z lékařské zprávy

# jméno a rč pacienta včetně data jeho lékařských vyšetření
# 21a
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT ?rc 
       ?jmeno 
       ?datum
WHERE {
  ?pacient a                ds:Patient ;
           ds:patientID     ?rc        ;
           ds:lastName      ?jmeno     ;
           ds:clinicalEvent ?vysetreni .
		   
  ?vysetreni ds:datetimeEvent ?datum .
}

Dotaz vrací 1 013 výsledků. Je to správně? Není, opakují se nám stejné kombinace hodnot.

# ve výsledku se nám opakují hodnoty - použijeme DISTINCT
# 21a
PREFIX ds: <http://mre.zcu.cz/ontology/dasta.owl#>

SELECT DISTINCT ?rc 
                ?jmeno 
                ?datum
WHERE {
  ?pacient a                ds:Patient ;
           ds:patientID     ?rc        ;
           ds:lastName      ?jmeno     ;
           ds:clinicalEvent ?vysetreni .
		   
  ?vysetreni ds:datetimeEvent ?datum .
}

Přidáním DISTINCT za SELECT omezíme počet duplicitních výsledků a dostaneme 47 výsledků. Je to už správně? Nevíme, uděláme si kontrolu. Nejdříve zjistíme, kolik existuje instancí třídy ds:MedicalExamination:

# 22a
PREFIX ds:  <http://mre.zcu.cz/ontology/dasta.owl#> 

SELECT ?uri
WHERE {
  ?uri a ds:MedicalExamination .
}

nebo prostřednictvím agregační funkce COUNT():

# 22b
PREFIX ds:  <http://mre.zcu.cz/ontology/dasta.owl#> 

SELECT ( COUNT(?uri) as ?pocet )
WHERE {
  ?uri a ds:MedicalExamination .
}

V obou případech je celkový počet 10 lékařských zpráv. Ve skutečnosti může být v ds:clinicalEvent:

Má-li být výstupem pouze datum a čas lékařských zpráv, musíme doplnit trojici, která specifikuje typ (třídu).

# problém je jinde, poskytuje to jak lékařská vyšetření, tak laboratorní vyšetření
# 21b
PREFIX ds:  <http://mre.zcu.cz/ontology/dasta.owl#> 

SELECT ?rc 
       ?jmeno 
       ?datum
WHERE {
  ?pacient a                ds:Patient ;
           ds:patientID     ?rc        ;
           ds:lastName      ?jmeno     ;
           ds:clinicalEvent ?vysetreni .
		   
  ?vysetreni ds:datetimeEvent ?datum                ;
             a                ds:MedicalExamination .
}

Nyní dotaz vrací správně 10 výsledků (stejně to bude v tomto případě s DISTINCT pro uvedená data). Přidání trojice s určením typu třídy odstraní všechny ostatní instance ds:LaboratoryReport, které nás zrovna nezajímají.


Diagnózy pacientů

Diagnóza je vždy uvedena u lékařské zprávy pacienta:

# zjistíme, jaké diagnózy byly určeny během lékařských vyšetření
# diagnózy jsou dostupné jen přes lékařská vyšetření
# 23a
PREFIX ds:  <http://mre.zcu.cz/ontology/dasta.owl#> 

SELECT ?rc 
       ?jmeno
       ?popis
WHERE {
  ?pacient a                ds:Patient ;
           ds:patientID     ?rc        ;
           ds:lastName      ?jmeno     ;
           ds:clinicalEvent ?vysetreni .
		   
  ?vysetreni ds:diagnosis ?diagnoza .
  
  ?diagnoza ds:diagDetail ?popis .
}

ORDER BY ?jmeno ?popis

Ve výsledku je patrné, že se nám některé diagnózy u stejného pacieta opakují. To je dáno skutečností, že stejná diagnóza byla u pacienta znova detekována na dalším vyšetření. Zjistíme, kolikrát byla každá diagnóza detekována u každého pacienta:

# kolikrát byla která diagnóza určena během lékařského vyšetření
# 23b
PREFIX ds:  <http://mre.zcu.cz/ontology/dasta.owl#> 

SELECT ?rc 
       ?jmeno
       (COUNT (?diagnoza) AS ?pocet) 
       ?popis
WHERE {
  ?pacient a                ds:Patient ;
           ds:patientID     ?rc        ;
           ds:lastName      ?jmeno     ;
           ds:clinicalEvent ?vysetreni .
		   
  ?vysetreni ds:diagnosis ?diagnoza .
  
  ?diagnoza ds:diagDetail ?popis .
}
GROUP BY ?rc ?jmeno ?popis
ORDER BY ?jmeno ?popis

Výsledek dotazu je 34 diagnóz pro data z patient7-medical. V dotazu musíme projít od pacienta ?patient (získáme jeho rodné číslo a jméno) na klinickou událost (?vysetreni), z klinické události ?vysetreni projdeme k diagnóze ?diagnoza a z diagnózy nás zajímá její popis. Ke stejnému výsledku dojdeme také při využití Property Path ve SPARQL 1.1:

# získání popisu diagnózy pomocí Property Path
# 23c
PREFIX ds:  <http://mre.zcu.cz/ontology/dasta.owl#> 

SELECT ?rc 
       ?jmeno
       (COUNT (?diagnoza) AS ?pocet) 
       ?popis
WHERE {
  ?pacient a                ds:Patient ;
           ds:patientID     ?rc        ;
           ds:lastName      ?jmeno     ;
           ds:clinicalEvent/ds:diagnosis ?diagnoza .
  
  ?diagnoza ds:diagDetail ?popis .
}
GROUP BY ?rc ?jmeno ?popis
ORDER BY ?jmeno ?popis

Ověření získaných znalostí

  1. Je chybou, že zde není v příkladech 23b a 23c uvedena třída – rdf:type (ds:MedicalExamination)?
  2. Dotazem zjistěte, kolik je v datech patient7-medical instancí ds:LaboratoryReport?
  3. Doplňte do 23b nebo 23c omezení, abychom získali pouze hlavní diagnózy (mají hodnotu 1 ve vlastnosti ds:diagOrder).
  4. Co je potřeba v datech změnit/přidat, abychom v předchozí úloze nepotřebovali použít FILTER?
  5. Podívejte se na data (na schéma výše není uvedeno) a najděte další způsob, jak jinak vypsat stejné výsledky. Vytvořte odpovídající dotaz.

Typy dotazů

Dotazovací jazyk SPARQL nabízí kromě příkazu SELECT ještě další dva příkazy pro dotazování: DESCRIBE a ASK. Příkazy SELECT a ASK vyžadují konstrukci FROM, u příkazu DESCRIBE je tato konstrukce nepovinná.

Příkaz DESCRIBE pro všechny proměnné mající tvar URI vrací všechny RDF troji těchto identifikátorů. Chceme-li znát všechny vlastnosti a jejich hodnoty daného identifikároru, použijeme k tomu tento příkaz.

Naproti tomu příkaz ASK poskytuje jen odpovědi True nebo False na otázku, zda dané trojice jsou v datové sadě dostupné či nikoliv. V uvedených trojicích se mohou vyskytovat proměnné, pak probíhá dosazování různých hodnot za tyto proměnné.

Porovnejte výsledky níže uvedených dotazů, které mají shodnou konstrukci WHERE:

# příkaz SELECT
PREFIX ds:  <http://mre.zcu.cz/ontology/dasta.owl#> 

SELECT *
WHERE {
  ?pacient a                ds:Patient .
  ?pacient ds:patientID     "666"      .
  ?pacient ds:clinicalEvent ?vysetreni .
}
# příkaz DESCRIBE
PREFIX ds:  <http://mre.zcu.cz/ontology/dasta.owl#> 

DESCRIBE *
WHERE {
  ?pacient a                ds:Patient .
  ?pacient ds:patientID     "666"      .
  ?pacient ds:clinicalEvent ?vysetreni .
}
# příkaz ASK
PREFIX ds:  <http://mre.zcu.cz/ontology/dasta.owl#> 

ASK
WHERE {
  ?pacient a                ds:Patient .
  ?pacient ds:patientID     "666"      .
  ?pacient ds:clinicalEvent ?vysetreni .
}

Samostatné úlohy

Pro následující úlohy použijte současně data patient7-medical a patient7-imaging. Můžete je nahrát:

  1. do jednoho datasetu (výchozího grafu) jako doposud
  2. nebo do dvou samostatných grafů, které si vhodně pojmenujete.

Úlohy

  1. Vyberte datum s časem všech laboratorních výsledků bez duplicit a seřazené od nejnovějších k nejstarším.
  2. Najděte a vypište všechny URI diagnóz, které jsou v datech použity (ds:DiagCode) a abecedně je seřaďte.
  3. Zjistěte počet DICOM studií (dcm:Study)?
  4. Zjistěte, jakým pacientům a které DICOM studie patří – uveďte jeho rodné číslo ds:patientID a číslo studie dcm:Study_ID.
  5. Zjistěte počet DICOM sérií (dcm:Series)?
  6. Zjistěte počet DICOM snímků (dcm:CT_Image)?
  7. Zjistěte z kolika DICOM souborů (snímků dcm:CT_Image) se každá ze sérií skládá, a seřaďte je od největší k nejmenší? Vypište číslo série (dcm:Series_Number), popis (dcm:Series_Description) a počet souborů v sérii.
  8. Zjistěte z kolika DICOM souborů (snímků dcm:CT_Image) se každá ze sérií skládá, a jaký objem dat na disku zabírá? Vypište číslo série (dcm:Series_Number), popis (dcm:Series_Description), počet souborů v sérii, celkovou velikost série v B i současně v MB. Hodnotu velikosti v MB zaokrouhlete. Série seřaďte dle velikosti v Bytech.
  9. Najděte laboratorní výsledky, jejichž hodnoty (ds:labNumberValue) jsou mimo stanovené referenční meze pro daného pacienta: a vypište unikátní název naměřené veličiny (ds:labLocalName), hodnotu, a obě referenční meze. Data budou řazena vzestupně dle názvu, dolní meze, hodnoty a horní meze.
    1. Neuvažujte datum laboratorního výsledku.
      • Řešení má být 171 výsledků.
    2. Uvažujte datum laboratorního výsledku. Zobrazen bude bezprostředně za názvem. Stejně tak u řazení, nejprve název a pak dle data, následovat budou zbývající hodnoty.
      • Řešení má být 216 výsledků.
    3. Zjistěte, kolikrát byly laboratorní hodnoty (název, ds:labLocalName) mimo stanovené meze. Zobrazit pouze ty, které se opakují (alespoň 2x) a seřadit dle počtu (sestupně) a názvů (vzestupně).
      • Řešení má být 25 výsledků. (Celkem je hodnot mimo referenční meze 47.)

Copyright © 2023 Petr Včelák a Martin Zíma