Vitaly Isaev
Vitaly Isaev

Reputation: 5795

Calculate the depth of subclass in the OWL ontology

I'm looking for a SPARQL query that could return the position of specified subclass in the OWL hierarchy. I have studied several examples but the best result I could ever reach is the computation the relative paths between the specified superclass and its subclasses (thanks to Joshua Taylor). Instead of that I need to calculate the "absolute" depth for a given subclass.

My ontology contains several top-level classes and every of them is followed with a separate tree of subclasses. Here is part of my OWL (converted to TTL with a rdfcat utility):

@prefix :      <http://www.semanticweb.org/administrator/ontologies/2014/7/untitled-ontology-9#> .
@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#> .

:depression  a              owl:Class ;
    rdfs:subClassOf  :pit .

:pit    a                owl:Class ;
    rdfs:subClassOf  :on_the_road .

:on_the_road  a            owl:Class ;
    rdfs:subClassOf  :traffic_accident .

:traffic_accident  a  owl:Class .

In this case for a given depression class I expect to get 3, pit -> 2, on_the_road -> 1, traffc_accident (a top-level class) -> 0.

Upvotes: 3

Views: 1241

Answers (1)

Joshua Taylor
Joshua Taylor

Reputation: 85813

The same approach works here for finding the depth of a class in a hierarchy (assuming, of course, that each class has a unique path to a root). The trick is just that you first need to find the roots of the hierarchy. You can do that with the following query to get the following results.

prefix : <http://www.semanticweb.org/administrator/ontologies/2014/7/untitled-ontology-9#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>

select ?class (count(?mid)-1 as ?depth) {
  #-- Select root classes (classes that have no
  #-- superclasses other than themselves).
  {
    select ?root {
      ?root a owl:Class
      filter not exists {
        ?root rdfs:subClassOf ?superroot 
        filter ( ?root != ?superroot )
      }
    }
  }

  ?class rdfs:subClassOf* ?mid .
  ?mid rdfs:subClassOf* ?root .
}
group by ?class
order by ?depth
-----------------------------
| class             | depth |
=============================
| :traffic_accident | 0     |
| :on_the_road      | 1     |
| :pit              | 2     |
| :depression       | 3     |
-----------------------------

Note that things may be a bit more complicated if you've got a reasoner. If you've got a reasoner, then every class, including your roots, is a subclass of owl:Thing, so there will actually only be one root, and all the depths will be off by one (from what you've mentioned in the question). You can avoid that by adjusting the filters in the query that finds values for ?root.

Upvotes: 5

Related Questions