Hi Barry,

On 04/09/18 12:47, Nouwt, B. (Barry) wrote:
Hi Dave,

Thanks for your answers and the pointer towards implementing such feature. I 
assume the syntactical solution you mention would not solve the limitation I 
describe below. I'm unsure how to circumvent this limitation without 
multi-headed backward rule support, but I'm of course open to suggestions.

See below ...

Do you maybe have "alternative general purpose backward rule engine" in mind 
that either already supports multiple heads, or that might be easier to extend to support 
it? I've also been looking into other engines, like TopQuadrant's SHACL engine 
(https://github.com/TopQuadrant/shacl/issues/44) or Openllet 
(https://github.com/Galigator/openllet), but for now none of them beats the Jena's 
GenericRuleEngine 😊.

I was thinking of non-RDF rule engines which would then need (non-trivial) work to wire up to a triple representation.

If you want serious backward chaining then XSB is the one to look at. The jena backward engine is based loosely on a simplified version of the SLG-WAM approach that XSB uses.

The alternative is Drools, which has in general a good reputation, but I know nothing about it's backward rule support (indeed next to nothing about it at all).

I'll try to explain one of the limitations we encounter in more detail. Imagine 
the following (untested and not that useful) scenario with a SPARQL query that 
retrieves a particular measured value based on a start and end date:

SELECT ?value
WHERE {
        ?measurement :hasValue ?value .
        ?measurement :validFor ?interval .
        ?interval rdf:type :DateInterval .
        ?interval :startDate "2018-06-10"^^xsd:date .
        ?interval :endDate "2018-07-07"^^xsd:date .
        ?interval :valid "true"^^xsd:boolean .
}

The data could look like this (note the missing ":interval1 :valid 
"true"^^xsd:boolean" triple):

        :measure1 :hasValue "123" .
        :measure1 :validFor :interval1 .
        :interval1 rdf:type :DateInterval .
        :interval1 :startDate "2018-06-10"^^xsd:date .
        :interval1 :endDate "2018-07-07"^^xsd:date .

Now we would like to have a backward rule that checks whether the start lies before the 
end date of the intervals and adds the valid = "true" triple.

[IntRule:
        (?int rdf:type :DateInterval)
        (?int :startDate ?start)
        (?int :endDate ?end)
<-
        lessThan(?start, ?end)
        (?int :valid "true"^^xsd:boolean)
]

Not sure I follow that. If you want to conclude that a measurement with correctly ordered dates is valid, and do so using a forward rule then you would use:

[IntRule:
    (?int rdf:type :DateInterval)
    (?int :startDate ?start)
    (?int :endDate ?end)
    lessThan(?start, ?end)
  ->
    (?int :valid "true"^^xsd:boolean)
]

That rule is valid both forward and backward. There is only one head (conclusion) from a set of three body terms and a condition. So you could set the engine to run in backward mode and run that same rule backwards with no problems.

If you want to use the explicit backward rule syntax, so you can use the generic reasoner in default hybrid mode, then the corresponding backward rule syntax is:

[IntRule:
    (?int :valid "true"^^xsd:boolean)
    <-
    (?int rdf:type :DateInterval)
    (?int :startDate ?start)
    (?int :endDate ?end)
    lessThan(?start, ?end)
]

That's valid and works for me on a trivial test case.

Maybe I'm misunderstanding what you are trying to do, or maybe there's some confusion caused by the backward rule syntax.

Dave

So, to answer the above query, the head of the backward rule would match with 
the corresponding goal triples from the SPARQL query and bind the ?start and 
?end variable in the rule to the dates mentioned in the SPARQL query. We have 
difficulties getting this to work with single-headed backward rules, since the 
splitted single-headed backward rules look like below and this means none of 
the rules can make the lessThan(?start, ?end) comparison since none of them has 
more than one triple in its head.

[IntRule1:
        (?int rdf:type :DateInterval)
<-
        lessThan(?start, ?end)  #MISSES BOTH ?start AND ?end
        (?int :valid "true"^^xsd:boolean)
]

[IntRule2:
        (?int :startDate ?start)
<-
        lessThan(?start, ?end)  #MISSES ?end
        (?int :valid "true"^^xsd:boolean)
]

[IntRule3:
        (?int :endDate ?end)
<-
        lessThan(?start, ?end)  #MISSES ?end
        (?int :valid "true"^^xsd:boolean)
]

Thanks in advance!

Regards, Barry

-----Original Message-----
From: Dave Reynolds <dave.e.reyno...@gmail.com>
Sent: dinsdag 4 september 2018 12:41
To: users@jena.apache.org
Subject: Re: [GenericRuleReasoner] multi-headed backward chaining

Hi,

On 03/09/18 13:05, Nouwt, B. (Barry) wrote:
Hi all,

We are using Apache Jena's GenericRuleReasoner in our project with backward 
chaining to selectively apply rules relevant to answer a particular SPARQL 
question. We learned that backward chaining in Jena's GenericRuleReasoner 
currently only supports single headed backward rules. However, we are facing 
quite some limitations due to this single-headedness and would like to know 
whether there have been or are attempts to overcome this limitation.

No, there have been no such attempts to my knowledge. Single headed rules are 
the norm. The forward engine provides multi headed as a convenience because 
that's slightly more efficient in the forward case than having N single-headed 
rules but in the backward case there would be no such saving.

Currently we split N-headed forward rules to N single-headed backward rules, 
but this limits the amount of bound variables (from the initial SPARQL query) 
available in a single rule's body. This is an important requirement in our use 
case.

This is the way I would do it. I don't understand what you mean by the 
limitation. If you are replicating the rules bodies then each body has all the 
variables.

So, could someone with knowledge about the internals of the backward chaining 
process in the GenericRuleReasoner shed some light on whether it would (in 
principle) be possible to support multi-headed backward rules in Apache Jena's 
GenericRuleReasoner. We are even considering/investigating whether we can 
implement this feature ourselves.

If someone wanted to do this I would advise them to do it by a syntactic 
transformation of the sources rules in the way you are already doing, not by 
messing with the engine.

If you *really* wanted engine support then I guess one way to do this would be 
to allow goals which can bind more values than are available in a triple. So 
you could have things like (pseudo rule code only):

     head1(A)   <- intermediate(A,B,C...X,Y,Z)
     head2(X,Y) <- intermediate(A,B,C...X,Y,Z)
     head3(Z)   <- intermediate(A,B,C...X,Y,Z)

     intermediate(A,B,C...X,Y,Z) <- ... body clauses ...

Extending the backward rule engine to allow for general tuple goals and terms 
(but hide non-triple terms from the jena interface) is probably possible but a 
pretty substantial amount of work.

Syntactically it might be possible to use the "Functor"
hack^h^h^h^hmachinery supported in the rule engines. But adding 
match/unification over functors would probably end up being as much work as 
generalizing the engine to non-triples.

Probably easier to find an alternative general purpose backward rule engine and 
wire it up to jena.

Dave

This message may contain information that is not intended for you. If you are 
not the addressee or if this message was sent to you by mistake, you are 
requested to inform the sender and delete the message. TNO accepts no liability 
for the content of this e-mail, for the manner in which you use it and for 
damage of any kind resulting from the risks inherent to the electronic 
transmission of messages.

Reply via email to