2

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());
        }
    }
}
Stanislav Kralin
  • 11,070
  • 4
  • 35
  • 58
Macilias
  • 3,279
  • 2
  • 31
  • 43

1 Answers1

7

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());
        }
    }
}
Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
  • Hej, great answer. Even than i realized that there is a problem with the namespaces, your answer clarifies a lot. To be honest, I´m still trying to add RDFS reasoning but failing. I added: Reasoner reasoner = RDFSRuleReasonerFactory.theInstance().create(null); reasoner.setParameter(ReasonerVocabulary.PROPsetRDFSLevel, ReasonerVocabulary.RDFS_DEFAULT); reasoner.setDerivationLogging(true); inf = ModelFactory.createInfModel(reasoner, model); but it does not do the trick. Do you have a idea, what might be wrong with that? – Macilias Jul 16 '14 at 20:10
  • 1
    **Even than i realized that there is a Problem with matching** Sorry,but I'm not quite sure what you mean. Did this work for you? – Joshua Taylor Jul 16 '14 at 20:11
  • i mean, that there was a namespace mismatch, eg on the one and "urn:x-hp-jena:eg/" on the other side. Do you have a pointer where to find more about the name space expansion you mentioned in first sentence? – Macilias Jul 16 '14 at 20:17
  • [The documentation](https://jena.apache.org/documentation/inference/) says that *"To keep rules readable qname syntax is supported for URI refs. The set of known prefixes is those registered with the PrintUtil object. This initially knows about rdf, rdfs, owl, xsd and a test namespace eg, but more mappings can be registered in java code. In addition it is possible to define additional prefix mappings in the rule file, see below."* It doesn't say what `eg:` maps to though. I only found out here through experimentation. Some of the examples show "urn:x-hp:eg", others "urn:x-hp-jena:eg". – Joshua Taylor Jul 16 '14 at 20:21
  • Ok, thanks again. But if you have a idea how to get the reasoning up and running i would be very great full. As mentioned in the first comment, the usage of a RDFSReasoner with RDFS Rules did not the trick. – Macilias Jul 16 '14 at 20:39
  • What do you mean? You've already got a reasoner up and running. What else are you trying to do? – Joshua Taylor Jul 16 '14 at 20:39
  • i mean the derivation test, it still fails. – Macilias Jul 16 '14 at 20:41
  • Do you want to add use an RDFS reasoner? Or just add the subproperty rule to your own set of rules? – Joshua Taylor Jul 16 '14 at 20:43
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/57445/discussion-between-macilias-and-joshua-taylor). – Macilias Jul 16 '14 at 20:58
  • @Macilias OK, I've updated my answer. With the edits I've made, all the tests pass. – Joshua Taylor Jul 16 '14 at 21:00
  • Glad to hear it! If you are going to do things like transitivity, look into how the rules handle owl:transitiveProperty and the like. There are a few ways to do it. One is `[(p a transitiveProperty) (?x p ?y) (?y p ?z) -> (?x p ?z)]`. The other creates a new rule for each transitive property: `[(p a transitiveProperty) -> [(?x p ?y) (?y p ?z) -> (?x p ?z)]]`. Similar things can be done for subproperty relations, too. – Joshua Taylor Jul 16 '14 at 21:12
  • Do you know if its possible to use the variables like ?x and so on as wildcards mapped to a namespace to do a mapping between ontologies e.g: `(ns1:?x rdf:type ns1:?y) (ns2:?z rdf:type ns2:?y) -> (ns1:?x rdf:type ns2:?y)` ? But i guess this would be at least another Question ;) – Macilias Jul 16 '14 at 21:41
  • That would be a different question. You can't do it the way that you've written it, but you might be able to do some string manipulation of URIs. There was a recent question about data conversion, [http://stackoverflow.com/q/24447249/1281433](http://stackoverflow.com/q/24447249/1281433) that had a fairly elegant solution in SPARQL (which Jena also supports). I'm not sure what you mean with your "rule", though; I don't get what ?z is supposed to do. At any rate, it's really better asked as a new question. – Joshua Taylor Jul 16 '14 at 21:45
  • it should express: if there is the same typename mapped to the different namespace n2 as it is in n1, all individuals of n1 get also the same type in n2, but i would first consult your pointer, and than maybe post a new question. Thanks – Macilias Jul 17 '14 at 08:22
  • Ah, I see what you mean now. However **(ns2:?z rdf:type ns2:?y)** might not be sufficient, though. What if **ns2:?y** had been declared as a class, but no resources have it as a type yet? The more general approach would be to define some criteria under which you assume two classes are the same, and figure out how to implement that check. Then you could, e.g., add another rule that makes sure instances of one class are instances of classes that are the same as it. Better yet (perhaps) you could just add the two `rdfs:subClassOf` triples **(ns1:?y rdfs:subClassOf ns2:?y)** and … – Joshua Taylor Jul 17 '14 at 10:52
  • … **(ns2:?y rdfs:subClassOf ns1:?y)** and let an RDFS reasoner take care of mapping the instances for you. – Joshua Taylor Jul 17 '14 at 10:54
  • i have played a round with your solution and must admit that even if the idea is valid, it didn`t work again, and there might be problem with generating too much unwonted information, instead of making it as specific as possible. However i posted everything in the different question: http://stackoverflow.com/questions/24806215/ho-to-achieve-mapping-between-namespaces-in-apache-jena-thru-reasoning This one is greatly answered :) – Macilias Jul 17 '14 at 14:26