Retrieving superclasses implied by OWL intersection classes

怎甘沉沦 提交于 2019-11-30 23:23:51
Joshua Taylor

It sounds like you've got a class that is a subclass of some intersection class. E.g., you might have

Student ⊑ Person ⊓ enrolledIn some Course

In the Protégé OWL ontology editor, this would look like:

If you write a SPARQL query for subclasses, e.g.,

prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>

select ?subclass ?superclass where { 
  ?subclass rdfs:subClassOf ?superclass
}

and you don't have a reasoner inferring additional data, you won't see Student as a subclass in your results, but you might see an blank (anonymous) node:

---------------------------------------------------------
| subclass                                 | superclass |
=========================================================
| <http://www.examples.org/school#Student> | _:b0       |
---------------------------------------------------------

To understand why this is the case, you need to take a look at the RDF serialization of the ontology. In this case, it's (in RDF/XML):

<rdf:RDF
    xmlns="http://www.examples.org/school#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
  <owl:Ontology rdf:about="http://www.examples.org/school"/>
  <owl:Class rdf:about="http://www.examples.org/school#Course"/>
  <owl:Class rdf:about="http://www.examples.org/school#Person"/>
  <owl:Class rdf:about="http://www.examples.org/school#Student">
    <rdfs:subClassOf>
      <owl:Class>
        <owl:intersectionOf rdf:parseType="Collection">
          <owl:Class rdf:about="http://www.examples.org/school#Person"/>
          <owl:Restriction>
            <owl:onProperty>
              <owl:ObjectProperty rdf:about="http://www.examples.org/school#enrolledIn"/>
            </owl:onProperty>
            <owl:someValuesFrom rdf:resource="http://www.examples.org/school#Course"/>
          </owl:Restriction>
        </owl:intersectionOf>
      </owl:Class>
    </rdfs:subClassOf>
  </owl:Class>
</rdf:RDF>

Or in the more human-readable Turtle (which is also more like the SPARQL query syntax):

@prefix :      <http://www.examples.org/school#> .
@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#> .

:Student  a              owl:Class ;
        rdfs:subClassOf  [ a                   owl:Class ;
                           owl:intersectionOf  ( :Person [ a                   owl:Restriction ;
                                                           owl:onProperty      :enrolledIn ;
                                                           owl:someValuesFrom  :Course
                                                         ] )
                         ] .

:Person  a      owl:Class .

:enrolledIn  a  owl:ObjectProperty .

:Course  a      owl:Class .

<http://www.examples.org/school>
        a       owl:Ontology .

There is, in fact, a Student rdfs:subClassOf [ ... ] triple in the data, but the [ ... ] is a blank node; it's an anonymous owl:Class that is the intersection of some other classes. A reasoner would be able to tell you that if X &sqsubseteq; (Y and Z) then X &sqsubseteq; Y and X &sqsubseteq; Z, but a SPARQL query on its own won't do that. You could make a more complex SPARQL query like this that would, though:

prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#>
prefix owl:   <http://www.w3.org/2002/07/owl#>
prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

select ?subclass ?superclass where {
  { ?subclass rdfs:subClassOf ?superclass }
  union
  { ?subclass rdfs:subClassOf [ owl:intersectionOf [ rdf:rest* [ rdf:first ?superclass ] ] ] }
}
--------------------------------------------------------------------------------------
| subclass                                 | superclass                              |
======================================================================================
| <http://www.examples.org/school#Student> | _:b0                                    |
| <http://www.examples.org/school#Student> | <http://www.examples.org/school#Person> |
| <http://www.examples.org/school#Student> | _:b1                                    |
--------------------------------------------------------------------------------------

The two blank nodes are the anonymous intersection class, and the anonymous restriction class (enrolledIn some Course). If you only want IRI results, you can use a filter:

prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#>
prefix owl:   <http://www.w3.org/2002/07/owl#>
prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

select ?subclass ?superclass where {
  { ?subclass rdfs:subClassOf ?superclass }
  union
  { ?subclass rdfs:subClassOf [ owl:intersectionOf [ rdf:rest* [ rdf:first ?superclass ] ] ] }

  filter( isIRI( ?superclass ) )
}
--------------------------------------------------------------------------------------
| subclass                                 | superclass                              |
======================================================================================
| <http://www.examples.org/school#Student> | <http://www.examples.org/school#Person> |
--------------------------------------------------------------------------------------

Now, as final touch, if you want to make your query a bit smaller, since the only difference in those two unioned patterns is the path that connects ?subclass and ?superclass, you can actually write this with just one property path. (Although, as noted in Sparql query Subclass or EquivalentTo, you might run into some issues with Protégé if you do this.) The idea is that you can rewrite this:

{ ?subclass rdfs:subClassOf ?superclass }
union
{ ?subclass rdfs:subClassOf [ owl:intersectionOf [ rdf:rest* [ rdf:first ?superclass ] ] ] }

as this, by using property paths, which also removes the need for the blank nodes:

?subclass ( rdfs:subClassOf |
            ( rdfs:subClassOf / owl:intersectionOf / rdf:rest* / rdf:first ) ) ?superclass

and you can simplify that a bit more to

?subclass rdfs:subClassOf/((owl:intersectionOf/rdf:rest*/rdf:first)+) ?superclass

and you can even remove one level of parentheses from that, to make it

?subclass rdfs:subClassOf/(owl:intersectionOf/rdf:rest*/rdf:first)+ ?superclass

but then you'd have to start remembering the precedence rules, and that's not much fun. The query works though:

prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#>
prefix owl:   <http://www.w3.org/2002/07/owl#>
prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

select ?subclass ?superclass where {
  ?subclass rdfs:subClassOf/(owl:intersectionOf/rdf:rest*/rdf:first)+ ?superclass
  filter( isIRI( ?superclass ) )
}
--------------------------------------------------------------------------------------
| subclass                                 | superclass                              |
======================================================================================
| <http://www.examples.org/school#Student> | <http://www.examples.org/school#Person> |
--------------------------------------------------------------------------------------
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!