Commit d449c706 authored by R.W.Majeed's avatar R.W.Majeed

Ontology interfaces and SKOS implementation

parent 486030ba
.settings/
.classpath
.project
target/
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<name>HIStream : SKOS ontology</name>
<groupId>de.sekmi.histream</groupId>
<artifactId>histream-skos</artifactId>
<version>0.2-alpha</version>
<parent>
<groupId>de.sekmi.histream</groupId>
<artifactId>histream</artifactId>
<version>0.2-alpha</version>
</parent>
<build>
<plugins>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>de.sekmi.histream</groupId>
<artifactId>histream-core</artifactId>
<version>0.2-alpha</version>
</dependency>
<!-- dependencies for RDF libraries -->
<dependency>
<groupId>org.openrdf.sesame</groupId>
<artifactId>sesame-model</artifactId>
<version>2.8.3</version>
</dependency>
<dependency>
<!-- in memory store -->
<groupId>org.openrdf.sesame</groupId>
<artifactId>sesame-sail-memory</artifactId>
<version>2.8.3</version>
</dependency>
<dependency>
<groupId>org.openrdf.sesame</groupId>
<artifactId>sesame-repository-sail</artifactId>
<version>2.8.3</version>
</dependency>
<!-- RDF i/o -->
<dependency>
<groupId>org.openrdf.sesame</groupId>
<artifactId>sesame-rio-api</artifactId>
<version>2.8.3</version>
</dependency>
<dependency>
<groupId>org.openrdf.sesame</groupId>
<artifactId>sesame-rio-turtle</artifactId>
<version>2.8.3</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix nom: <http://sekmi.de/histream/nomenclature#> .
@prefix : <http://sekmi.de/histream/concepts#> .
nom: dc:title "HIStream concept ontology nomenclature base".
nom:nomenclature a rdfs:Class ;
rdfs:subClassOf rdfs:Datatype .
nom:CodingSystem a rdfs:Class ;
rdfs:subClassOf rdfs:Datatype .
nom:enum a rdfs:Class ;
rdfs:subClassOf rdfs:Datatype .
nom:ConceptModifier a rdfs:Class ;
rdfs:subclassOf skos:Concept .
# TODO: rdfs:Property correct???
nom:valueType a rdfs:Property .
nom:valueEnum a rdfs:Property .
nom:enumEntry a rdfs:Class .
nom:constValue a rdfs:Class .
nom:hasModifier a rdfs:Property .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix nom: <http://sekmi.de/histream/nomenclature#> .
@prefix : <http://sekmi.de/histream/concepts#> .
: dc:title "HIStream meta ontology".
#
# define concept value types
#
:empty a rdfs:Datatype .
:enum a rdfs:Datatype .
# predicate for concepts
:valueType a rdf:Property ;
owl:oneOf ( xsd:decimal xsd:string xsd:integer :enum :empty ) .
:ConceptModifier a rdfs:Class .
# Todo: add required predicates :valueType, ...
:hasModifier a rdf:Property ;
rdfs:range :ConceptModifier .
nom:id a rdf:Property;
rdfs:range xsd:string .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix nom: <http://sekmi.de/histream/nomenclature#> .
@prefix : <http://sekmi.de/histream/concepts#> .
: dc:title "HIStream concept ontology".
:versionOf a owl:ObjectProperty;
rdfs:domain skos:Concept;
rdfs:range skos:Concept.
:hasVersion a owl:ObjectProperty;
owl:inverseOf :versionOf;
rdfs:domain skos:Concept;
rdfs:range skos:Concept.
:Diagnoses a skos:ConceptScheme;
skos:hasTopConcept :Icd10.
:Procedures a skos:ConceptScheme;
skos:hasTopConcept :Ops301.
:Icd10 a skos:Concept;
skos:inScheme :Diagnoses;
skos:prefLabel "Diagnosen (ICD-10)"@de;
skos:prefLabel "Diagnoses (ICD-10)"@en;
skos:narrower :Icd10a00b99;
dc:description "Diagnosen nach ICD-10".
:Icd10a00b99 a skos:Concept;
skos:inScheme :Diagnoses;
skos:prefLabel "A00-B99"@de;
skos:narrower :Icd10a00a09;
dc:description "Bestimmte infektiöse und parasitäre Krankheiten"@de.
:Icd10a00a09 a skos:Concept;
skos:inScheme :Diagnoses;
skos:prefLabel "Infektiöse Darmkrankheiten (A00-A09)"@de;
skos:narrower :Icd10_a00_9;
dc:description "Infektiöse Darmkrankheiten"@de.
:Icd10_a00_9 a skos:Concept;
skos:inScheme :Diagnoses;
skos:notation "A00.9"^^nom:icd10_2010;
skos:notation "A00.9"^^nom:icd10_2011;
skos:notation "A00.9"^^nom:icd10_2012;
skos:notation "I10-2011:A00.9"^^xsd:string;
skos:prefLabel "A00.9: Cholera, nicht näher bezeichnet"@de .
:Ops301 a skos:Concept;
skos:inScheme :Procedures;
skos:prefLabel "Prozeduren (OPS)"@de;
skos:prefLabel "Procedures (OPS/German ICPM)"@en;
dc:description "Prozeduren und Therapien nach OPS".
:Patient a skos:ConceptScheme;
skos:hasTopConcept :PatientConcept.
:PatientConcept a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Patient"@de;
skos:prefLabel "Patient"@en;
skos:narrower :MasterData;
skos:narrower :Timepoints.
:MasterData a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Stammdaten"@de;
skos:prefLabel "Master data"@en;
skos:narrower :Age;
skos:narrower :Sex.
:Age a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Alter"@de;
skos:prefLabel "Age"@en;
skos:notation "p:age"^^xsd:string.
:Sex a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Geschlecht"@de;
skos:prefLabel "Sex"@en;
skos:notation "p:sex"^^xsd:string.
:Timepoints a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Zeitpunkte"@de;
skos:prefLabel "Time points"@en;
skos:narrower :Admission;
skos:narrower :Discharge;
dc:description "Zeitpunkte xxx".
:Admission a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Aufnahme"@de;
skos:prefLabel "Admission"@en;
skos:narrower :AdmissionI;
skos:narrower :AdmissionO;
skos:narrower :AdmissionE.
:AdmissionI a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Stationär"@de;
skos:prefLabel "Inpatient"@en;
skos:notation "ADM:admission:I"^^xsd:string.
:AdmissionO a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Ambulant"@de;
skos:prefLabel "Outpatient"@en;
skos:notation "ADM:admission:O"^^xsd:string.
:AdmissionE a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Notaufnahme"@de;
skos:prefLabel "Emergency"@en;
skos:notation "ADM:admission:E"^^xsd:string.
\ No newline at end of file
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix nom: <http://sekmi.de/histream/nomenclature#> .
@prefix : <http://sekmi.de/histream/concepts#> .
nom: dc:title "HIStream concept ontology for testing".
:TestScheme a skos:ConceptScheme ;
skos:hasTopConcept :TestData .
:TestData a skos:Concept ;
skos:prefLabel "TestData_label_en"@en ;
skos:prefLabel "TestData_label_de"@de ;
skos:narrower :TestEnumConcept ;
skos:narrower :TestStringConcept ;
skos:narrower :TestIntegerConcept ;
skos:narrower :TestDecimalConcept ;
dc:description "Top concept for test data" .
:TestCS a rdfs:Datatype ;
nom:id "test_cs" ;
rdfs:comment "Test coding system" ;
nom:hasModifier :TestConstModifier ;
owl:onDatatype xsd:string .
:TestEnumConcept a skos:Concept;
skos:inScheme :TestData;
nom:valueType nom:enum;
nom:valueEnum [
nom:enumEntry [ nom:constValue "1"^^xsd:string; skos:prefLabel "1_de"@de; skos:prefLabel "1_en"@en ] ;
nom:enumEntry [ nom:constValue "2"^^xsd:string; skos:prefLabel "2_de"@de; skos:prefLabel "2_en"@en ] ;
] ;
skos:prefLabel "Enum_label_de"@de;
skos:prefLabel "Enum_label_en"@en;
skos:notation "Enum"^^:TestCS .
:TestIntegerConcept a skos:Concept;
skos:inScheme :TestData ;
nom:valueType xsd:integer ;
skos:prefLabel "Integer_label_en"@en ;
skos:notation "Int"^^:TestCS .
:TestStringConcept a skos:Concept;
skos:inScheme :TestData ;
nom:valueType xsd:string ;
skos:prefLabel "String_label_en"@en ;
skos:notation "String"^^:TestCS .
:TestDecimalConcept a skos:Concept;
skos:inScheme :TestData ;
nom:valueType xsd:decimal ;
skos:prefLabel "Decimal_label_en"@en ;
skos:notation "Decimal"^^:TestCS .
:TestConstModifier a :ConceptModifier ;
rdfs:comment "Modifier also a skos:Concept?" ;
skos:prefLabel "ConstModifier_label_en"@en;
skos:prefLabel "ConstModifier_label_de"@de;
skos:notation "Const"^^xsd:string ;
nom:constValue "C"^^xsd:string .
:admitdiag a :ConceptModifier ;
rdfs:comment "Modifier also a skos:Concept?" ;
skos:prefLabel "Admit diagnosis"@en;
skos:prefLabel "Aufnahmediagnose"@de;
skos:notation "Type"^^xsd:string ;
nom:constValue "AD"^^xsd:string .
# will result in queries: Type=AD
nom:icd10_2012 a rdfs:Datatype ;
nom:id "I10-2012" ;
rdfs:comment "Datentyp für ICD10-Katalog 2012" ;
owl:onDatatype xsd:string ;
nom:hasModifier :admitdiag ;
owl:withRestrictions (
[
xsd:pattern "[A-Z][0-9.]+"
]
) .
nom:icd10_2011 a rdfs:Datatype ;
nom:id "I10-2011" ;
rdfs:comment "Datentyp für ICD10-Katalog 2011" ;
owl:onDatatype xsd:string ;
owl:withRestrictions (
[
xsd:pattern "[A-Z][0-9.]+"
]
) .
nom:imdd a rdfs:Datatype ;
nom:id "IMDD" ;
rdfs:comment "Imeso Medical Data Dictionary" ;
owl:onDatatype xsd:string .
:Imeso a skos:ConceptScheme;
skos:hasTopConcept :ImesoData .
:ImesoData a skos:Concept;
skos:inScheme :Imeso;
skos:prefLabel "Imeso"@de;
skos:narrower :IMDD_Temp;
skos:narrower :IMDD_HF;
skos:narrower :IMDD_AF;
skos:narrower :Test_enum;
dc:description "Werte aus Imeso-Software".
:IMDD_Temp a skos:Concept;
skos:inScheme :Imeso;
skos:prefLabel "Temperatur"@de;
skos:prefLabel "Temperature"@en;
nom:valueType xsd:decimal;
skos:notation "MDD_Temp"^^nom:imdd .
:IMDD_HF a skos:Concept;
skos:inScheme :Imeso;
nom:valueType xsd:integer;
skos:prefLabel "Heart rate"@en;
skos:prefLabel "Herzfrequenz"@de;
skos:notation "MDD_HF"^^nom:imdd .
:IMDD_AF a skos:Concept;
skos:inScheme :Imeso;
nom:valueType xsd:integer;
skos:prefLabel "Respiratory rate"@de;
skos:prefLabel "Atemfrequenz"@de;
skos:notation "MDD_AF"^^nom:imdd .
:Test_enum2 a skos:Concept;
skos:inScheme :Imeso;
nom:valueType :enum;
nom:valueEnum [
nom:enumEntry [ nom:constValue "1"^^xsd:string; skos:prefLabel "Erstens"@de; skos:prefLabel "First"@en ];
nom:enumEntry [ nom:constValue "2"^^xsd:string; skos:prefLabel "Zweitens"@de; skos:prefLabel "Second"@en ];
] ;
skos:prefLabel "Test enum"@de;
skos:notation "MDD_Enum"^^nom:imdd .
:Diagnoses a skos:ConceptScheme;
skos:hasTopConcept :Icd10.
:Procedures a skos:ConceptScheme;
skos:hasTopConcept :Ops301.
:Icd10 a skos:Concept;
skos:inScheme :Diagnoses;
skos:prefLabel "Diagnosen (ICD-10)"@de;
skos:prefLabel "Diagnoses (ICD-10)"@en;
skos:narrower :Icd10a00b99;
dc:description "Diagnosen nach ICD-10".
:Icd10a00b99 a skos:Concept;
skos:inScheme :Diagnoses;
skos:prefLabel "A00-B99"@de;
skos:narrower :Icd10a00a09;
dc:description "Bestimmte infektiöse und parasitäre Krankheiten"@de.
:Icd10a00a09 a skos:Concept;
skos:inScheme :Diagnoses;
skos:prefLabel "Infektiöse Darmkrankheiten (A00-A09)"@de;
skos:narrower :Icd10_a00_9;
dc:description "Infektiöse Darmkrankheiten"@de.
:Icd10_a00_9 a skos:Concept;
skos:inScheme :Diagnoses;
skos:notation "A00.9"^^nom:icd10_2011;
skos:notation "A00.9"^^nom:icd10_2012;
skos:notation "I10-2011:A00.9"^^xsd:string;
skos:prefLabel "A00.9: Cholera, nicht näher bezeichnet"@de .
:Ops301 a skos:Concept;
skos:inScheme :Procedures;
skos:prefLabel "Prozeduren (OPS)"@de;
skos:prefLabel "Procedures (OPS/German ICPM)"@en;
dc:description "Prozeduren und Therapien nach OPS".
:Patient a skos:ConceptScheme;
skos:hasTopConcept :PatientConcept.
:PatientConcept a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Patient"@de;
skos:prefLabel "Patient"@en;
skos:narrower :MasterData;
skos:narrower :Timepoints.
:MasterData a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Stammdaten"@de;
skos:prefLabel "Master data"@en;
skos:narrower :Age;
skos:narrower :Sex.
:Age a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Alter"@de;
skos:prefLabel "Age"@en;
skos:notation "p:age"^^xsd:string.
:Sex a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Geschlecht"@de;
skos:prefLabel "Sex"@en;
skos:notation "p:sex"^^xsd:string.
:Timepoints a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Zeitpunkte"@de;
skos:prefLabel "Time points"@en;
skos:narrower :Admission;
skos:narrower :Discharge;
dc:description "Zeitpunkte xxx".
:Admission a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Aufnahme"@de;
skos:prefLabel "Admission"@en;
skos:narrower :AdmissionI;
skos:narrower :AdmissionO;
skos:narrower :AdmissionE.
:AdmissionI a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Stationär"@de;
skos:prefLabel "Inpatient"@en;
skos:notation "ADM:admission:I"^^xsd:string.
:AdmissionO a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Ambulant"@de;
skos:prefLabel "Outpatient"@en;
skos:notation "ADM:admission:O"^^xsd:string.
:AdmissionE a skos:Concept;
skos:inScheme :Patient;
skos:prefLabel "Notaufnahme"@de;
skos:prefLabel "Emergency"@en;
skos:notation "ADM:admission:E"^^xsd:string.
package de.sekmi.histream.ontology.skos;
import java.util.ArrayList;
import java.util.Locale;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.Value;
import org.openrdf.model.vocabulary.DC;
import org.openrdf.model.vocabulary.SKOS;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;
import de.sekmi.histream.ontology.Concept;
import de.sekmi.histream.ontology.OntologyException;
public class ConceptImpl implements Concept {
private Resource res;
private Store store;
public ConceptImpl(Store store, Resource concept){
this.store = store;
this.res = concept;
}
@Override
public Concept[] getNarrower() throws OntologyException {
return store.getNarrower(this);
}
public Resource getResource(){
return res;
}
public String toString(){
return res.toString();
}
@Override
public String[] getIDs() throws OntologyException {
ArrayList<String> ids = new ArrayList<>();
try{
RepositoryResult<Statement> s = store.getConnection().getStatements(res, SKOS.NOTATION, null, true);
try{
while( s.hasNext() ){
Value o = s.next().getObject();
ids.add(o.stringValue());
}
}finally{
s.close();
}
}catch( RepositoryException e ){
throw new OntologyException(e);
}
return ids.toArray(new String[ids.size()]);
}
@Override
public Concept[] getBroader() throws OntologyException {
return store.getBroader(this);
}
@Override
public String getPrefLabel(Locale locale) throws OntologyException {
return store.getLocalString(getResource(), SKOS.PREF_LABEL, locale.toString());
}
@Override
public String getDescription(Locale locale) throws OntologyException {
return store.getLocalString(getResource(), DC.DESCRIPTION, locale.toString());
}
}
package de.sekmi.histream.ontology.skos;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.openrdf.model.Literal;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.model.util.Literals;
import org.openrdf.model.vocabulary.SKOS;
import org.openrdf.repository.Repository;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;
import org.openrdf.repository.sail.SailRepository;
import org.openrdf.rio.RDFFormat;
import org.openrdf.rio.RDFParseException;
import org.openrdf.sail.memory.MemoryStore;
import de.sekmi.histream.ontology.Concept;
import de.sekmi.histream.ontology.Ontology;
import de.sekmi.histream.ontology.OntologyException;
public class Store implements Ontology {
private Repository repo;
private RepositoryConnection rc;
private final static Concept[] noConcepts = new Concept[]{};
public Store(File[] files) throws RepositoryException, RDFParseException, IOException{
repo = new SailRepository(new MemoryStore());
repo.initialize();
rc = repo.getConnection();
String baseURI = null;
for( File file : files ){
rc.add(file, baseURI, RDFFormat.TURTLE);
}
}
public Store(File file) throws RepositoryException, RDFParseException, IOException{
this(new File[]{file});
}
public RepositoryConnection getConnection(){return rc;}
/**
* Collect concepts from a statement iterator to an array.
* The iterator will be closed after the method returns
* @param result statement iterator which yields SKOSConcept resources as objects
* @return array of concepts
* @throws RepositoryException
*/
private Concept[] collectConcepts(RepositoryResult<Statement> result) throws RepositoryException{
List<Concept> concepts = new ArrayList<>();
try{
while( result.hasNext() ){
Statement s = result.next();
concepts.add(new ConceptImpl(this, (Resource)s.getObject()));
}
}finally{
result.close();
}
if( concepts.size() == 0 )return noConcepts;
else return concepts.toArray(new Concept[concepts.size()]);
}
public Concept[] getTopConcepts()throws OntologyException{
return getRelatedConcepts(null, SKOS.HAS_TOP_CONCEPT);
}
private Concept[] getRelatedConcepts(Resource subject, URI predicate)throws OntologyException{
RepositoryResult<Statement> rr;
try {
rr = rc.getStatements(subject, predicate, null, true);
return collectConcepts(rr);
} catch (RepositoryException e) {
throw new OntologyException(e);
}
}
Concept[] getBroader(ConceptImpl concept)throws OntologyException{
return getRelatedConcepts(concept.getResource(), SKOS.BROADER);
}
Concept[] getNarrower(ConceptImpl concept)throws OntologyException{
return getRelatedConcepts(concept.getResource(), SKOS.NARROWER);
}
public void printTopConcepts() throws OntologyException{
for( Concept c : getTopConcepts() ){
System.out.println("Top: "+c);
}
}
private void printSubHierarchy(int indent, Concept concept) throws OntologyException{
StringBuilder b = new StringBuilder();
for( int i=0; i<indent; i++ )b.append('\t');
System.out.println(b.toString()+concept.toString());
for( Concept c : concept.getNarrower() ){
printSubHierarchy(indent+1, c);
}
}
public void printConceptHierarchy()throws OntologyException{
for( Concept c : getTopConcepts() ){
printSubHierarchy(0, c);
}
}
@Override
public Concept getConceptByNotation(String id) throws OntologyException {
try {
RepositoryResult<Statement> rs = rc.getStatements(null, SKOS.NOTATION, Literals.createLiteral(rc.getValueFactory(), id), true);
try{
if( !rs.hasNext() )return null;
Resource s = rs.next().getSubject();
if( rs.hasNext() ){
// multiple concepts with same id
// this should not happen
throw new OntologyException("Notation '"+id+"' with multiple concepts");
}
return new ConceptImpl(this, s);
}finally{
rs.close();
}
}catch( RepositoryException e ){
throw new OntologyException(e);
}
}
String getLocalString(Resource subject, URI predicate, String language) throws OntologyException {
// empty language same as no language
if( language.length() == 0 )
language = null;
try {
RepositoryResult<Statement> rs = rc.getStatements(subject, predicate, null, true);
try{