I have an ontology that contains plants and diseases and a property treat (a plant treats diseases). I have a lot of plants and diseases, but now I want to add a disease that is treatable by a combination of two or more plants. For instance, how can I represent the following sentence?
Disease X is treatable by the combination of plant A and plant B, but not by plant A or plant B alone.
I've been thinking to obtain this using a reasoner, but I have no idea how.
It sounds like you have, at the moment, an ontology with a classes Disease and Plant, and a property treats with domain Plant and range Disease. As I understand it, the problem is that what should treat some Diseases are not individual Plants, but rather combinations of them. In these cases, we might say that a plant is used in the treatment of a disease, but does not, itself, treat the disease. It is probably reasonable to say, too, that if a plant, by itself, treats a disease, then it also is used in the treatment of a disease.
So, you have a class of individuals that you haven't considered before, that is combinations of plants, so why not introduce a class PlantCombination and a property hasComponent that relates PlantCombinations to the plants in the combination? You can also add a restriction that says that each plant combination has at least two plants, if you like, by saying PlantCombination SubClassOf hasComponent min 2 Plant. Since both Plants and PlantCombinations can treat Diseases, you'll want to change the domain of treats to be Plant or PlantCombination. To ensure that a reasoner can infer that if plant82 treats disease92 then plant82 isUsedToTreat disease92, you can assert that treats SubPropertyOf isUsedToTreat. (This will also mean that a plant combination that treats a disease is also used to treat that disease.) To ensure that when a combination with a component plant23 treats a disease, that plant23 is used to treat the disease, you can add the assertion that inverse(hasComponent) o treats SubPropertyOf isUsedToTreat. Here's an ontology that does just that:
N3 Format
#prefix : <http://www.example.org/plantsAndDiseases#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
<http://www.example.org/plantsAndDiseases>
a owl:Ontology .
:Plant
a owl:Class .
:Disease
a owl:Class .
:PlantCombination
a owl:Class ;
rdfs:subClassOf
[ a owl:Restriction ;
owl:minQualifiedCardinality
"2"^^xsd:nonNegativeInteger ;
owl:onClass :Plant ;
owl:onProperty :hasComponent
] .
:hasComponent
a owl:ObjectProperty ;
rdfs:domain :PlantCombination ;
rdfs:range :Plant .
:isUsedToTreat
a owl:ObjectProperty ;
rdfs:comment "X isUsedToTreat Y means that X is used in the treatment of Y. X may either treat Y, or may be a component of a combination that treats Y." ;
rdfs:domain
[ a owl:Class ;
owl:unionOf (:Plant :PlantCombination)
] ;
rdfs:range :Disease ;
owl:propertyChainAxiom
([ owl:inverseOf :hasComponent
] :treats) .
:treats
a owl:ObjectProperty ;
rdfs:comment "X treats Y means that X is a sufficient treatment for Y." ;
rdfs:domain
[ a owl:Class ;
owl:unionOf (:Plant :PlantCombination)
] ;
rdfs:range :Disease ;
rdfs:subPropertyOf :isUsedToTreat .
OWL Functional Syntax
Prefix(xsd:=<http://www.w3.org/2001/XMLSchema#>)
Prefix(owl:=<http://www.w3.org/2002/07/owl#>)
Prefix(xml:=<http://www.w3.org/XML/1998/namespace>)
Prefix(rdf:=<http://www.w3.org/1999/02/22-rdf-syntax-ns#>)
Prefix(rdfs:=<http://www.w3.org/2000/01/rdf-schema#>)
Ontology(<http://www.example.org/plantsAndDiseases>
Declaration(Class(<http://www.example.org/plantsAndDiseases#Disease>))
Declaration(Class(<http://www.example.org/plantsAndDiseases#Plant>))
Declaration(Class(<http://www.example.org/plantsAndDiseases#PlantCombination>))
SubClassOf(<http://www.example.org/plantsAndDiseases#PlantCombination> ObjectMinCardinality(2 <http://www.example.org/plantsAndDiseases#hasComponent> <http://www.example.org/plantsAndDiseases#Plant>))
Declaration(ObjectProperty(<http://www.example.org/plantsAndDiseases#hasComponent>))
ObjectPropertyDomain(<http://www.example.org/plantsAndDiseases#hasComponent> <http://www.example.org/plantsAndDiseases#PlantCombination>)
ObjectPropertyRange(<http://www.example.org/plantsAndDiseases#hasComponent> <http://www.example.org/plantsAndDiseases#Plant>)
Declaration(ObjectProperty(<http://www.example.org/plantsAndDiseases#isUsedToTreat>))
AnnotationAssertion(rdfs:comment <http://www.example.org/plantsAndDiseases#isUsedToTreat> "X isUsedToTreat Y means that X is used in the treatment of Y. X may either treat Y, or may be a component of a combination that treats Y.")
ObjectPropertyDomain(<http://www.example.org/plantsAndDiseases#isUsedToTreat> ObjectUnionOf(<http://www.example.org/plantsAndDiseases#PlantCombination> <http://www.example.org/plantsAndDiseases#Plant>))
ObjectPropertyRange(<http://www.example.org/plantsAndDiseases#isUsedToTreat> <http://www.example.org/plantsAndDiseases#Disease>)
Declaration(ObjectProperty(<http://www.example.org/plantsAndDiseases#treats>))
AnnotationAssertion(rdfs:comment <http://www.example.org/plantsAndDiseases#treats> "X treats Y means that X is a sufficient treatment for Y.")
SubObjectPropertyOf(<http://www.example.org/plantsAndDiseases#treats> <http://www.example.org/plantsAndDiseases#isUsedToTreat>)
ObjectPropertyDomain(<http://www.example.org/plantsAndDiseases#treats> ObjectUnionOf(<http://www.example.org/plantsAndDiseases#PlantCombination> <http://www.example.org/plantsAndDiseases#Plant>))
ObjectPropertyRange(<http://www.example.org/plantsAndDiseases#treats> <http://www.example.org/plantsAndDiseases#Disease>)
SubObjectPropertyOf(ObjectPropertyChain(ObjectInverseOf(<http://www.example.org/plantsAndDiseases#hasComponent>) <http://www.example.org/plantsAndDiseases#treats>) <http://www.example.org/plantsAndDiseases#isUsedToTreat>)
)
Alternative to Joshua's answer: You can represent diseases and plants as OWL classes, as here you refer to sets of plants (not particular instances, which you would find in the nature). You can then link classes with existential restrictions (some - common pattern in biology).
You need also to introduce a supplementary step in your modelling, as mentioned: Plants can be for example ingredients of treatments, diseases being treatable by treatments.
Then if you consider the following commented (#) ontology (Manchester syntax), I describe the axioms for the modelling. You can save the file and open it with Protege.
Prefix: xsd: <http://www.w3.org/2001/XMLSchema#>
Prefix: owl: <http://www.w3.org/2002/07/owl#>
Prefix: : <http://www.example.org/demo.owl#>
Prefix: xml: <http://www.w3.org/XML/1998/namespace>
Prefix: rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
Prefix: rdfs: <http://www.w3.org/2000/01/rdf-schema#>
Ontology: <http://www.example.org/demo.owl>
ObjectProperty: has-ingredient
ObjectProperty: treatableBy
Class: owl:Thing
Class: PlantA
SubClassOf:
Plant
Class: Treatment
#Your treatment obtained by mixing some
#of the plant B and some of the plant A
Class: TreatmentAB
SubClassOf:
Treatment,
(has-ingredient some PlantA)
and (has-ingredient some PlantB)
Class: PlantB
SubClassOf:
Plant
#This treatment has ingredient the plant A
Class: TreatmentA
SubClassOf:
has-ingredient some PlantA,
Treatment
#This treatment is made from plant B (among other things)
Class: TreatmentB
SubClassOf:
Treatment,
has-ingredient some PlantB
Class: Disease
Class: Plant
# This disease is treatable by the TreatmentAB
Class: DiseaseA
SubClassOf:
treatableBy some TreatmentAB,
Disease
Class: DiseaseB
SubClassOf:
treatableBy some TreatmentB,
Disease
Now if we were reasoning over the ontology and ask for the subclasses of treatableBy some TreatmentA we wouldn't get any class. The expression treatableBy some TreatmentAB returns DiseaseA as expected.
Related
I have an ontology where instance types are described with class restrictions. My goal is to use a reasoner to generate all other class restrictions which are valid for an instance. Consider this toy ontology example below:
#Class Hierarchy
:Highest_Class rdf:type owl:Class .
:Lower_Class rdf:type owl:Class ;
rdfs:subClassOf :Highest_Class .
:Lowest_Class rdf:type owl:Class ;
rdfs:subClassOf :Lower_Class .
#The class of named individuals
:ThingClass rdf:type owl:Class .
#Object property relationship
:related_to rdf:type owl:ObjectProperty ,
owl:TransitiveProperty .
#Instances in ontology
:thing_1 rdf:type owl:NamedIndividual ,
:ThingClass ,
[ rdf:type owl:Restriction ;
owl:onProperty :related_to ;
owl:someValuesFrom :Lowest_Class
] .
:thing_2 rdf:type owl:NamedIndividual ,
:ThingClass ,
[ rdf:type owl:Restriction ;
owl:onProperty :related_to ;
owl:someValuesFrom :Lower_Class
] .
This is what I would expect the reasoner to infer:
Since thing_1 is something that is related_to some Lowest_Class, and Lowest_Class is a subclass of Lower_Class and Highest_Class, then thing_1 is something that is related_to some Lower_Class and is related_to some Highest_Class.
Since thing_2 is something that is related_to some Lower_Class, and Lower_Class is a subclass of Highest_Class , then thing_2 is something that is "related_to some Highest_Class".
If I run a reasoner in Protege on this ontology and use the DL query tab to find individuals which are related_to some Highest_Class or related_to some Lower_Class, I see thing_1 and thing_2 listed, as expected. However, when I try to run a reasoner using the ROBOT tool or ELK command line tool, these class restriction axioms do not appear in the reasoned ontology.
Is there a way to produce such axioms into a reasoned ontology after running inference or is this not possible? Also, an explanation on how DL query is able to correctly associate individuals with the class restriction query would be very helpful.
I have a set of multiple files that store time series data.
The time series data is stored as a CSV file with multiple large columns.
E.g.:
Time
Force
1
0.1
2
0.2
3
0.2
4
0.3
...
...
I would like to make this data accessible using RDF without conversion of the actual data into RDF. The columns in the file should be related to ontology individuals.
I know I can create a json-ld file that stores the meta information of the file. I read that this file is usually stored together with the csv file as "-metadata.json" file.
I made a minimal example for my table:
{
"#context":[
"http://www.w3.org/ns/csvw"
],
"url":"PATH-TO-URL",
"dialect":{
"delimiter":"\t",
"skipRows":4,
"headerRowCount":2,
"encoding":"ISO-8859-1"
},
"tableSchema":{
"columns":[
{
"titles":"Time",
"#id":"Time",
"#type":"Column"
},
{
"titles":"Force",
"#id":"Force",
"#type":"Column"
}
]
}
}
Now I also have an ontology, with individuals representing time and force of a specific experiment (F1 and T1). This ontology is stored in a tripplestore.
E.g.:
#prefix : <http://www.semanticweb.org/example#> .
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix xml: <http://www.w3.org/XML/1998/namespace> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#base <http://www.semanticweb.org/example> .
<http://www.semanticweb.org/example> rdf:type owl:Ontology .
#################################################################
# Object Properties
#################################################################
### http://www.semanticweb.org/example#hasDataReference
:hasDataReference rdf:type owl:ObjectProperty .
#################################################################
# Classes
#################################################################
### http://www.semanticweb.org/example#Force
:Force rdf:type owl:Class .
### http://www.semanticweb.org/example#Time
:Time rdf:type owl:Class .
#################################################################
# Individuals
#################################################################
### http://www.semanticweb.org/example#F1
:F1 rdf:type owl:NamedIndividual ,
:Force .
### http://www.semanticweb.org/example#T1
:T1 rdf:type owl:NamedIndividual ,
:Time .
I would like to relate these individuals to the columns stored in the "-metadata.json" file. So that the user can locate the specific column by following the graph from the individuals.
What would be the correct way to link the individuals with the column location ? Do I need to convert the json-ld to ttl, add it to the tripplestore and then add a relation to the column, e.g. using my "hasDataReference" relation?
I think the file itself could be made accessible using an ontology like dcat.
In general, I am looking for the recommended way to make csv data (e.g. the columns and rows) available via an ontology-based graph.
I do not want to load the entire column in the tripplestore only the location of the column in the file, so that the user can extract the column if needed.
I'm creating an ontology using Apache Jena. However, I can't find a way of creating custom datatypes as in the following example:
'has value' some xsd:float[>= 0.0f , <= 15.0f].
Do you have any ideas?
It seems what you need is DatatypeRestriction with two facet restrictions: xsd:minInclusive and xsd:maxInclusive.
It is OWL2 constructions.
org.apache.jena.ontology.OntModel does not support OWL2, only OWL1.1 partially (see documentation), and, therefore, there are no builtin methods for creating such data-ranges (there is only DataOneOf data range expression, see OntModel#createDataRange(RDFList)).
So you have to create a desired datatype manually, triple by triple, using the general org.apache.jena.rdf.model.Model interface.
In RDF, it would look like this:
_:x rdf:type rdfs:Datatype.
_:x owl:onDatatype DN.
_:x owl:withRestrictions (_:x1 ... _:xn).
See also owl2-quick-guide.
Or, to build such an ontology, you can use some external utilities or APIs.
For example, in ONT-API (v. 2.x.x) the following snippet
String ns = "https://stackoverflow.com/questions/54131709#";
OntModel m = OntModelFactory.createModel()
.setNsPrefixes(OntModelFactory.STANDARD).setNsPrefix("q", ns);
OntDataRange.Named floatDT = m.getDatatype(XSD.xfloat);
OntFacetRestriction min = m.createFacetRestriction(OntFacetRestriction.MinInclusive.class,
floatDT.createLiteral("0.0"));
OntFacetRestriction max = m.createFacetRestriction(OntFacetRestriction.MaxInclusive.class,
floatDT.createLiteral("15.0"));
OntDataRange.Named myDT = m.createDatatype(ns + "MyDatatype");
myDT.addEquivalentClass(m.createDataRestriction(floatDT, min, max));
m.createResource().addProperty(m.createDataProperty(ns + "someProperty"),
myDT.createLiteral("2.2"));
m.write(System.out, "ttl");
will produce the following ontology:
#prefix q: <https://stackoverflow.com/questions/54131709#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
[ q:someProperty "2.2"^^q:MyDatatype ] .
q:MyDatatype a rdfs:Datatype ;
owl:equivalentClass [ a rdfs:Datatype ;
owl:onDatatype xsd:float ;
owl:withRestrictions ( [ xsd:minInclusive "0.0"^^xsd:float ]
[ xsd:maxInclusive "15.0"^^xsd:float ]
)
] .
q:someProperty a owl:DatatypeProperty .
I have a semantic network. Is it possible to use a jena framework to create a new object in the semantic web based on some rule. For example there is an object has a certain property, then you need to create a new object and make a connection between them. Is it possible?
Yes, this is possible in Jena's rule system. Typically, we create such nodes using the makeSkolem Reasoner Builtin Primitive:
[example:
(?a urn:ex:owns ?b)
makeSkolem(?ownership,?a,?b)
->
(?a urn:ex:hasOwnership ?ownership)
(?ownership urn:ex:of ?b)
]
This will create a new blank node in the graph that will be used to reify the <urn:ex:owns> triple. E.g., when given a graph containing the triple <urn:ex:a> <urn:ex:owns> <urn:ex:b> as input, the preceding rule will generate the following graph structure:
<urn:ex:a> <urn:ex:hasOwnership> [
<urn:ex:of> <urn:ex:b>
].
You can also construct URIs in your rule if you have some scheme for generating them.
Java Example
Assuming that so.rules exists on your classpath and contains the rule from above, the following java code will demonstrate custom rules for this task.
// Obtains a list of rules to pass to a rule-based reasoner
// These rules are read from a file.
// This is the most common case.
final List<Rule> rules;
try (final InputStream src = Resources.getResource("so.rules").openStream()) {
rules = Rule
.parseRules(Rule.rulesParserFromReader(new BufferedReader(new InputStreamReader(src))));
}
// Create a rule-based reasoner.
// There are multiple types of reasoners available.
// You may prefer some over others (e.g., when performing OWL inference in tandem with custom rules)
final GenericRuleReasoner reasoner =
(GenericRuleReasoner) GenericRuleReasonerFactory.theInstance().create(null);
reasoner.setRules(rules);
// Create a RDF Model to store data in.
// Create an inference model to interact with.
// The inference model will store any added data in the base model.
// The inference model will store inferred triples internally.
final Model baseModel = ModelFactory.createDefaultModel();
final InfModel model = ModelFactory.createInfModel(reasoner, baseModel);
model.prepare();
// Stimulate the rule by introducing the desired triples to the graph
// :a :owns :b
final Property owns = model.createProperty("urn:ex:", "owns");
final Property hasOwnership = model.createProperty("urn:ex:","hasOwnership");
final Property of = model.createProperty("urn:ex:","of");
final Resource a = model.createResource("urn:ex:a");
final Resource b = model.createResource("urn:ex:b");
model.add(a,owns,b);
// Verify that the rule has fired. That is, that we have created some node
// and that the node relates our other two resources
// -> :a :hasOwnership [ :of :b ]
assertTrue(a.hasProperty(hasOwnership));
final Resource createdObject = a.getPropertyResourceValue(hasOwnership);
assertTrue(createdObject.hasProperty(of,b));
If you needs are reasonably simple you can use SPARQL CONSTRUCT queries, i.e.
CONSTRUCT { ?p :hasGrandfather ?g . }
WHERE {
?p :hasParent ?parent .
?parent :hasParent ?g .
?g :gender :male .
}
will cause triples to be generated for stating grandfather relations.
If your needs are more sophisticated, you can achieve this with SHACL for which an implementation on top of Jena exists. I will give a brief example. Assume you have the following RDF data:
#prefix ex: <http://example.com/ns#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
ex:InvalidRectangle
a ex:Rectangle .
ex:NonSquareRectangle
a ex:Rectangle ;
ex:height 2 ;
ex:width 3 .
ex:SquareRectangle
a ex:Rectangle ;
ex:height 4 ;
ex:width 4 .
for which you define the following shape file:
#prefix ex: <http://example.com/ns#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix dash: <http://datashapes.org/dash#> .
#prefix sh: <http://www.w3.org/ns/shacl#> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
ex:Rectangle
a rdfs:Class, sh:NodeShape ;
rdfs:label "Rectangle" ;
sh:property [
sh:path ex:height ;
sh:datatype xsd:integer ;
sh:maxCount 1 ;
sh:minCount 1 ;
sh:name "height" ;
] ;
sh:property [
sh:path ex:width ;
sh:datatype xsd:integer ;
sh:maxCount 1 ;
sh:minCount 1 ;
sh:name "width" ;
] ;
sh:rule [
a sh:TripleRule ;
sh:subject sh:this ;
sh:predicate rdf:type ;
sh:object ex:Square ;
sh:condition ex:Rectangle ;
sh:condition [
sh:property [
sh:path ex:width ;
sh:equals ex:height ;
] ;
] ;
] .
It will generate the following RDF data:
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://example.com/ns#SquareRectangle>
a <http://example.com/ns#Square> .
which you can add to your RDF store.
This example with code can be found here, as well as a more advanced example.
I have a question about an OWL ontology that I am making. I have a class that is actually an ID class and I would like to have instances: first, second, third etc.
The first solution that I have figured is creating individuals {first, second, third etc} for this class, but then I have to write a huge number of individuals.
The other solution is to create a data property that will be connected with my class that has type "integer".
The second solution looks more appropriate but the thing is that I can't represent the word "first", just the number 1.
Do you know how I can do that?
You could create a class of ordinals that are uniquely identified by an integer, like so (in Turtle syntax):
:hasPosition a owl:DatatypeProperty, owl:FunctionalProperty ;
rdfs:range xsd:integer .
:Ordinal a owl:Class ;
rdfs:subClassOf [
a owl:Restriction ;
owl:onProperty :hasPosition ;
owl:someValuesFrom :integer
] ;
owl:hasKey ( :hasPosition ) .
Note the use of owl:hasKey (introduced in OWL 2) which means that the value of :hasPosition identifies a unique instance. The property is functional so that an instance cannot have two distinct positions.