Retrieving superclasses implied by OWL intersection classes

前端 未结 1 1005
-上瘾入骨i
-上瘾入骨i 2021-01-06 12:44

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

A ⊑ (B ⊓ C)

or in approximate Manches

相关标签:
1条回答
  • 2021-01-06 13:05

    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> |
    --------------------------------------------------------------------------------------
    
    0 讨论(0)
提交回复
热议问题