Removing unwanted superclass answers in SPARQL - sparql

I have an OWL file that includes a taxonomic hierarchy that I want to write a query where the answer includes each individual and its immediate taxonomic parent. Here's an example (the full query is rather messier).
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix rdf: <http:://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix : <urn:ex:> .
:fido rdf:type :Dog .
:Dog rdfs:subClassOf :Mammal .
:Mammal rdfs:subClassOf :Vertebrate .
:Vertebrate rdfs:subClassOf :Animal .
:fido :hasToy :bone
:kitty rdf:type :Cat .
:Cat rdfs:subClassOf :Mammal .
:kitty :hasToy :catnipMouse .
And this query does what I want.
prefix rdf: <http:://www.w3.org/1999/02/22-rdf-syntax-ns#> .
prefix : <urn:ex:> .
SELECT ?individual ?type
WHERE {
?individual :hasToy :bone .
?individual rdf:type ?type .
}
The problem is that I'd rather use a reasoned-over version of the OWL file, which unsurprisingly includes additional statements:
:fido rdf:type :Mammal .
:fido rdf:type :Vertebrate .
:fido rdf:type :Animal .
:kitty rdf:type :Mammal .
:kitty rdf:type :Vertebrate .
:kitty rdf:type :Animal .
And now the query results in additional answers about Fido being a Mammal, etc. I could just give up on using the reasoned version of the file, or, since the SPARQL queries are called from java, I could do a bunch of additional queries to find the least inclusive type that appears. My question is whether there is a reasonable pure SPARQL solution to only returning the Dog solution.

A generic solution is that you make sure you ask for the direct type only. A class C is the direct type of an instance X if:
X is of type C
there is no C' such that:
X is of type C'
C' is a subclass of C
C' is not equal to C
(that last condition is necessary, by the way, because in RDF/OWL, the subclass-relation is reflexive: every class is a subclass of itself)
In SPARQL, this becomes something like this:
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX : <urn:ex:> .
SELECT ?individual ?type
WHERE {
?individual :hasToy :bone .
?individual a ?type .
FILTER NOT EXISTS { ?individual a ?other .
?other rdfs:subClassOf ?type .
FILTER(?other != ?type)
}
}
Depending on which API/triplestore/library you use to execute these queries, there may also be other, tool-specific solutions. For example, the Sesame API (disclosure: I am on the Sesame dev team) has the option to disable reasoning for the purpose of a single query:
TupleQuery query = conn.prepareTupleQuery(SPARQL, "SELECT ...");
query.setIncludeInferred(false);
TupleQueryResult result = query.evaluate();
Sesame also offers an optional additional inferencer (called the 'direct type inferencer') which introduces additional 'virtual' properties you can query, such as sesame:directType, sesame:directSubClassOf, etc. Other tools will undoubtedly have similar options.

Related

Infer data with SPARQL in Protege

I'm trying to get my head around inferring RDF data. Say that I have these triples (RDF Turtle), which I created using Protege:
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
:hasSpouse rdf:type owl:ObjectProperty ,
owl:SymmetricProperty ;
rdfs:domain :People ;
rdfs:range :People .
:People rdf:type owl:Class .
:Jane_Doe rdf:type owl:NamedIndividual ,
:People .
:John_Doe rdf:type owl:NamedIndividual ,
:People ;
:hasSpouse :Jane_Doe .
The reasoner in Protege will kindly highlight the expected inference, that is :Jane_Doe :hasSpouse :John_Doe.
How can I see that inference with SPARQL? If I run this query in Protege (SPARQL tab):
SELECT ?subject
WHERE {?subject hasSpouse ?object .}
It shows the asserted triple, not the inferred one. I understand how to do it manually, e.g. :
CONSTRUCT {?object ?prop ?subject }
WHERE { ?prop rdf:type owl:SymmetricProperty .
?subject ?prop ?object .}
I'd see now the inferred data I'm expecting but 1) that would be losing the point imho (i.e; reinventing the wheel) 2) I cannot have 2 queries in this tab (construct, then select). There's got to be a way to do this automatically, just like the reasoner did.
I read in Stack Overflow a post saying to use 'Snap SPARQL' plugin in Protege. I tried but simple queries don't work (like the first one above). It's like it's a different language. How does it work?
So, how can I get the benefit of these owl properties with SPARQL? How can I have an OWL-aware SPARQL in Protege? Am I taking this the wrong way? What's the right way?
thanks for your help.
Nicolas
You need to make your inferences a part of your knowledge.
To do so, go to the SWRL Tab and click successively on the button
at the bottom of that Tab, start from the left to the right.

How to create a Class as equivalent of a Class with defined type of RDF Statements?

I have three classes, let's call them :A, :B and :C and a property :p.
Every statement X: :p :Y should become a member of :A, when :X a :B and :Y a :C
Currently I'd prefer a solution with OWL, but could be also with SPARQL and/or SHACL.
Your question is rather ambiguous and quite impossible to parse without intuitive assumptions about what you are trying to express. This may be either due to your choice of being informal in order to avoid complicated precision, or a confusion about the meaning of the RDF and OWL concepts.
The way I interpreted at first the sentence:
Every statement X: :p :Y should become a member of :A
was that:
Every RDF triple of the form ?x :p ?y (where ?x and ?y are any subject and object respectively) can be inferred as a member of class :A.
It is easy to answer the question in this case: it cannot be expressed in any of RDF, RDFS, OWL, SWRL, RIF, SPARQL, SPIN, SHACL. The reason is that it is never possible to constrain any class to contain RDF triples in any of these formalisms and languages. To do so, it would be necessary to have RDF triples as first class citizens in the language.
The confusion, if there is, could be that the class rdf:Statement is often incorrectly considered to be the class of RDF triples. rdf:Statement, although being described as a way to express statements about statements, is not constrained in any way to contain RDF triples, no matter how you write your data, ontology, query, shape, rule, etc. The class rdf:Statement is just, formally, an arbitrary class of resources.
However, looking at the comments and answers, it may very well be possible that my interpretation of your use of "statement" and "become a member" is inappropriate for what you are trying to achieve.
Obvious SPARQL solution for free-standing triples:
PREFIX : <http://example.com/ontology#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
CONSTRUCT {
[] a :A, rdf:Statement ;
rdf:subject ?X ;
rdf:predicate :p ;
rdf:object ?Y
}
WHERE {
?X a :B .
?X :p ?Y .
?Y a :C .
}
With Jena rules, you could probably use makeSkolem(...).
Revised... this might not meet your needs, because it's making an inference about an rdf:Statement, not a free-standing triple. I can't figure how to do this without reificiation. Maybe something with named graphs, although that's generally not compatible with OWL implementations. Maybe you'd like Blazegraph's "Reification Done Right"
Also, maybe you already know how to do this.
It is asserted that lemonTest is an rdf:Statement. With Hermit reasoning on, it is inferred that lemonTest is a flavorStatement.
#prefix : <http://example.com/ontology#> .
#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#> .
#base <http://www.w3.org/2002/07/owl#> .
[ rdf:type owl:Ontology ;
owl:imports rdf: ,
rdfs:
] .
:flavor rdf:type owl:ObjectProperty .
:flavorStatement rdf:type owl:Class ;
owl:equivalentClass [ rdf:type owl:Restriction ;
owl:onProperty rdf:object ;
owl:someValuesFrom :flavor
] ,
[ rdf:type owl:Restriction ;
owl:onProperty rdf:subject ;
owl:someValuesFrom :fruit
] ;
rdfs:subClassOf rdf:Statement .
:fruit rdf:type owl:Class .
:lemon a :fruit .
:lemonTest rdf:type owl:NamedIndividual ,
rdf:Statement ;
rdf:object :flavor ;
rdf:predicate :result ;
rdf:subject :lemon .
:sour a :flavor .
First attempt:
I'm not an OWL expert either, but the Hermit reasoner in Protégé doesn’t complain about this:
#prefix : <http://example.com/ontology#> .
#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#> .
:root a owl:Class .
:A a rdf:Statement ;
rdf:subject :X ;
rdf:predicate :p ;
rdf:object :Y ;
rdfs:subClassOf :root .
:B rdfs:subClassOf :root .
:C rdfs:subClassOf :root .
:X a :B .
:p a owl:ObjectProperty .
:Y a :C .

OWL reasoning: Necessary and sufficient conditions for inferring a property

We are trying to get a reasoner (e.g. HermiT in Protege) to infer that a more specific sub-property can be used instead of the asserted general property.
Classes:
- Patient
- Finding
- Dyspnea
- ObservationStatus
- Inclusion
- Exclusion
Properties:
- has_finding (domain: Patient, range: Finding)
- has_positive_finding (domain: Patient, range: Finding, Inclusion)
- has_negative_finding (domain: Patient, range: Finding, Exclusion)
If we assert the following triples:
:Patient1 a :Patient .
:Patient1 :has_negative_finding :Dyspnea1 .
A reasoner can infer (among other things) that:
:Dyspnea1 a :Finding .
:Dyspnea1 a :Exclusion.
But when we look at it the other way around and assert:
:Patient1 a :Patient .
:Dyspnea1 a :Dyspnea .
:Dyspnea1 a :Exclusion .
:Patient1 :has_finding :Dyspnea1.
We would like the reasoner to infer that:
:Patient1 :has_negative_finding :Dyspnea1 .
We cannot seem to get Protege and HermiT to draw that conclusion and infer the triples.
What are we missing? Are the conditions not necessary and sufficient for it to infer that knowledge?
:Patient1 a :Patient .
:Dyspnea1 a :Dyspnea .
:Dyspnea1 a :Exclusion .
:Patient1 :has_finding :Dyspnea1.
We would like the reasoner to infer that:
:Patient1 :has_negative_finding :Dyspnea1 .
… What are we missing? Are the conditions not necessary and sufficient
for it to infer that knowledge?
There are a few issues here.
First, you haven't said that every has_finding actually corresponds to one of the subproperties. That is, just because something has as finding, you don't know that it also has a negative or a positive finding. The finding could just be a general finding, without being one of the more specific ones.
Second, the more specific type of the object doesn't mean that you have to use the more specific property.
Third, even if you state that the finding is an exclusion, if you don't know that exclusions are disjoint from inclusions, you could still have the finding be both a positive and negative finding.
Now, what it'd be really nice to do would be to state that has_finding is the union of has_negative_finding and has_positive_finding, and then declare inclusion and exclusion disjoint. Then every instance of a finding would have to be one or the other, and you could make your inference.
Since you can't do that, you'll need some sort of alternative. If you're using individuals as per-person diagnoses, then you could say that every finding is either a negative finding or a positive finding with an axiom like
(inverse(hasFinding) some Patient) subClass ((inverse(hasNegativeFinding) some Patient) or (inverse(hasPositiveFinding) some Patient))
along with making hasFinding inverse functional, so that each finding is associated with at most one patient. Then you'd have an ontology like this:
#prefix : <http://stackoverflow.com/a/30903552/1281433/> .
#prefix a: <http://stackoverflow.com/a/30903552/1281433/> .
#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#> .
a:Exclusion a owl:Class ;
rdfs:subClassOf a:Finding .
a:hasNegativeFinding a owl:ObjectProperty ;
rdfs:range a:Exclusion ;
rdfs:subPropertyOf a:hasFinding .
_:b0 a owl:Restriction ;
owl:onProperty a:hasPositiveFinding ;
owl:someValuesFrom a:Inclusion .
a: a owl:Ontology .
[ a owl:Restriction ;
rdfs:subClassOf [ a owl:Class ;
owl:unionOf ( _:b1 _:b0 )
] ;
owl:onProperty a:hasFinding ;
owl:someValuesFrom a:Finding
] .
a:Finding a owl:Class ;
owl:disjointUnionOf ( a:Finding a:Inclusion ) .
a:patient1 a owl:Thing , owl:NamedIndividual ;
a:hasFinding a:dyspnea1 .
_:b1 a owl:Restriction ;
owl:onProperty a:hasNegativeFinding ;
owl:someValuesFrom a:Exclusion .
a:hasFinding a owl:ObjectProperty .
a:Inclusion a owl:Class ;
rdfs:subClassOf a:Finding .
a:hasPositiveFinding a owl:ObjectProperty ;
rdfs:range a:Inclusion ;
rdfs:subPropertyOf a:hasFinding .
a:dyspnea1 a owl:NamedIndividual , a:Exclusion .
and you can get results like this:

SPARQL query and reasoning to get similar indviduals from two different ontologies

The first ontology has the following:
Issue Ontology members(classes):
<http://www.issueonto.com/ontologies/issues#issues>
<http://www.issueonto.com/ontologies/issues#products>
Predicate/Properties:
<http://www.issueonto.com/ontologies/issues#hasIssues>
Triple store for this ontology (raw data), I show it here in Turtle format:
#prefix : <http://www.issueonto.com/ontologies/issues#> .
#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.issueonto.com/ontologies/issues> .
:Fido rdf:type :products ,
owl:NamedIndividual ;
:productName "FidoProdCEO_12"^^xsd:string ;
:hasIssues :issue_1239 .
### http://www.issueonto.com/ontologies/issues#issue_1239
:issue_1239 rdf:type :issues ,
owl:NamedIndividual ;
:issueName "FeatureIssue"^^xsd:string .
The Second ontology has the following:
Project Ontology members (classes):
<http://www.projectexample.com/ontology/project#GroupProject>
<http://www.projectexample.com/ontology/project#Project>
<http://www.projectexample.com/ontology/project#ProjectVersion>
Predicate/Properties:
<http://www.projectexample.com/ontology/project#belongsTo>
<http://www.projectexample.com/ontology/project#dependsOn>
Triple store for the ontology (raw data), I show it here in Turtle format:
#prefix : <http://www.projectexample.com/ontology/project#> .
#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.projectexample.com/ontology/project> .
### http://www.projectexample.com/ontology/project#Apple
:Apple rdf:type :ProjectVersion ,
owl:NamedIndividual ;
:hasProjectName "AppleTowandOne"^^xsd:string ;
:belongsTo :RedBlueCompany .
### http://www.projectexample.com/ontology/project#Fido
:Fido rdf:type :ProjectVersion ,
owl:NamedIndividual ;
:hasProjectName "FidoProdCEO"^^xsd:string ;
:dependsOn :Apple .
### http://www.projectexample.com/ontology/project#RedBlueCompany
:RedBlueCompany rdf:type :GroupProject ,
owl:NamedIndividual ;
:groupName "RedGroupCompant lmt"^^xsd:string .
Question
1- I would like to say, project:projectversion from ontology project same as issues:product from ontology issues, is that possible and how?
2- if question (1) is yes, how could I infer the similar individuals from the shared concepts, i.e, if we say projectversion is same as product it does not mean all the individuals are similar, in the example, i would like to automatically infer the individual issues:Fido type of issue:products is same as the individual prject:Fido type of project:projectversion. From that inferred fact, i would infer automatically that project:Fido issue:hasissue issues:issues_1239. Finally, I would like to run SPARQL query as follow:
SELECT ?product ?issue FROM <namegraph>
WHERE{
?product issues:hasIssues ?issue.
}
The results that I should get as follow:
?product ?issue
--------------------------------------------------------------------------
<http://www.projectexample.com/ontology/project#Fido> <http://www.issueonto.com/ontologies/issues#issue_1239>
<http://www.issueonto.com/ontologies/issues#Fido> <http://www.issueonto.com/ontologies/issues#issue_1239>
I would like to say, project:projectversion from ontology project same
as issues:product from ontology issues, is that possible and how?
All you need is the triple
project:projectversion owl:equivalentClass issues:product
I don't know how you're combining these ontologies; whether you're just loading the data from both into a triple store, or creating a third ontology that imports both and loading that (along with its imports) into a triple store, but somewhere you need that axiom. For a "merging" ontology like this, I'd usually create a third ontology that imports both (but leaving them unchanged) and add the axiom to that third ontology.
2- if question (1) is yes, how could I infer the similar individuals
from the shared concepts, i.e, if we say projectversion is same as
product it does not mean all the individuals are similar, in the
example, i would like to automatically infer the individual
issues:Fido type of issue:products is same as the individual
prject:Fido type of project:projectversion. From that inferred fact, i
would infer automatically that project:Fido issue:hasissue
issues:issues_1239.
You still have told us what criteria you would use to decide that issues:Fido and project:Fido are the same individual. The only apparent similarity that they have is the strings "FidoProdCEO_12" and "FidoProdCEO". Is that what the decision is supposed to be based on? If so, then you could do something like the following. I've created a minimal amount of data for convenience:
#prefix o1: <urn:ex:ont1#> .
#prefix o2: <urn:ex:ont2#> .
#prefix owl: <http://www.w3.org/2002/07/owl#> .
o1:A a o1:Product ;
o1:productName "ProductA_1234" ;
o1:hasIssue o1:issue42 .
o2:B a o2:ProjectVersion ;
o2:projectName "ProductA" .
o1:Product owl:equivalentClass o2:ProjectVersion .
prefix o1: <urn:ex:ont1#>
prefix o2: <urn:ex:ont2#>
prefix owl: <http://www.w3.org/2002/07/owl#>
select ?product ?issue where {
#-- A *product* is something that's an instance of
#-- o1:Product or another class that's equivalent
#-- to it.
?product a/(owl:equivalentClass|^owl:equivalentClass)* o1:Product
#-- The issues of a product are any of its
#-- o1:hasIssue values, or the o1:hasIssue
#-- value of any product that has a name
#-- beginning with its o2:projectName.
{ ?product o1:hasIssue ?issue }
union
{ ?product o2:projectName ?projectName .
?_product o1:productName ?productName ;
o1:hasIssue ?issue .
filter strstarts(?productName,?projectName)
}
}
------------------------
| product | issue |
========================
| o2:B | o1:issue42 |
| o1:A | o1:issue42 |
------------------------
Of course, the fact that you still end up having to examine projectName and productName values means that the equivalent class axiom isn't actually buying you all that much (at least in terms of this query). That is, it would be sufficient to just ask for "products (and projects with matching names) and their issues." That is, you get the same results from this query, which is just the second part of the first query:
prefix o1: <urn:ex:ont1#>
prefix o2: <urn:ex:ont2#>
prefix owl: <http://www.w3.org/2002/07/owl#>
select ?product ?issue where {
{ ?product o1:hasIssue ?issue }
union
{ ?product o2:projectName ?projectName .
?_product o1:productName ?productName ;
o1:hasIssue ?issue .
filter strstarts(?productName,?projectName)
}
}
The solution here is an owl:equivalentClass relation. To make this work you have to perform the following tasks:
Create and RDF document into which you place the owl:equivalentClass relation -- alternatively you can use SPARQL 1.1 INSERT to place the relation into a Virtuoso hosted Named Graph
Create an Inference Rule that functions as a Context-Lense when viewing the data in Virtuoso -- be it via SPARQL Query Results of an Entity Description Page etc.
Command (issued via SQL CommandLine of Conductor UI) for associating a Named Graph with an Inference Rule:
RDFS_RULE_SET ('{rule-name}', '{named-graph-uri-or-rdf-document-url}');
Links:
Sample file (note SQL part is commented out re., Rules and Named Graph association)
Live Example -- showcasing owl:equivalentClass reasoning via Schema.org, FOAF, and GoodRelations ontologies.

Extracting hierarchy for dbpedia entity using SPARQL

I am trying to extract the hierarchy of Wikipedia category or Yago classification for DBpedia resources using the SPARQL endpoint. For instance, I would like to find out all the possible categories and classes in hierarchical form of entity, say, http://dbpedia.org/resource/Nokia, like Thing → Organization → Company → … → Nokia.
A simple SPARQL select can retrieve the information that you're interested in, though it won't be arranged hierarchically. You're interested in getting all the types of a resource, as well as the rdfs:subClassOf relations between them. Here's a very simple query for Nokia that can be run on the DBpedia SPARQL endpoint
SELECT * WHERE {
dbpedia:Nokia a ?c1 ; a ?c2 .
?c1 rdfs:subClassOf ?c2 .
}
SPARQL results
If you treat each pair of classes in that result set as a directed edge and perform a topological sort , then you'll see the hierarchy of the classes to which the Nokia resource belongs. In fact, since it is probably convenient to treat this as a graph, you can get it in the form of an RDF graph by using a SPARQL construct query.
CONSTRUCT WHERE {
dbpedia:Nokia a ?c1 ; a ?c2 .
?c1 rdfs:subClassOf ?c2 .
}
SPARQL results
The construct query produces this graph (in N3 format):
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#prefix dbpedia-owl: <http://dbpedia.org/ontology/> .
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix yago: <http://dbpedia.org/class/yago/> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix dbpedia: <http://dbpedia.org/resource/> .
dbpedia-owl:Agent rdfs:subClassOf owl:Thing .
dbpedia-owl:Company rdfs:subClassOf dbpedia-owl:Organisation .
dbpedia-owl:Organisation rdfs:subClassOf dbpedia-owl:Agent .
yago:CompaniesBasedInEspoo rdfs:subClassOf yago:Company108058098 .
dbpedia:Nokia rdf:type yago:CompaniesListedOnTheHelsinkiStockExchange ,
owl:Thing ,
yago:CompaniesBasedInEspoo ,
dbpedia-owl:Agent ,
yago:DisplayTechnologyCompanies ,
yago:ElectronicsCompaniesOfFinland ,
dbpedia-owl:Company ,
dbpedia-owl:Organisation ,
yago:Company108058098 ,
yago:CompaniesEstablishedIn1865 .
yago:CompaniesEstablishedIn1865 rdfs:subClassOf yago:Company108058098 .
yago:CompaniesListedOnTheHelsinkiStockExchange rdfs:subClassOf yago:Company108058098 .
yago:DisplayTechnologyCompanies rdfs:subClassOf yago:Company108058098 .
yago:ElectronicsCompaniesOfFinland rdfs:subClassOf yago:Company108058098 .
Remarks
The queries above retrieve the rdf:type hierarchy for Nokia. In the question, you also mention Wikipedia categories. DBpedia resources are associated with the Wikipedia categories to which their corresponding articles belong by the dcterms:subject property. Those Wikipedia categories are then structured hierarchically by skos:broader. These really are not types for the individuals though. For instance, the data contain:
dbpedia:Nokia dcterms:subject category:Finnish_brands
category:Finnish_brands skos:broader category:Brands_by_country
While it probably makes sense to say that Nokia is a Finnish_brand, it makes much less sense to say that Nokia is a Brand_by_country.