0

I am new in Drools applications and above all in Drools fusion. In my office we are working on a Standalone Complex Event Processing application. One of main requirements is the possibility to calculate starting time, frequency, end time, duration of each event. We are testing Drools Fusion to do so and we made this example that doens't work. In this example we try to calculate duration. As side note, we were not able to calculate event timestamp and for now we resolved using System.currentTimeMillis().

Maybe Drools is not a good framework and we have to change our choice?

Sample.drl

import it.ipiu.other.SElDroolsTest.Message;
declare Message
 @role(event)
 @timestamp(time)
 @duration(howMuch)
end

rule "Message"
    when
        Message() from entry-point "entry"
    then
        System.out.println("a message!!!");
end

and example class

package it.ipiu.other;

import java.util.Date;
import java.util.concurrent.TimeUnit;

import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseConfiguration;
import org.drools.KnowledgeBaseFactory;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderError;
import org.drools.builder.KnowledgeBuilderErrors;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.common.EventFactHandle;
import org.drools.conf.EventProcessingOption;
import org.drools.io.ResourceFactory;
import org.drools.logger.KnowledgeRuntimeLogger;
import org.drools.logger.KnowledgeRuntimeLoggerFactory;
import org.drools.runtime.KnowledgeSessionConfiguration;
import org.drools.runtime.StatefulKnowledgeSession;
import org.drools.runtime.conf.ClockTypeOption;
import org.drools.runtime.rule.FactHandle;
import org.drools.runtime.rule.WorkingMemoryEntryPoint;
import org.drools.time.SessionClock;
import org.drools.time.impl.PseudoClockScheduler;

/**
 * This is a sample class to launch a rule.
 */
public class SElDroolsTest {

    public static final void main(String[] args) {
        try {
            // load up the knowledge base
            KnowledgeBase kbase = readKnowledgeBase();
            KnowledgeSessionConfiguration sessionConfiguration = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
            sessionConfiguration.setOption(ClockTypeOption.get("pseudo"));

            StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession(sessionConfiguration, null);
            KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");

            PseudoClockScheduler sessionClock = ksession.getSessionClock(); // !!!
            // go !
            Message message = new Message();
            message.setMessage("Hello World");
            message.setStatus(Message.HELLO);
            message.setTime(System.currentTimeMillis());

            WorkingMemoryEntryPoint entryPoint = ksession.getWorkingMemoryEntryPoint("entry");

            sessionClock.advanceTime(1, TimeUnit.HOURS);

            EventFactHandle factHandle = (EventFactHandle) entryPoint.insert(message);

            sessionClock.advanceTime(1, TimeUnit.HOURS);

            int fireAllRules = ksession.fireAllRules();
            System.out.println("FACT : startTimeStamp " +  factHandle.getStartTimestamp());
            System.out.println("FACT : duration " +  factHandle.getDuration());
            System.out.println("FIRED : " + fireAllRules);
            System.out.println("TIME STAMP " + message.getTime()); 
            System.out.println("TIME DURATION " + message.getHowMuch()); 
            logger.close();
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    private static KnowledgeBase readKnowledgeBase() throws Exception {
        KnowledgeBaseConfiguration configuration = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
        configuration.setOption(EventProcessingOption.STREAM);
        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add(ResourceFactory.newClassPathResource("Sample.drl"), ResourceType.DRL);
        KnowledgeBuilderErrors errors = kbuilder.getErrors();
        if (errors.size() > 0) {
            for (KnowledgeBuilderError error : errors) {
                System.err.println(error);
            }
            throw new IllegalArgumentException("Could not parse knowledge.");
        }

        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(/*configuration*/);
        kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
        return kbase;
    }

    public static class Message {

        public static final int HELLO = 0;
        public static final int GOODBYE = 1;
        private Long time = new Long(0);
        private Long howMuch = new Long(0);


        public Long getHowMuch() {
            return howMuch;
        }

        public void setHowMuch(Long howMuch) {
            this.howMuch = howMuch;
        }

        public Long getTime() {
            return time;
        }

        public void setTime(Long time) {
            this.time = time;
        }

        private String message;

        private int status;

        public String getMessage() {
            return this.message;
        }

        public void setMessage(String message) {
            this.message = message;
        }

        public int getStatus() {
            return this.status;
        }

        public void setStatus(int status) {
            this.status = status;
        }

    }

}
Darrell Teague
  • 4,132
  • 1
  • 26
  • 38

1 Answers1

3

I think there are a few misconceptions in your use of Drools Fusion. I will try to clarify a few of them:

  • I am not sure what you mean by "calculate starting time, frequency, end time, duration of each event". CEP products in general allow an application to listen to events, detect patterns by matching those events and correlating them and other data, and react when those patterns are detected. So, you can detect events and calculate their frequency, but starting time, duration (and end time) are part of the events themselves, not something the engine comes up with. Of course the engine can correlate atomic events into complex events and in this case it will assign things like duration to the complex event, but it is still application logic, not the engine doing magic.

  • Drools works in two modes: batch (called CLOUD mode, as in cloud of events) and real time mode (called STREAM mode, as in streams of events). Time flow only makes sense in STREAM (real time) mode. You commented out the configuration of the STREAM mode, and so everything you are doing with a clock in your application is ignored:

    KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(/configuration/);

  • Your code is configuring the engine to use the pseudo-clock, but you are using the machine clock to assign timestamps to your events with System.currentTimeMillis(). Your application needs to be consistent: either you use a real time clock or you use the pseudo-clock.

  • Minor fix: you should use the public interface SessionPseudoClock instead of the internal implementation class PseudoClockScheduler. Same thing with the internal class EventFactHandle that I assume you are using just for the test as your application should never need to use that.

  • Finally, I am not sure what you are trying to achieve with this example. Your message class timestamp and duration will be read from the class attributes as your example tells the engine to:

    declare Message @role(event) @timestamp(time) @duration(howMuch) end

Drools will not deliberately change attributes (like howMuch) if that is what you were expecting.

I suggest you take another look at the Drools Fusion documentation and join the Drools mailing list. People are very helpful there and can help you with any follow up questions you might have.

Edson Tirelli
  • 3,891
  • 20
  • 23
  • Thank you @Edson a lot for this answer. Probably I tried so many time to make this example working that I leave some dirt code. message.setTime(System.currentTimeMillis()); is because I was unable to make drools changing in this parameter automatically (as I had understood it should do) – Alberto Rugnone Feb 16 '12 at 09:09
  • From your answer I understand that is not what Drools Fusion is expected to do. The developer instead has to set and to make changes to these parameters. Then he can declare to Drools the event in order to make Drools able to calculate window slicing and other timed operators. Is it correct? – Alberto Rugnone Feb 16 '12 at 09:27
  • However, I take an other look to "Drools fusion feature" document included with Drools 5.3. Final distribution. In this document, at section 2.1.3.2 about '@timestamp', It says "By default, the timestamp for a vigen event is read from session Clock and assigned to the event at the time the event is inserted into working memory". It seems to me not true,then? Or maybe, am I misunderstanding? Again, how I can make drools calculating timestamp, duration etc about event when they are inserted? Is it possible? – Alberto Rugnone Feb 16 '12 at 09:27
  • Thank you again for you answer and also for your reply :) I will follow also your tips, asking to the forum. Alberto :) – Alberto Rugnone Feb 16 '12 at 09:27
  • The documentation is correct. If you don't define a @timestamp attribute, Drools will assign the object one based on the session clock. In any case, this assignment is an internal operation and Drools will never change a fact/event attribute by itself, as it would be wrong. – Edson Tirelli Feb 16 '12 at 15:21