0

I am trying to write a rule that collects / accumulates values based on a temporal operator.

rule "Zone6 Overlap"
when
    $i1 : Instance ($e1 : event == " Vel : 20.99-23.98 km/h : " && $name1 : name) from entry-point "Stream"
    $i2 : Instance ($e2 : event && $name2 : name && $e2 == $e1 && $name2 != $name1 
    && this overlaps $i1) from entry-point "Stream"
then 
    System.out.println("** Overlap Event: Velocity Zone 6 ** \nPlayer1: " + $i1.getName() + "\nPlayer2: " 
    + $i2.getName() + "\nEvent: " + $i1.getEvent() + "\n" + "Start Time (P1): " 
    + $i1.getStart() + " - End Time: " + $i1.getEnd() + "\nStart Time (P2): " 
    + $i2.getStart() + " - End Time: " + $i2.getEnd() + "\n");
end

This is my original rule which manages to get the overlap of two durations.

The idea of the rule i want to create is to see if there are any collective overlaps of the durations of players in a football game. I want to see if any of up to the 9 players on the field are travelling at a range of speed specified as a string in the event variable that are all overlapping at once.

I've tried a few things regarding accumulate and collect but struggling with how to collect these events when they happen and return them to the right hand side of the rule so they can be printed to standard out.

Please help.

Thanks.

Stu
  • 67
  • 6

1 Answers1

1

It should be possible to create a rule to match your requirements, but I think you need to be aware of the exact definition of the overlaps keyword in Drools:

The overlaps evaluator correlates two events and matches when the current event starts before the correlated event starts and finishes after the correlated event starts, but before the correlated event finishes. In other words, both events have an overlapping period.

That means that it will not match any arbitrary overlap, but only if one event both starts before another event's start and ends before that event's end. Let's assume we have the following 3 events:

A [11:19:00-11:19:30]
B [11:19:15-11:19:45]
C [11:19:20-11:19:40]

In this case, A starts before B and C, and also ends before both. That means A overlaps B and C. However, B does not overlap C, because it starts before C, but it ends after C. For a full definition of each of the available operators, see the Drools fusion documentation.

If that matches your use case, the following rule will collect all events that overlap a given event:

rule "Overlap"
when
    $i1 : Instance ($e1 : event == "some event" ) 
    $instances : List( size > 0 ) from collect ( Instance ( event == $e1, this != $i1, 
        this overlappedby $i1 ) )
then
    System.out.println("** Overlap Event for: " + $i1.getName());
    for (int i = 0; i < $instances.size(); i++) {
        System.out.println("Overlaps: " +  ((Instance)$instances.get(i)).getName());
    }
end

As you can see, it uses the overlappedby keyword, which is the inverse of overlaps.

Ben Damer
  • 996
  • 7
  • 14
  • Ahh I understand. Yes that does make sense. Basically, the temporal operator (overlaps) was the wrong way round (should be overlappedby). And I just simply needed to use the collect function, Instead of the accumulate. Drools documentation (including the books that were written by packt) seems to push the accumulation function a lot. Hence why I was confused whether to use it or not. Regardless, Thanks for your help. – Stu Aug 18 '16 at 11:52
  • Done. Just wondering if you can answer a quick question for me: Ive declared a global variable which is a list and populated it with certain objects. Do you know how to call the methods on those objects within a global array on the RHS after a condition is met? Thanks. – Stu Aug 18 '16 at 15:42
  • P.s just your array declaration reminded me I had a problem with using a global list in my project in terms of editing objects. – Stu Aug 18 '16 at 15:47
  • Assuming that your global is of the generic type java.util.List, you'll have to cast each object that it contains to the actual type. Basically, the same thing I am doing for the list `$instances` above - cast the entry to class `Instance` before calling `getName`. – Ben Damer Aug 18 '16 at 16:54