Question

In Jena, I have created an RDFS inference model using InfModel class:

InfModel infmodel = ModelFactory.createRDFSModel(schema, data);

Given an inferred statement from infmodel, how do we get the two statements that were used to infer it, similar to the the "explain inference" option in Protégé? For instance, if infModel contains the statement :a rdf:type :t, we might get two statements used to infer it, e.g., :a :p :b and :p rdfs:domain :t.

Was it helpful?

Solution

According to the documentation (and testing with Jena 2.11.1) you can get access to a Derivation object which will allow you to create a textual description of what happened. In the following example, we retrieve RuleDerivation objects that expose a little bit more regarding the internal state.

The following is a tested implementation of the documentation example which begins with the following model:

<urn:eg:C>  <urn:eg:p>  <urn:eg:D> .
<urn:eg:B>  <urn:eg:p>  <urn:eg:C> .
<urn:eg:A>  <urn:eg:p>  <urn:eg:B> .

... and the following rule:

[rule1: (?a urn:eg:p ?b) (?b urn:eg:p ?c) -> (?a urn:eg:p ?c)]

... to produce this resulting model:

<urn:eg:B>  <urn:eg:p>  <urn:eg:D> , <urn:eg:C> .
<urn:eg:A>  <urn:eg:p>  <urn:eg:D> , <urn:eg:C> , <urn:eg:B> .
<urn:eg:C>  <urn:eg:p>  <urn:eg:D> .

This basic transitive inference becomes the core aspect of the example to follow. Note that we obtain an instance of RuleDerivation which is a start towards your end goal.

final Resource A = ResourceFactory.createResource("urn:eg:A");
final Resource B = ResourceFactory.createResource("urn:eg:B");
final Resource C = ResourceFactory.createResource("urn:eg:C");
final Resource D = ResourceFactory.createResource("urn:eg:D");
final Property p = ResourceFactory.createProperty("urn:eg:p");

final Model rawData = ModelFactory.createDefaultModel();
rawData.add(A, p, B);
rawData.add(B, p, C);
rawData.add(C, p, D);

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

final 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 (final Iterator<Derivation> id = inf.getDerivation(s); id.hasNext(); ) {
        final RuleDerivation deriv = (RuleDerivation) id.next();
        deriv.printTrace(out, true);
    }
}
out.flush();

The output of this example is:

Statement is [urn:eg:A, urn:eg:p, urn:eg:D]
Rule rule1 concluded (urn:eg:A urn:eg:p urn:eg:D) <-
    Rule rule1 concluded (urn:eg:A urn:eg:p urn:eg:C) <-
        Fact (urn:eg:A urn:eg:p urn:eg:B)
        Fact (urn:eg:B urn:eg:p urn:eg:C)
    Fact (urn:eg:C urn:eg:p urn:eg:D)

EDIT - Tips

Check out the internals of RuleDerivation#printTrace(...) if you are looking for an example about how to explore derivations. If you want to convert a triple (from RuleDerivation#getMatches()) back to a statement, use StatementImpl#toStaetment(Triple,ModelCom).

EDIT2 - Done Assuming that you are using one of Jena's built in rule-based reasoners, the following code will allow you to explore the matches for one particular derivation reported by a reasoner.

final StmtIterator input = inf.listStatements(A, p, D);
assert( input.hasNext() );

final Iterator<Derivation> derivations = inf.getDerivation(input.next());
assert( null != derivations );
assert( derivations.hasNext() );

final RuleDerivation oneDerivation = (RuleDerivation) derivations.next();
final ExtendedIterator< Statement > matches = 
        new NiceIterator< Triple >()
        .andThen( oneDerivation.getMatches().iterator())
        .mapWith( new Map1< Triple, Statement >(){
            @Override
            public Statement map1( final Triple t )
            {
                /* Note that it seems that this model doesn't really mean anything. While
                 * the statement will be associated with the infModel, the triple that led
                 * to the match could have been from either the deductions graph or the
                 * raw graph. This does not actually add any triples to the underlying
                 * store.
                 */
                return StatementImpl.toStatement(t, (ModelCom)inf);
            }});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top