I\'m working on a small Drools project, because I want to learn more about using rule engines. I have a class called Event
that has the following fields:
Assuming you are using the STREAM event processing mode and your events are ordered in the stream:
rule "3 most recent events"
when
accumulate( $e : Event( tag == "OK" ) over window:length(3),
$events : collectList( $e ) )
then
// $events is a list that contains your 3 most recent
// events by insertion order
end
===== edit ====
Based on your comment bellow, here is how to achieve what you want in Drools 5.4+:
declare window LastEvents
Event() over window:length(3)
end
rule "OK events among the last 3 events"
when
accumulate( $e : Event( tag == "OK" ) from window LastEvents,
$events : collectList( $e ) )
then
// $events is a list that contains the OK events among the last 3
// events by insertion order
end
Just double check the syntax as I am doing this by heart, but it should be close to this.
I was able to simplify 'not logic' like this
rule "Three most recent events tagged with 'OK'"
when
$e1 : Event( tag == "OK")
$e2 : Event( tag == "OK", millis < $e1.millis )
$e3 : Event( tag == "OK", millis < $e2.millis )
not Event( this != $e2, tag == "OK", $e3.millis < millis, millis < $e1.millis )
then
System.out.printf("%s - %s - %s%n", $e1, $e2, $e3);
end
There was nothing said about cleaning events. Usually this is desirable, so you can achieve the same logic with deletion of the last event:
rule "Three most recent events tagged with 'OK'"
when
$e1 : Event( tag == "OK")
$e2 : Event( tag == "OK", millis < $e1.millis )
$e3 : Event( tag == "OK", millis < $e2.millis )
then
System.out.printf("%s - %s - %s%n", $e1, $e2, $e3);
retract ($e3)
end
Let say each second you'll insert an event one 'OK' another empty '', here is the test:
@DroolsSession("classpath:/test3.drl")
public class PlaygroundTest {
@Rule
public DroolsAssert drools = new DroolsAssert();
@Test
public void testIt() {
for (int i = 0; i < 10; i++) {
drools.advanceTime(1, SECONDS);
drools.insertAndFire(new Event(i % 2 == 0 ? "OK" : "", i));
}
}
}
all three variants will produce the same triggering logic:
00:00:01 --> inserted: Event[tag=OK,millis=0]
00:00:01 --> fireAllRules
00:00:02 --> inserted: Event[tag=,millis=1]
00:00:02 --> fireAllRules
00:00:03 --> inserted: Event[tag=OK,millis=2]
00:00:03 --> fireAllRules
00:00:04 --> inserted: Event[tag=,millis=3]
00:00:04 --> fireAllRules
00:00:05 --> inserted: Event[tag=OK,millis=4]
00:00:05 --> fireAllRules
00:00:05 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [Event, Event, Event]
OK4 - OK2 - OK0
00:00:06 --> inserted: Event[tag=,millis=5]
00:00:06 --> fireAllRules
00:00:07 --> inserted: Event[tag=OK,millis=6]
00:00:07 --> fireAllRules
00:00:07 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [Event, Event, Event]
OK6 - OK4 - OK2
00:00:08 --> inserted: Event[tag=,millis=7]
00:00:08 --> fireAllRules
00:00:09 --> inserted: Event[tag=OK,millis=8]
00:00:09 --> fireAllRules
00:00:09 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [Event, Event, Event]
OK8 - OK6 - OK4
00:00:10 --> inserted: Event[tag=,millis=9]
00:00:10 --> fireAllRules
variant with window:length(3)
will also deal with last 3 OK events. It is different on the beginning though: it will be triggered for 1 and 2 first OK events too. It will be also triggered once with empty list on the beginning if session doesn't contain any events. According to documentation, sliding windows start to match immediately and defining a sliding window does not imply that the rule has to wait for the sliding window to be "full" in order to match. For instance, a rule that calculates the average of an event property on a window:length(10) will start calculating the average immediately, and it will start at 0 (zero) for no-events, and will update the average as events arrive one by one.
00:00:01 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [InitialFactImpl, UnmodifiableRandomAccessList]
[]
00:00:01 --> inserted: Event[tag=OK,millis=0]
00:00:01 --> fireAllRules
00:00:01 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [InitialFactImpl, UnmodifiableRandomAccessList]
[OK0]
00:00:02 --> inserted: Event[tag=,millis=1]
00:00:02 --> fireAllRules
00:00:03 --> inserted: Event[tag=OK,millis=2]
00:00:03 --> fireAllRules
00:00:03 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [InitialFactImpl, UnmodifiableRandomAccessList]
[OK0, OK2]
00:00:04 --> inserted: Event[tag=,millis=3]
00:00:04 --> fireAllRules
00:00:05 --> inserted: Event[tag=OK,millis=4]
00:00:05 --> fireAllRules
00:00:05 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [InitialFactImpl, UnmodifiableRandomAccessList]
[OK0, OK2, OK4]
00:00:06 --> inserted: Event[tag=,millis=5]
00:00:06 --> fireAllRules
00:00:07 --> inserted: Event[tag=OK,millis=6]
00:00:07 --> fireAllRules
00:00:07 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [InitialFactImpl, UnmodifiableRandomAccessList]
[OK2, OK4, OK6]
00:00:08 --> inserted: Event[tag=,millis=7]
00:00:08 --> fireAllRules
00:00:09 --> inserted: Event[tag=OK,millis=8]
00:00:09 --> fireAllRules
00:00:09 <-- 'Three most recent events tagged with 'OK'' has been activated by the tuple [InitialFactImpl, UnmodifiableRandomAccessList]
[OK4, OK6, OK8]
00:00:10 --> inserted: Event[tag=,millis=9]
00:00:10 --> fireAllRules