Arthur Vaïsse Arthur Vaïsse - 17 days ago 4
Java Question

How to Use the Jena OntModel.listClasses() method?

I'm trying to use the Jena OntModel to get the direct relations of an ontology.
Problems come from the listClasses() method.

I searched a while for tips on the net but don't find relevant answer to my problem.

So here comes a complete example with minimal data and code showing what's wrong.

I have a for example this basic ontology (N-Triple formated):



<http://weblab.ow2.org/wookie#Anti-social_behaviour> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://weblab.ow2.org/wookie#CriminalEvent>.
<http://weblab.ow2.org/wookie#Robbery> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://weblab.ow2.org/wookie#CriminalEvent>.
<http://weblab.ow2.org/wookie#Vehicle_crime> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://weblab.ow2.org/wookie#CriminalEvent>.
<http://weblab.ow2.org/wookie#Bicycle_theft> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://weblab.ow2.org/wookie#CriminalEvent>.
<http://weblab.ow2.org/wookie#CriminalEvent> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://weblab.ow2.org/wookie#Event>.
<http://weblab.ow2.org/wookie#Event> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://weblab.ow2.org/wookie#WookieThing>.
<http://weblab.ow2.org/wookie#Event> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class>.


I basically would like to be able to get the all the classes, and for each class, get subClasses.

I use the following JAVA code :

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.util.FileManager;

public class Main {

public static void main(final String [] argv) throws FileNotFoundException, IOException {

final OntModel model = ModelFactory.createOntologyModel();

model.read(FileManager.get().open("./src/test/resources/eventOnto.n3"), "", "N-TRIPLE");

// This part allows to check that the ontology model is really loaded and that inference is
// correctly done. WORKING
final List<Statement> statements = model.listStatements().toList();
Collections.sort(statements, new Comparator<Statement>() {
@Override
public int compare(final Statement o1, final Statement o2) {
return o1.toString().compareTo(o2.toString());
}
});

for (final Statement statement : statements) {
System.out.println(statement);
}

System.out.println("-------------------------------------------------");

// Listing all the classes.
final List<OntClass> classes = model.listClasses().toList();
for (final OntClass ontclass : classes) {
System.out.println(ontclass);
}

System.out.println("-------------------------------------------------");

// Bug got nothing. So try with a SPARQL query...
final Query query = QueryFactory.create("PREFIX rdf:<http://www.w3.org/2000/01/rdf-schema#> SELECT distinct ?class WHERE {?class a rdf:Class.}");
final ResultSet queryResult = QueryExecutionFactory.create(query, model).execSelect();
while (queryResult.hasNext()) {
System.out.println(queryResult.next());
}
// and got many results...

}


Prints show that the ontology model is correctly loaded and basic inference is done. It also show that the getClasses() don't return anything while the SPARQL query that ask for classes got every single class.

[http://weblab.ow2.org/wookie#Anti-social_behaviour, http://www.w3.org/1999/02/22-rdf-syntax-ns#type, http://www.w3.org/2000/01/rdf-schema#Class]
[http://weblab.ow2.org/wookie#Anti-social_behaviour, http://www.w3.org/1999/02/22-rdf-syntax-ns#type, http://www.w3.org/2000/01/rdf-schema#Resource]
[http://weblab.ow2.org/wookie#Anti-social_behaviour, http://www.w3.org/2000/01/rdf-schema#subClassOf, http://weblab.ow2.org/wookie#Anti-social_behaviour]
[http://weblab.ow2.org/wookie#Anti-social_behaviour, http://www.w3.org/2000/01/rdf-schema#subClassOf, http://weblab.ow2.org/wookie#CriminalEvent]
[http://weblab.ow2.org/wookie#Anti-social_behaviour, http://www.w3.org/2000/01/rdf-schema#subClassOf, http://weblab.ow2.org/wookie#Event]
[http://weblab.ow2.org/wookie#Anti-social_behaviour, http://www.w3.org/2000/01/rdf-schema#subClassOf, http://weblab.ow2.org/wookie#WookieThing]
[http://weblab.ow2.org/wookie#Anti-social_behaviour, http://www.w3.org/2000/01/rdf-schema#subClassOf, http://www.w3.org/2000/01/rdf-schema#Resource]
[http://weblab.ow2.org/wookie#Anti-social_behaviour, http://www.w3.org/2000/01/rdf-schema#subClassOf, http://www.w3.org/2002/07/owl#Thing]
...(many other lines)...
-------------------------------------------------
-------------------------------------------------
( ?class = rdf:Property )
( ?class = rdf:List )
( ?class = rdfs:Resource )
( ?class = rdfs:Class )
( ?class = rdf:Statement )
( ?class = rdfs:Literal )
( ?class = <http://weblab.ow2.org/wookie#Event> )
( ?class = rdf:XMLLiteral )
( ?class = owl:Thing )
( ?class = <http://weblab.ow2.org/wookie#WookieThing> )
( ?class = <http://weblab.ow2.org/wookie#CriminalEvent> )
( ?class = rdfs:Container )
( ?class = <http://weblab.ow2.org/wookie#Robbery> )
( ?class = <http://weblab.ow2.org/wookie#Bicycle_theft> )
( ?class = rdf:Seq )
( ?class = rdf:Alt )
( ?class = <http://weblab.ow2.org/wookie#Anti-social_behaviour> )
( ?class = <http://weblab.ow2.org/wookie#Vehicle_crime> )
( ?class = rdfs:ContainerMembershipProperty )
( ?class = rdf:Bag )
( ?class = rdfs:Datatype )


Do anyone know why the OntModel.getClasses() don't return anything ?

Answer

You get no results for two reasons.

  1. The default ontology profile is an OWL profile, so you're getting an OWL model use getOntologyModel without a particular OntModelSpec. Instead, you should probably be using an RDFS ontology model. That will make listClasses look for instances of rdfs:Class rather than owl:Class. That will still only get you one result, though, because you've only declared one thing to be an rdfs:Class.
  2. You've only declared one thing as an rdfs:Class, and the rest are supposed to be inferred to be rdfs:Classes based on the fact that they're subclasses of something else. That means that you need to use an inference model. In this case, you probably want an RDFS inference model, but because (some of) Jena's OWL reasoners include the RDFS rules, you might be able to use an OWL model too.

Here's code that loads your data into a few different types of models and shows the results of listClasses:

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFDataMgr;

import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;

public class ListClassesExample {
    public static void main(String[] args) throws IOException {
        String content = 
                "<http://weblab.ow2.org/wookie#Anti-social_behaviour> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://weblab.ow2.org/wookie#CriminalEvent>.\n" +
                "<http://weblab.ow2.org/wookie#Robbery> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://weblab.ow2.org/wookie#CriminalEvent>.\n" +
                "<http://weblab.ow2.org/wookie#Vehicle_crime> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://weblab.ow2.org/wookie#CriminalEvent>.\n" +
                "<http://weblab.ow2.org/wookie#Bicycle_theft> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://weblab.ow2.org/wookie#CriminalEvent>.\n" +
                "<http://weblab.ow2.org/wookie#CriminalEvent> <http://www.w3.org/2000/01/rdf-schema#subClassOf>  <http://weblab.ow2.org/wookie#Event>.\n" +
                "<http://weblab.ow2.org/wookie#Event> <http://www.w3.org/2000/01/rdf-schema#subClassOf>  <http://weblab.ow2.org/wookie#WookieThing>.\n" +
                "<http://weblab.ow2.org/wookie#Event> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class>.";

        final Model base = ModelFactory.createDefaultModel();
        try ( InputStream in = new ByteArrayInputStream( content.getBytes() )) { 
            RDFDataMgr.read( base, in, Lang.NTRIPLES );
        }

        System.out.println( "== OWL Classes (no inference) ==" );
        OntModel owlOntology = ModelFactory.createOntologyModel( OntModelSpec.OWL_MEM, base );
        for ( OntClass klass : owlOntology.listClasses().toList() ) {
            System.out.println( klass );
        }

        System.out.println( "== RDFS Classes (no inference) ==" );
        OntModel rdfsOntology = ModelFactory.createOntologyModel( OntModelSpec.RDFS_MEM, base );
        for ( OntClass klass : rdfsOntology.listClasses().toList() ) {
            System.out.println( klass );
        }

        System.out.println( "== RDFS Classes (with inference) ==" );
        OntModel rdfsOntologyInf = ModelFactory.createOntologyModel( OntModelSpec.RDFS_MEM_RDFS_INF, base );
        for ( OntClass klass : rdfsOntologyInf.listClasses().toList() ) {
            System.out.println( klass );
        }

        System.out.println( "== End ==");
    }
}
== OWL Classes (no inference) ==
== RDFS Classes (no inference) ==
http://weblab.ow2.org/wookie#Event
== RDFS Classes (with inference) ==
http://www.w3.org/1999/02/22-rdf-syntax-ns#Property
http://www.w3.org/1999/02/22-rdf-syntax-ns#List
http://www.w3.org/2000/01/rdf-schema#Resource
http://www.w3.org/2000/01/rdf-schema#Class
http://www.w3.org/1999/02/22-rdf-syntax-ns#Statement
http://www.w3.org/2000/01/rdf-schema#Literal
http://weblab.ow2.org/wookie#Event
http://weblab.ow2.org/wookie#WookieThing
http://weblab.ow2.org/wookie#CriminalEvent
http://www.w3.org/2000/01/rdf-schema#Container
http://weblab.ow2.org/wookie#Robbery
http://weblab.ow2.org/wookie#Bicycle_theft
http://www.w3.org/1999/02/22-rdf-syntax-ns#Seq
http://www.w3.org/1999/02/22-rdf-syntax-ns#Alt
http://weblab.ow2.org/wookie#Anti-social_behaviour
http://weblab.ow2.org/wookie#Vehicle_crime
http://www.w3.org/2000/01/rdf-schema#ContainerMembershipProperty
http://www.w3.org/1999/02/22-rdf-syntax-ns#Bag
http://www.w3.org/2000/01/rdf-schema#Datatype
http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral
== End ==

This has some classes that you didn't mention, because the RDFS axioms entail them. If you just want the things that are declared as rdfs:Classes in your data, and the subclasses of them, you could use a SPARQL query:

String query = "\n" +
        "prefix rdfs: <"+RDFS.getURI()+">\n" +
        "\n" +
        "select distinct ?class where {\n" +
        "  { ?class a rdfs:Class } union\n" +
        "  { ?class rdfs:subClassOf|^rdfs:subClassOf [] }\n" +
        "}";
ResultSet results = QueryExecutionFactory.create( query, base ).execSelect();
System.out.println( query );
ResultSetFormatter.out( results );
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>

select distinct ?class where {
  { ?class a rdfs:Class } union
  { ?class rdfs:subClassOf|^rdfs:subClassOf [] }
}
--------------------------------------------------------
| class                                                |
========================================================
| <http://weblab.ow2.org/wookie#Event>                 |
| <http://weblab.ow2.org/wookie#Bicycle_theft>         |
| <http://weblab.ow2.org/wookie#Anti-social_behaviour> |
| <http://weblab.ow2.org/wookie#WookieThing>           |
| <http://weblab.ow2.org/wookie#Vehicle_crime>         |
| <http://weblab.ow2.org/wookie#CriminalEvent>         |
| <http://weblab.ow2.org/wookie#Robbery>               |
--------------------------------------------------------