javardfjenareasoningjena-rules

Problems with inference examples from Apache Jena framework


I have a serious problem to get any reasoner up and running. Also the examples from the documentation: https://jena.apache.org/documentation/inference/ does not work here. I transferred the example into a unit test, so that the problem might be easier reproduced.

Is reasoning limited to certain environment like a spatial JDK or so on, or am i getting something wrong?

Thanks

Here the example code (as java unit test):

import static org.junit.Assert.assertNotNull;
import java.io.PrintWriter;
import java.util.Iterator;

import org.junit.Before;
import org.junit.Test;

import com.hp.hpl.jena.rdf.model.InfModel;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.reasoner.Derivation;
import com.hp.hpl.jena.reasoner.rulesys.GenericRuleReasoner;
import com.hp.hpl.jena.reasoner.rulesys.Rule;
import com.hp.hpl.jena.vocabulary.RDFS;

public class ReasonerTest {

    String NS = "urn:x-hp-jena:eg/";

    // Build a trivial example data set
    Model model = ModelFactory.createDefaultModel();
    InfModel inf;

    Resource A = model.createResource(NS + "A");
    Resource B = model.createResource(NS + "B");
    Resource C = model.createResource(NS + "C");
    Resource D = model.createResource(NS + "D");

    Property p = model.createProperty(NS, "p");
    Property q = model.createProperty(NS, "q");


    @Before
    public void init() {

        // Some small examples (subProperty)
        model.add(p, RDFS.subPropertyOf, q);
        model.createResource(NS + "A").addProperty(p, "foo");

        String rules = "[rule1: (?a eg:p ?b) (?b eg:p ?c) -> (?a eg:p ?c)]";
        GenericRuleReasoner reasoner = new GenericRuleReasoner(Rule.parseRules(rules));
        reasoner.setDerivationLogging(true);
        inf = ModelFactory.createInfModel(reasoner, model);

        // Derivations
        A.addProperty(p, B);
        B.addProperty(p, C);
        C.addProperty(p, D);
    }


    @Test
    public void subProperty() {
        Statement statement =  A.getProperty(q);
        System.out.println("Statement: " + statement);
        assertNotNull(statement);
    }


    @Test
    public void derivations() {
        String trace = null;
        PrintWriter out = new PrintWriter(System.out);
        for (StmtIterator i = inf.listStatements(A, p, D); i.hasNext(); ) {
            Statement s = i.nextStatement();
            System.out.println("Statement is " + s);
            for (Iterator id = inf.getDerivation(s); id.hasNext(); ) {
                Derivation deriv = (Derivation) id.next();
                deriv.printTrace(out, true);
                trace += deriv.toString();
            }
        }
        out.flush();
        assertNotNull(trace);
    }

    @Test
    public void listStatements() {
        StmtIterator stmtIterator = inf.listStatements();
        while(stmtIterator.hasNext()) {
            System.out.println(stmtIterator.nextStatement());
        }
    }
}

Solution

  • The prefix eg: isn't what you think it is:

    The eg: prefix in the rules doesn't expand to what you think it does. I modified your rules string to

    String rules = "[rule1: (?a eg:p ?b) (?b eg:p ?c) -> (?a eg:p ?c)] [rule2: -> (<urn:ex:a> eg:foo <urn:ex:b>)]";
    

    so that rule2 will always insert the triple urn:ex:a eg:foo urn:ex:b into the graph. Then, the output from your tests includes:

    [urn:ex:a, urn:x-hp:eg/foo, urn:ex:b]
    [urn:x-hp-jena:eg/C, urn:x-hp-jena:eg/p, urn:x-hp-jena:eg/D]
    

    The first line shows the triple that my rule2 inserted, whereas the second uses the prefix you entered by hand. We see that the eg: prefix is short for urn:x-hp:eg/. If you change your NS string accordingly, with String NS = "urn:x-hp:eg/";, then your derivations test will pass.

    You need to ask the right model

    The subProperty test fails for two reasons. First, it's checking in the wrong model.

    You're checking with A.getProperty(q):

    Statement statement =  A.getProperty(q);
    System.out.println("Statement: " + statement);
    assertNotNull(statement);
    

    A is a resource that you created for the the model model, not the model inf, so when you ask for A.getProperty(q), it's actually asking model for the statement, so you won't see the inferences in inf. You can use inModel to get A "in inf" so that getProperty looks in the right model:

    Statement statement = A.inModel(inf).getProperty(q);
    

    Alternatively, you could also ask inf directly whether it contains a triple of the form A q <something>:

    inf.contains( A, q, (RDFNode) null );
    

    Or you could enumerate all such statements:

    StmtIterator stmts = inf.listStatements( A, q, (RDFNode) null );
    assertTrue( stmts.hasNext() );
    while ( stmts.hasNext() ) { 
      System.out.println( "Statement: "+stmts.next() );
    }
    

    You need RDFS reasoning too

    Even if you're querying the right model, your inference model still needs to do RDFS reasoning as well as your custom rule that makes the property p transitive. To do that, we can pull the rules out from an RDFS reasoner, add your rule to that a copy of that list, and then create a custom reasoner with the new list of rules:

    // Get an RDFS reasoner
    GenericRuleReasoner rdfsReasoner = (GenericRuleReasoner) ReasonerRegistry.getRDFSReasoner();
    // Steal its rules, and add one of our own, and create a
    // reasoner with these rules
    List<Rule> customRules = new ArrayList<>( rdfsReasoner.getRules() );
    String customRule = "[rule1: (?a eg:p ?b) (?b eg:p ?c) -> (?a eg:p ?c)]";
    customRules.add( Rule.parseRule( customRule ));
    Reasoner reasoner = new GenericRuleReasoner( customRules );
    

    The complete result

    Here's the modified code, all together for easy copying and pasting. All the tests pass.

    import static org.junit.Assert.assertNotNull;
    import static org.junit.Assert.assertTrue;
    
    import java.io.PrintWriter;
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    import org.junit.Before;
    import org.junit.Test;
    
    import com.hp.hpl.jena.rdf.model.InfModel;
    import com.hp.hpl.jena.rdf.model.Model;
    import com.hp.hpl.jena.rdf.model.ModelFactory;
    import com.hp.hpl.jena.rdf.model.Property;
    import com.hp.hpl.jena.rdf.model.RDFNode;
    import com.hp.hpl.jena.rdf.model.Resource;
    import com.hp.hpl.jena.rdf.model.Statement;
    import com.hp.hpl.jena.rdf.model.StmtIterator;
    import com.hp.hpl.jena.reasoner.Derivation;
    import com.hp.hpl.jena.reasoner.Reasoner;
    import com.hp.hpl.jena.reasoner.ReasonerRegistry;
    import com.hp.hpl.jena.reasoner.rulesys.GenericRuleReasoner;
    import com.hp.hpl.jena.reasoner.rulesys.Rule;
    import com.hp.hpl.jena.vocabulary.RDFS;
    
    public class ReasonerTest {
    
        String NS = "urn:x-hp:eg/";
    
        // Build a trivial example data set
        Model model = ModelFactory.createDefaultModel();
        InfModel inf;
    
        Resource A = model.createResource(NS + "A");
        Resource B = model.createResource(NS + "B");
        Resource C = model.createResource(NS + "C");
        Resource D = model.createResource(NS + "D");
    
        Property p = model.createProperty(NS, "p");
        Property q = model.createProperty(NS, "q");
    
    
        @Before
        public void init() {
    
            // Some small examples (subProperty)
            model.add(p, RDFS.subPropertyOf, q);
            A.addProperty(p, "foo" );
    
            // Get an RDFS reasoner
            GenericRuleReasoner rdfsReasoner = (GenericRuleReasoner) ReasonerRegistry.getRDFSReasoner();
            // Steal its rules, and add one of our own, and create a
            // reasoner with these rules
            List<Rule> customRules = new ArrayList<>( rdfsReasoner.getRules() );
            String customRule = "[rule1: (?a eg:p ?b) (?b eg:p ?c) -> (?a eg:p ?c)]";
            customRules.add( Rule.parseRule( customRule ));
            Reasoner reasoner = new GenericRuleReasoner( customRules );
    
            reasoner.setDerivationLogging(true);
            inf = ModelFactory.createInfModel(reasoner, model);
    
            // Derivations
            A.addProperty(p, B);
            B.addProperty(p, C);
            C.addProperty(p, D);
        }
    
        @Test
        public void subProperty() {
            StmtIterator stmts = inf.listStatements( A, q, (RDFNode) null );
            assertTrue( stmts.hasNext() );
            while ( stmts.hasNext() ) { 
                System.out.println( "Statement: "+stmts.next() );
            }
        }
    
        @Test
        public void derivations() {
            String trace = null;
            PrintWriter out = new PrintWriter(System.out);
            for (StmtIterator i = inf.listStatements(A, p, D); i.hasNext(); ) {
                Statement s = i.nextStatement();
                System.out.println("Statement is " + s);
                for (Iterator<Derivation> id = inf.getDerivation(s); id.hasNext(); ) {
                    Derivation deriv = (Derivation) id.next();
                    deriv.printTrace(out, true);
                    trace += deriv.toString();
                }
            }
            out.flush();
            assertNotNull(trace);
        }
    
        @Test
        public void listStatements() {
            StmtIterator stmtIterator = inf.listStatements();
            while(stmtIterator.hasNext()) {
                System.out.println(stmtIterator.nextStatement());
            }
        }
    }