Retrieving superclasses implied by OWL intersectio

2019-02-15 09:25发布

An OWL ontology may have classes A, B, and C, and axiom (in DL notation):

A ⊑ (B ⊓ C)

or in approximate Manchester OWL Syntax:

A subClassOf (B and C)

It is logically true that A is a subclass of B, and that A is a subclass of C, but the triples

A rdfs:subClassOf B
A rdfs:subClassOf C

are not necessarily present in the RDF serialization of the OWL ontology. For instance, consider this very simple ontology in Protégé and its RDF serialization in RDF/XML and Turtle:

enter image description here

<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns="http://stackoverflow.com/q/19924861/1281433/sample.owl#"
    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://stackoverflow.com/q/19924861/1281433/sample.owl"/>
  <owl:Class rdf:about="http://stackoverflow.com/q/19924861/1281433/sample.owl#C"/>
  <owl:Class rdf:about="http://stackoverflow.com/q/19924861/1281433/sample.owl#B"/>
  <owl:Class rdf:about="http://stackoverflow.com/q/19924861/1281433/sample.owl#A">
    <rdfs:subClassOf>
      <owl:Class>
        <owl:intersectionOf rdf:parseType="Collection">
          <owl:Class rdf:about="http://stackoverflow.com/q/19924861/1281433/sample.owl#B"/>
          <owl:Class rdf:about="http://stackoverflow.com/q/19924861/1281433/sample.owl#C"/>
        </owl:intersectionOf>
      </owl:Class>
    </rdfs:subClassOf>
  </owl:Class>
</rdf:RDF>
@prefix :      <http://stackoverflow.com/q/19924861/1281433/sample.owl#> .
@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://stackoverflow.com/q/19924861/1281433/sample.owl>
        a       owl:Ontology .

:B      a       owl:Class .

:C      a       owl:Class .

:A      a                owl:Class ;
        rdfs:subClassOf  [ a                   owl:Class ;
                           owl:intersectionOf  ( :B :C )
                         ] .

The serialization has a triple with rdfs:subClassOf, but the object isn't :B or :C, so a query like

:A rdfs:subClassOf ?superclass

won't return the superclasses of :A. How can I write a SPARQL query that will return those superclasses of :A?

1条回答
霸刀☆藐视天下
2楼-- · 2019-02-15 09:59

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

StudentPersonenrolledIn some Course

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

Definition of student in Protege

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 ⊑ (Y and Z) then XY and XZ, 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> |
--------------------------------------------------------------------------------------
查看更多
登录 后发表回答