I am trying to design a rule system where the rules themselves can be external configured, using a rule configuration object. Specifically, I want to configure externally to the DRL rule definition what the minimum time between rule firings for a particular type of rule should be.
My approach so far is to insert the rule configuration as a fact ValueRuleSpec:
rule "Any value detected"
when
$r : ValueRuleSpec(mode == ValueRuleSpecMode.ANY(), $devices: devices)
$e : SensorEvent(deviceId memberOf $devices) from entry-point FMSensorEvents
not Activation(ruleSpec == $r, cause == $e)
then
insert(new Activation($r, $e));
end
The $r ValueRuleSpec object has a property triggerEvery that contains the minimum number of seconds between activations. I know that this can be done statically by testing for the absence of an Activation object that is inside a specific range before $e using something like:
not Activation(this before[60s, 0s] $e)
How could I do this with a configurable time window, using the $r.triggerEvery property as the number of seconds?
Answering my own question based on the advice of laune.
The before keyword's behavior is described in the manual as:
$eventA : EventA( this before[ 3m30s, 4m ] $eventB )
The previous pattern will match if and only if the temporal distance between the time when $eventA finished and the time when $eventB started is between ( 3 minutes and 30 seconds ) and ( 4 minutes ). In other words:
3m30s <= $eventB.startTimestamp - $eventA.endTimeStamp <= 4m
Looking up the source code for the before evaluator we can see the same.
@Override
protected boolean evaluate(long rightTS, long leftTS) {
long dist = leftTS - rightTS;
return this.getOperator().isNegated() ^ (dist >= this.initRange && dist <= this.finalRange);
}
Based on this I've modified my code accordingly, and it seems to work correctly now:
rule "Any value detected"
when
$r : ValueRuleSpec(mode == ValueRuleSpecMode.ANY(), $devices: devices)
$e : SensorEvent(deviceId memberOf $devices) from entry-point FMSensorEvents
not Activation(ruleSpec == $r, cause == $e)
// no activation within past triggerEvery seconds for same device
not Activation(
ruleSpec == $r,
deviceId == $e.deviceId,
start.time > ($e.start.time - ($r.triggerEvery * 1000))
)
then
insert(new Activation($r, $e));
end