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:
String tag;
A tag which can be any string.long millis;
A timestamp. (Actually, this is converted from a JodaTime LocalDate
field which is also in Event
.)int value;
A value that I want reason about.I insert several hundreds of Event
instances into my knowledge base, and now I want to get the 3 most recent events that are tagged with "OK"
. I came up with the following code, which works:
rule "Three most recent events tagged with 'OK'"
when
$e1 : Event( tag == "OK",
$millis1 : millis )
$e2 : Event( tag == "OK",
millis < $millis1, $millis2 : millis )
$e3 : Event( tag == "OK",
millis < $millis2, $millis3 : millis )
not Event( tag == "OK",
millis > $millis1 )
not Event( tag == "OK",
millis > $millis2 && millis < $millis1 )
not Event( tag == "OK",
millis > $millis3 && millis < $millis2 )
then
# Do something with $e1.value, $e2.value and $e3.value
end
But I have a feeling there should be a better way to do this. This is quite verbose and not easily re-used: what if I want to get the five most recent events with value > 10
, for example? I would end up copy-pasting a lot of code, and I don't want to do that :).
Also, the code doesn't look very 'beautiful' to me. I don't really like the repeated not Event...
constraints, and I also don't like having to repeat the same tag condition over and over. (This example is a heavily simplified version of my real app, in which the condition is actually a lot more complex.)
How can I improve this code?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With