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.