I look for a clearly OWL solution to define a property that is a restriction of another property, similar to an equivalent class. Restriction is based on data properties of either the domain or the range. The restricted property is definitely a subproperty, and, must be inferred.
"kid","mother","father" are Person s
father.gender = "male" data property
mother.gender = "female"
(a Male subclassOf Person = equivalent class "gender value "male")
father parentOf child ' object relation
mother parentOf child ' object relation
How to defined fatherOf property, based on parentOf and gender of father?
Clearly it is a subproperty of parentOf.
However, equivalent object property editor in Protégé does not allow setting a property query, even I do not really see if this can be solved with a property chain.
Defining fatherOf as subproperty and (manually) setting fatherOf instead of parentOf is not an option, since this family example is an oversimplified situation of a more complex scenario.
<Declaration>
<Class IRI="#Person"/>
</Declaration>
<Declaration>
<ObjectProperty IRI="#fatherOf"/>
</Declaration>
<Declaration>
<ObjectProperty IRI="#parentOf"/>
</Declaration>
<Declaration>
<DataProperty IRI="#gender"/>
</Declaration>
<Declaration>
<NamedIndividual IRI="#father"/>
</Declaration>
<Declaration>
<NamedIndividual IRI="#kid"/>
</Declaration>
<Declaration>
<NamedIndividual IRI="#mother"/>
</Declaration>
<ClassAssertion>
<Class IRI="#Person"/>
<NamedIndividual IRI="#father"/>
</ClassAssertion>
<ClassAssertion>
<Class IRI="#Person"/>
<NamedIndividual IRI="#kid"/>
</ClassAssertion>
<ClassAssertion>
<Class IRI="#Person"/>
<NamedIndividual IRI="#mother"/>
</ClassAssertion>
<ObjectPropertyAssertion>
<ObjectProperty IRI="#parentOf"/>
<NamedIndividual IRI="#father"/>
<NamedIndividual IRI="#kid"/>
</ObjectPropertyAssertion>
<ObjectPropertyAssertion>
<ObjectProperty IRI="#parentOf"/>
<NamedIndividual IRI="#mother"/>
<NamedIndividual IRI="#kid"/>
</ObjectPropertyAssertion>
<DataPropertyAssertion>
<DataProperty IRI="#gender"/>
<NamedIndividual IRI="#father"/>
<Literal datatypeIRI="&rdf;PlainLiteral">male</Literal>
</DataPropertyAssertion>
<DataPropertyAssertion>
<DataProperty IRI="#gender"/>
<NamedIndividual IRI="#mother"/>
<Literal datatypeIRI="&rdf;PlainLiteral">female</Literal>
</DataPropertyAssertion>
<SubObjectPropertyOf>
<ObjectProperty IRI="#fatherOf"/>
<ObjectProperty IRI="#parentOf"/>
</SubObjectPropertyOf>
<DataPropertyDomain>
<DataProperty IRI="#gender"/>
<Class IRI="#Person"/>
</DataPropertyDomain>
<DataPropertyRange>
<DataProperty IRI="#gender"/>
<Datatype abbreviatedIRI="xsd:string"/>
</DataPropertyRange>
So, you have something like the following in your data:
:x :parentOf :y .
:x :gender "male" .
and you would like to infer that:
:x :fatherOf :y .
I'm afraid you cannot do this in OWL. For cases like this one, you may want to rely on a rule language like SWRL, SPIN, etc. However, for the particular case of father, mother, etc, you could do the following:
define :hasParent as the inverse of :parentOf;
restrict the cardinality of :hasParent to 2;
define :hasFather as the inverse of :fatherOf;
make :hasFather a owl:FunctionalProperty;
define :hasMother as the inverse of :motherOf;
make :hasMother a owl:FunctionalProperty;
define the class :Man of male people;
define the class :Woman of female people;
make :Man disjointWith :Woman;
set the range of :hasFather to :Man;
set the range of :hasMother to :Woman.
So the ontology looks like this (in Turtle because I'm not familiar with OWL/XML):
:Person a owl:Class;
rdfs:subClassOf [
a owl:Restriction;
owl:onProperty :hasParent;
owl:cardinality 2
] .
:Man a owl:Class;
owl:equivalentclass [
a owl:Class;
owl:intersectionOf (
:Person
[
a owl:Restriction;
owl:onProperty :gender;
owl:hasValue "male";
]
)
] .
:Woman a owl:Class;
owl:equivalentclass [
a owl:Class;
owl:intersectionOf (
:Person
[
a owl:Restriction;
owl:onProperty :gender;
owl:hasValue "female";
]
)
] .
:gender a owl:DatatypeProperty, owl:FunctionalProperty .
:hasParent a owl:ObjectProperty;
owl:inverseOf :parentOf;
rdfs:domain :Person;
rdfs:range :Person .
:hasFather a owl:ObjectProperty, owl:FunctionalProperty;
rdfs:subPropertyOf :hasParent;
rdfs:range :Man .
:hasMother a owl:ObjectProperty, owl:FunctionalProperty;
rdfs:subPropertyOf :hasParent;
rdfs:range :Woman .
This should do the trick, but it's a very complicated ontology and reasoning with it may be very slow.
Edit: I added that :gender must be functional, otherwise there could be a mother who is at the same time a father and that would not work!
Related
I have this kind of structure
<ontology:Louvre>
<rdf:type ontology:Museum/>
<ontology:preserves rdf:Gioconda/>
<ontology:locatedIn rdf:Paris/>
<ontology:name>Louvre</ontology:name>
<ontology:Gioconda>
<rdf:type ontology:Artwork/>
<ontology:preserved rdf:Louvre/>
<ontology:author rdf:Leonardo/>
<nomeOpera>Gioconda</nomeOpera>
<rdf:Leonardo_Da_Vinci>
<rdf:type ontology:Painter"/>
<ontology:paint ontology:Gioconda"/>
<ontology:paint ontology:Ultima_cena"/>
<name>Leonardo Da Vinci</name>
...(other museum, artist and artwork)
I use "ontology" to indicate my prefix
Is it possible to recover the exclusive artists of a museum?
I found the solution.
This is the query that i'm looking for
SELECT DISTINCT * WHERE {
?museum ontology:preserves ?artwork .
?museum ontology:name "Louvre" .
?artwork ontology:author ?author.
FILTER NOT EXISTS{
?museum2 ontology:preserves ?artwork2 .
?artwork2 ontology:author ?author .
FILTER (?museum2 != ?museum)
}
}
I'm rather confused about why I'm receiving too little results (256 expected, 224 returned). When I run the code below, everything returns exactly as I want it, except that I miss all the classes in my ontology which lie at the highest level, or one below the highest level. I don't understand where I'm being too "strict" in my query so that these classes are not being returned in the table. They also all have parent classes (whether that be the topmost class "top concept" of the ontology, or something like an enumeration type class, either way, the leaf should still be found. Would be thankful for tips or pointers where my code might be inadvertently filtering out those classes.
SELECT DISTINCT ?leaf ?parentclasses
WHERE {
GRAPH <>
#a leaf is the lowest level class: A class that does not have a subclass
{
{
{
#I want anything which is a class
{
?leaf rdf:type owl:Class.
}
#i also want the subclass of any superclass if that exists
{
?leaf rdfs:subClassOf ?superclass .
}
#squeezed to specific section of OTL.
filter strstarts(str(?leaf), "URIgoeshere")
#Only keep the results that do not have a preflabel
OPTIONAL {
?leaf skos:prefLabel ?subclasslabel.
}
#make sure the subclasslabel is in dutch
#filter( langMatches(lang(?subclasslabel),"nl") )
#give me the label of the superclass
OPTIONAL {
?superclass skos:prefLabel ?superclasslabel.
}
#make sure it's in dutch
FILTER (lang(?superclasslabel) = "nl")
#if it exists, give me also the superclass of the superclass creating a supersuperclass
{
?superclass rdfs:subClassOf ?supersuperclass.
#give me the label of the supersuperclass
OPTIONAL {
?supersuperclass skos:prefLabel ?supersuperclasslabel.
}
#make sure it's in dutch
FILTER (lang(?supersuperclasslabel) = "nl")
#keep the leafs that are NOT The values whereby the subclass is not empty. (double negative for removing leafs where the subclass has a subclass below it)
FILTER NOT EXISTS {
?subclass rdfs:subClassOf ?leaf
FILTER (?subclass != owl:Nothing )
}
#concatenate the two parentclass variables into one
BIND(concat(str(?superclasslabel), str("-"), str(?supersuperclasslabel) ) as ?parentclasses)
}
}
}
}
}
Here is a ttl file with the same structure as my database: https://file.io/jjwkAWbK4jrF
Below is my end solution to my problem. It was more complicated than I expected, but it works.
The problem was that these classes that didn't have a parent class were not being accepted by the query. With some union cases this could be covered for 0 parent classes, 1 parent class or 2 parent classes.
SELECT DISTINCT ?leaf ?parentclasses
WHERE {
GRAPH <>
#a leaf is the lowest level class: A class that does not have a subclass
{{{{{
#I want anything which is a class
{?leaf rdf:type owl:Class.}
#squeezed
filter strstarts(str(?leaf), "graph")
#keep the leafs that are NOT The values whereby the subclass is not empty.
(double negative for removing leafs where the subclass has a subclass below it)
FILTER NOT EXISTS {?subclass rdfs:subClassOf ?leaf
FILTER (?subclass != owl:Nothing ) }
}
{
{?leaf rdfs:subClassOf ?superclass .}
#grab dutch label if available
optional {
?superclass skos:prefLabel ?superclassnllabel .
filter( langMatches(lang(?superclassnllabel),"nl") )
}
# take either as the label, but dutch over empty
bind( coalesce( ?superclassnllabel, replace(str(?
superclass),"^[^#]*#", "" ) ) as ?superclasslabel )
{
{?superclass rdfs:subClassOf ?supersuperclass.}
#grab dutch label if available
?supersuperclass skos:prefLabel ?supersuperclassnllabel .
filter( langMatches(lang(?supersuperclassnllabel),"nl") )
# take either as the label, but dutch over empty
bind( coalesce( ?supersuperclassnllabel, replace(str(?
supersuperclass),"^[^#]*#", "" ) ) as ?supersuperclasslabel )
BIND(concat(str(?superclasslabel), str(" - "), str(?
supersuperclasslabel) ) as ?parentclasses)
}
union
{
{?superclass ?p ?o.filter(!isblank(?superclass))}
FILTER NOT EXISTS {?superclass rdfs:subClassOf ?supersuperclass}
BIND(concat(str(?superclasslabel), str(" - "), str("Top
Concept") ) as ?parentclasses)
#concatenate the two parentclass variables into one
}
}
}
union
{
#figure this out, WHY IS IT HERE?
{?leaf rdf:type owl:Class .filter(!isblank(?leaf))}
FILTER strstarts(str(?leaf), "graph")
FILTER NOT EXISTS {?leaf rdfs:subClassOf ?superclass}
FILTER NOT EXISTS {?subclass rdfs:subClassOf ?leaf
FILTER (?subclass != owl:Nothing ) }
BIND (str("Top Class") as ?parentclasses )
}
}}}}
The following is a subquestion to my previous question: available here.
How to modify the following SPARQL query:
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
select ?dt ?element ?elementType {
?dt a rdfs:Datatype ;
owl:oneOf/rdf:rest*/rdf:first ?element .
bind(datatype(?element) as ?elementType)
}
in order to to get a result of only A and C? I would like to obtain { "a1" "a2" "c1" "c2" }. The above query returns all enumeration values from the ontology, I mean: { "a1" "a2" "b1" "b2" "c1" "c2" }
We are given the ontology (A and B are equivalent but presented in different style syntax):
Variant A) in the functional style syntax:
Prefix(ont:=<http://www/ont.owl#>)
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#>)
Ontology(<http://www/ont.owl>
DatatypeDefinition( ont:A DataOneOf( "a1" "a2" ) )
DatatypeDefinition( ont:B DataOneOf( "b1" "b2" ) )
DatatypeDefinition( ont:C DataOneOf( "c1" "c2" ) )
)
Variant B) in the RDF/XML style syntax:
<?xml version="1.0"?>
<!DOCTYPE rdf:RDF [
<!ENTITY ont "http://www/ont.owl#" >
<!ENTITY owl "http://www.w3.org/2002/07/owl#" >
<!ENTITY xsd "http://www.w3.org/2001/XMLSchema#" >
<!ENTITY xml "http://www.w3.org/XML/1998/namespace" >
<!ENTITY rdfs "http://www.w3.org/2000/01/rdf-schema#" >
<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#" >
]>
<rdf:RDF xmlns="http://www/ont.owl#"
xml:base="http://www/ont.owl"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:ont="http://www/ont.owl#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:xml="http://www.w3.org/XML/1998/namespace">
<owl:Ontology rdf:about="http://www/ont.owl"/>
<!--
///////////////////////////////////////////////////////////////////////////////////////
//
// Datatypes
//
///////////////////////////////////////////////////////////////////////////////////////
-->
<!-- http://www/ont.owl#A -->
<rdfs:Datatype rdf:about="&ont;A">
<owl:equivalentClass>
<rdfs:Datatype>
<owl:oneOf>
<rdf:Description>
<rdf:type rdf:resource="&rdf;List"/>
<rdf:first>a1</rdf:first>
<rdf:rest>
<rdf:Description>
<rdf:type rdf:resource="&rdf;List"/>
<rdf:first>a2</rdf:first>
<rdf:rest rdf:resource="&rdf;nil"/>
</rdf:Description>
</rdf:rest>
</rdf:Description>
</owl:oneOf>
</rdfs:Datatype>
</owl:equivalentClass>
</rdfs:Datatype>
<!-- http://www/ont.owl#B -->
<rdfs:Datatype rdf:about="&ont;B">
<owl:equivalentClass>
<rdfs:Datatype>
<owl:oneOf>
<rdf:Description>
<rdf:type rdf:resource="&rdf;List"/>
<rdf:first>b1</rdf:first>
<rdf:rest>
<rdf:Description>
<rdf:type rdf:resource="&rdf;List"/>
<rdf:first>b2</rdf:first>
<rdf:rest rdf:resource="&rdf;nil"/>
</rdf:Description>
</rdf:rest>
</rdf:Description>
</owl:oneOf>
</rdfs:Datatype>
</owl:equivalentClass>
</rdfs:Datatype>
<!-- http://www/ont.owl#C -->
<rdfs:Datatype rdf:about="&ont;C">
<owl:equivalentClass>
<rdfs:Datatype>
<owl:oneOf>
<rdf:Description>
<rdf:type rdf:resource="&rdf;List"/>
<rdf:first>c1</rdf:first>
<rdf:rest>
<rdf:Description>
<rdf:type rdf:resource="&rdf;List"/>
<rdf:first>c2</rdf:first>
<rdf:rest rdf:resource="&rdf;nil"/>
</rdf:Description>
</rdf:rest>
</rdf:Description>
</owl:oneOf>
</rdfs:Datatype>
</owl:equivalentClass>
</rdfs:Datatype>
</rdf:RDF>
<!-- Generated by the OWL API (version 3.4.2) http://owlapi.sourceforge.net -->
As I said in the comments on the previous answer:
#Annabelle I was basing the retrieval methods on the ontology that I provided. There are certainly other ways to select the data types if they're identified by IRIs. In your case, it looks like it would be values ?dt {:A :B } if you only want ?dt to be A or B.
and
In this case, note that the axiom is encoded by saying that :A is owl:equivalentClass to the datatype class expression. That's the extra link you need between the class IRI and the expression.
That gives us:
select ?dt ?element ?elementType {
values ?dt { ont:A ont:B }
?dt owl:equivalentClass/a rdfs:Datatype ;
owl:oneOf/rdf:rest*/rdf:first ?element .
bind(datatype(?element) as ?elementType)
}
This really isn't much different from the previous answer. You just need to add on the specific values that you're looking for, and then add the equivalentClass link.
I have created a small ontology. It has only one class called methods and a datatype property action_nb (integer).
Then I created two individuals :
AHP => action_nb = 20
electre => action_nb = 50
I want to execute a simple query . Select method where nb_action < 40 and the results should give me EL1.
<?xml version="1.0"?>
<!DOCTYPE rdf:RDF [
<!ENTITY owl "http://www.w3.org/2002/07/owl#" >
<!ENTITY xsd "http://www.w3.org/2001/XMLSchema#" >
<!ENTITY rdfs "http://www.w3.org/2000/01/rdf-schema#" >
<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#" >
<!ENTITY untitled-ontology-77 "http://www.semanticweb.org/diabolico/ontologies/2016/3/untitled-ontology-77#" >
]>
<rdf:RDF xmlns="http://www.semanticweb.org/diabolico/ontologies/2016/3/untitled-ontology-77#"
xml:base="http://www.semanticweb.org/diabolico/ontologies/2016/3/untitled-ontology-77"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:untitled-ontology-77="http://www.semanticweb.org/diabolico/ontologies/2016/3/untitled-ontology-77#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<owl:Ontology rdf:about="http://www.semanticweb.org/diabolico/ontologies/2016/3/untitled-ontology-77"/>
<!--
///////////////////////////////////////////////////////////////////////////////////////
//
// Data properties
//
///////////////////////////////////////////////////////////////////////////////////////
-->
<!-- http://www.semanticweb.org/diabolico/ontologies/2016/3/untitled-ontology-77#action_nb -->
<owl:DatatypeProperty rdf:about="&untitled-ontology-77;action_nb">
<rdfs:domain rdf:resource="&untitled-ontology-77;methods"/>
<rdfs:range rdf:resource="&xsd;integer"/>
</owl:DatatypeProperty>
<!--
///////////////////////////////////////////////////////////////////////////////////////
//
// Classes
//
///////////////////////////////////////////////////////////////////////////////////////
-->
<!-- http://www.semanticweb.org/diabolico/ontologies/2016/3/untitled-ontology-77#methods -->
<owl:Class rdf:about="&untitled-ontology-77;methods"/>
<!--
///////////////////////////////////////////////////////////////////////////////////////
//
// Individuals
//
///////////////////////////////////////////////////////////////////////////////////////
-->
<!-- http://www.semanticweb.org/diabolico/ontologies/2016/3/untitled-ontology-77#ahp -->
<owl:NamedIndividual rdf:about="&untitled-ontology-77;ahp">
<rdf:type rdf:resource="&untitled-ontology-77;methods"/>
<action_nb rdf:datatype="&xsd;integer">20</action_nb>
</owl:NamedIndividual>
<!-- http://www.semanticweb.org/diabolico/ontologies/2016/3/untitled-ontology-77#electre -->
<owl:NamedIndividual rdf:about="&untitled-ontology-77;electre">
<rdf:type rdf:resource="&untitled-ontology-77;methods"/>
<action_nb rdf:datatype="&xsd;integer">50</action_nb>
</owl:NamedIndividual>
</rdf:RDF>
<!-- Generated by the OWL API (version 3.4.2) http://owlapi.sourceforge.net -->
PREFIX ex: <http://example.org/so#>
SELECT ?methods
WHERE {
?inst rdf:type ex:methods .
?inst ex:action_nb ?value .
FILTER (?value < 40)
}
this is the code that I have been manipulating: but it gave me only an empty row when filtering with 40 & 2 rows when using 60
The key to understanding how to approach this is to understand how RDF triples are defined. You've stated that action_nb is the property whose values are integers that you want to compare. Therefore create your query using that property:
PREFIX untitled-ontology-77: <http://www.semanticweb.org/diabolico/ontologies/2016/3/untitled-ontology-77#>
SELECT ?inst
WHERE {
?inst untitled-ontology-77:action_nb ?value .
FILTER (?value < 40)
}
...where the FILTER clause allows only values of action_nb that are less than 40.
If the property is used in other classes, and you want to make sure that only members of methods are found, then you will also need to query for instances of that class:
PREFIX untitled-ontology-77: <http://www.semanticweb.org/diabolico/ontologies/2016/3/untitled-ontology-77#>
SELECT ?inst
WHERE {
?inst rdf:type untitled-ontology-77:methods .
?inst untitled-ontology-77:action_nb ?value .
FILTER (?value < 40)
}
I doubt you'll need DISTINCT in this case, and be aware that finding all distinct values is performed after the query, but is applied pairwise to all SELECTED values. I.e. it may not perform well with large result sets. Therefore, use DISTINCT only when necessary.
I build this ontology in protege. I have this individual ev001 that has these types Room,hasRoom only {rm001} and rm001 has data property roomName "room 1"^^xsd:string.
Right now I have a SPARQL query that returns
Event Room RoomName
ev001 {rm001}
My question is, how to get the room name from there,
here is my query so far
SELECT ?event ?room ?roomname
WHERE { ?x owl:onProperty base:hasRoom .
?event a base:FilmScreening ;
a ?x .
?x owl:allValuesFrom ?room .
}
Any advice is appreciated, thank you very much
In general, it looks like you'd just need:
SELECT ?event ?room ?roomname
WHERE {
?event base:hasRoom ?room .
?room base:roomName ?roomname.
}
You don't need to be retrieving all the axiom stuff with owl:onProperty, etc. However, in your case, the ontology is structured a bit strangely. E.g., you have content like:
<!-- http://www.example.org/ontologies/loncon3#pi00314001 -->
<owl:NamedIndividual rdf:about="http://www.example.org/ontologies/loncon3#pi00314001">
<!-- ... -->
<rdf:type>
<owl:Restriction>
<owl:onProperty rdf:resource="http://www.example.org/ontologies/loncon3#hasRoom"/>
<owl:allValuesFrom>
<owl:Class>
<owl:oneOf rdf:parseType="Collection">
<rdf:Description rdf:about="http://www.example.org/ontologies/loncon3#rm03005"/>
</owl:oneOf>
</owl:Class>
</owl:allValuesFrom>
</owl:Restriction>
</rdf:type>
<!-- ... -->
</owl:NamedIndividual>
In the Manchester syntax, that says that pi00314001 has the type:
hasRoom only { rm03005 }
Based on your question, it sounds like you expect the
pi00314001 hasRoom rm03005
is in your data, or at least inferable from it. Unfortunately, that's not what it actually means. When you say that an individual X has the type
p only D
it means it if X has any value for the property p, then that value must be an instance of D. Similarly, the content in your ontology says that if pi00314001 has a value for the property hasRoom, then that value must be from the class { rm03005 }. It doesn't say that pi00314001 actually has a value for that property, so you don't actually know whether it has rm03005 as a value for hasRoom or not.
If it's under your control, I think you'd want to add some actual object property assertions to your ontology, so that the query I mentioned above will work. Right now your ontology is telling you more about what's possible than what's actually the case.
That said, if you do want to retrieve the room from the data as it's structured now, you can follow the structure of the data and make that work too. It'd be something like:
select ?event ?roomName {
?event a [ owl:onProperty base:hasRoom ;
owl:allValuesFrom/owl:oneOf/rdf:rest*/rdf:first ?room ] .
?room base:roomName ?roomName .
}