0

It sounds quite simple but I have not managed to find a nice solution yet. I'm looking to find the classes in my ontology which have exactly one subclass.

So far I have approached it as follows:

SELECT (COUNT(?anything) AS ?count) ?class
WHERE {
GRAPH <> {

    ?class rdf:type owl:Class.
    ?class rdfs:subClassOf ?anything.
    ?anything rdf:type owl:Class.
   
} group by ?class 

I should then theoretically be able to sort on count, and the results that have value 1 should have only have 1 subclass. However, when I execute this query, the counts do not correspond with what I expect at all e.g. my test case should return 1, which it does, but another class which doesn't have a subclass at all, also returns 1. And a class with 3 subclasses returns a count of 4.

in the image below, it should find that the highlighted classes have a count of 1. picture of class structure

Robin
  • 135
  • 10

1 Answers1

1

The SPARQL query you're looking for would be something like

SELECT ?class WHERE {
  ?sub rdfs:subClassOf ?class
}
GROUP BY ?class 
HAVING (COUNT(DISTINCT ?sub) = 1)

As UninformedUser mentioned in a comment, though, if there is OWL inference available, there can be lots of answers that you might not be expecting, such as

owl:Nothing rdfs:subClassOf ex:YourClass

and

ex:YourClass rdfs:subClassOf ex:YourClass

If those keep the query from producing the kind of results you're looking for, you should add a filter like

SELECT ?class WHERE {
  ?sub rdfs:subClassOf ?class
  FILTER ( ?sub != ?class && ?sub != owl:Nothing )
}
GROUP BY ?class 
HAVING (COUNT(DISTINCT ?sub) = 1)
Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
  • Thank you both! This helped immensly. I have now learned about "Having". I also did not know a class could be a subclass of itsself, so the filters are helpful. – Robin Feb 02 '21 at 07:22
  • Perhaps more telling and frustrating to me, the real problem was my declaration in the WHERE statement, if I had flipped this statement: ?class rdfs:subClassOf ?anything. I would have already gotten correct answers in my case, but it's good to know that this might not always be correct, hence the filters. – Robin Feb 02 '21 at 07:39
  • @robin yes, a class X is a sub class of Y when everything that has type X also has type Y. So, every class is a subclass of itself. Typically we won't assert that directly, but an OWL reasoner will recognize it. – Joshua Taylor Feb 02 '21 at 12:22