Hi Justin,
I'm not the developer of the rule engine, might I will try do answer
your question with my limited knowledge:
Using Generic rule reasoner (in FORWARD mode), say I have a rule with this
in the head:
(?reportA ex:supercededBy ?reportB)
Then another rule with this in the body:
noValue(?reportA ex:supercededBy ?reportB)
Shouldn't there be an implicit rule fire ordering since we can see that the
second rule depends on the first rule firing until completion.
As far as I know, there is nothing for
- guaranteed rule ordering
- stratification
- dependency analysis
- truth maintenance
Under the hood, the forward GenericRuleReasoner is implemented using a
RETE network. What RETE does not imply rule ordering, stratification, or
safe negation. It just makes matching fast.
Your specific example
Rule A (producer):
... -> (?reportA ex:supercededBy ?reportB)
Rule B (consumer):
noValue(?reportA ex:supercededBy ?reportB) ... -> ...
Your expectation is basically:
“Rule B should wait until Rule A has fully fired.”
That expectation assumes stratified negation (like in Datalog or SQL),
but Jena does not do that.
So, why do I think that Jena can’t safely do implicit ordering?
Because the builtIn noValue is non-monotonic.
At the moment Rule B fires:
- The triple might not exist yet
- But it might be inferred later
- Jena has no way to know that in advance
So from the engine’s perspective:
"Absence of a triple right now is not stable information."
That’s why:
- noValue is evaluated against the current graph snapshot
- Results may become logically invalid later
- Jena will not retract them
This is probably one reason why the documentation quietly treats noValue
as dangerous but useful.
And a related question...
Say I have triples like:
:thingA :hasValue 8 .
:thingA :hasValue 4 .
:thingA :hasValue 9 .
...
Using FORWARD mode, is it possible to write a set of rules that do the
equivalent of:
```
CONSTRUCT
{
?thing :hasMaxValue ?max_value .
}
WHERE
{ SELECT ?thing (MAX(?value) AS ?max_value)
WHERE
{ ?thing :hasValue ?value }
GROUP BY ?thing
}
```
No, I don't think this is possible. The Generic Rule Reasoner cannot
express aggregation semantics like MAX in a sound way.
Why aggregation doesn’t work in Jena forward rules, is basically because
those:
- Fire on local pattern matches
- Have no global view
- Cannot “see all values” for a thing at once
- Cannot retract previously inferred triples
For example when we have
:thingA :hasValue 8 .
:thingA :hasValue 4 .
:thingA :hasValue 9 .
A forward rule might see:
- 8 first -> infer hasMaxValue 8
- then 9 later -> infer hasMaxValue 9
but cannot remove the 8
So we would end up with
:thingA :hasMaxValue 8 .
:thingA :hasMaxValue 9 .
I know that other rule languages might have extensions for aggregates,
but we could maybe better think of Jena FORWARD rules as:
“RDFS with custom Horn clauses — not SQL, not Datalog with negation, not
a rule engine with agenda control.”
Hope this answers your questions to some extent, although that wouldn't
solve your problem. A combination of rules + SPARQL CONSTRUCT (INSERTs)
might solve your use-case
Cheers,
Lorenz
--
Lorenz Bühmann
Research Associate/Scientific Developer
[email protected]
Institute for Applied Informatics e.V. (InfAI) | Goerdelerring 9 | 04109
Leipzig | Germany