[rules-users] Monitoring applications using Drools
Wolfgang Laun
wolfgang.laun at gmail.com
Wed Jun 4 11:31:03 EDT 2014
Your code does:
insert 1st event
delay 1 minute
insert 2nd event
delay 1 minute
insert 3rd event
delay 1 minute
delay (1 or) 2 minutes
fire all rules
In the second case, 5 minutes have elapsed since the 1st insert. I
don't think that this means "that [the 1st insert] falls well within
the specified time range" - it is exactly at the beginning of the
window, and I'd expect the window to be an interval open at one end -
otherwise events smack on the point in time "separating" two intervals
would be in both windows.
-W
On 04/06/2014, Sushant Goyal <sushantgoyal25 at yahoo.co.in> wrote:
> Hi,
>
> I am
> trying to understand how Drools can be used to monitor events over a period
> of
> time using Sliding Time Windows. I have created a rule to sound an alarm
> when
> average temperature read from a sensor is above 25 degrees (threshold) over
> a
> time period of 5 minutes. The rule makes of use of the Stream processing
> mode so
> that continuous stream of events could be processed.
>
> Below
> is how my rule looks like:
>
> //declare any global
> variables here
> globaljava.lang.StringBuilder alertMessage
>
> // add declaration to
> change the Fact into an Event
> declareSensorReading
> @role(event)
> end
>
> /* Alert when average
> temperature is above 25
> over a time period of 5 minutes */
> rule"TemperatureAlarm1"
>
> when
> //conditions
> $averageTemp : Number(doubleValue >
> 25.00)
> fromaccumulate(SensorReading($temp
> : temperature)
> over
> window:time(5m) fromentry-point "Temperature Reading", average($temp))
> then
> //actions
> System.out.println("Fired rule:
> "+
> kcontext.getRule().getName());
> alertMessage.append("Threshold
> temperature breached!!"+
> "\nTurn on the
> Air Conditioner"+
> "\nAverage
> temperature over 5 minutes is above 25 ("+ $averageTemp.intValue() + ")\n");
>
> end
>
> And below
> is the snapshot of the fact (SensorReading) which is inserted as an event in
> the working memory:
>
> publicclassSensorReading {
>
> privatedoubletemperature;
>
> publicSensorReading(){}
>
> publicSensorReading(doubletemp){
> this.temperature= temp;
> }
>
> // getters and setters
> }
>
>
> In
> order to test the rule, I am using Pseudo Clock with Stream processing
> turned
> on. I am inserting three SensorReading objects in the working memory with
> temperature
> values as (24, 26, 28) after every minute, so that the average of the
> temperatures is above threshold and the rule is invoked. After the objects
> are
> inserted in the working memory, I am deliberately advancing the Pseudo clock
> by
> another 1 minute, so that the total time elapsed is 4 minutes. The rule
> works
> as expected with the above test setup and prints the average value as 26 on
> the
> console.
>
> However,
> if I advance the clock by 2 minutes instead of 1 minute after three sensor
> reading objects have been inserted in the working memory (after every 1
> minute
> interval), the rule gets invoked but the average value gets changed to 27
> (26 +
> 28 / 2 == 27). Looks like the first temperature reading is getting ignored
> by
> the rule despite the fact that it falls well within the specified time range
> of
> 5 minutes. Below is the snapshot of my test class:
>
> publicclassTemperatureAlarmTest
> {
>
> staticKnowledgeBase kbase;
> staticStatefulKnowledgeSession ksession;
> staticKnowledgeRuntimeLogger logger;
> staticSessionPseudoClock clock;
>
> @BeforeClass
> publicstaticvoidsetupKsession() {
> try{
> // load up the
> knowledge base
> kbase= readKnowledgeBase();
> ksession= readKnowldedeSession(kbase);
> clock= ksession.getSessionClock();
>
> logger=
> KnowledgeRuntimeLoggerFactory.newThreadedFileLogger(ksession, "log/Errors",
> 500);
>
> } catch(Throwable t) {
> t.printStackTrace();
> }
> }
>
> /**
> *
> Create a new Stateful knowledge Session with a pseudo clock from the
> *
> knowledge base
> *
> * @paramkbase
> * @return
> * @throwsException
> */
> privatestaticStatefulKnowledgeSession readKnowldedeSession(
> KnowledgeBase kbase) throwsException {
>
> // Knowledge Session Configuration
> KnowledgeSessionConfiguration
> config = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
> config.setOption(ClockTypeOption.get("pseudo"));
> returnkbase.newStatefulKnowledgeSession(config, null);
>
> }
>
> @AfterClass
> publicstaticvoidcloseKsession() {
> try{
> // load up the
> knowledge base
> logger.close();
> ksession.dispose();
>
> } catch(Throwable t) {
> t.printStackTrace();
> }
> }
>
> @Test
> publicvoidTemperatureAlarm1_Test() {
>
> // Create Temperature list
> ArrayList<SensorReading>
> tempMetrics = newArrayList<SensorReading>();
> doubletemp = 24.00;
>
> while(tempMetrics.size()
> < 3) {
> tempMetrics.add(newSensorReading(temp));
> temp += 2;
> }
> System.out.println("Size of
> tempMetrics List: "+tempMetrics.size()+"\n");
> System.out.println("First Temp
> reading: "+tempMetrics.get(0).getTemperature());
> System.out.println("Second Temp
> reading: "+tempMetrics.get(1).getTemperature());
> System.out.println("Third Temp
> reading: "+tempMetrics.get(2).getTemperature()+"\n");
>
> // Separate stream for inserts
> WorkingMemoryEntryPoint
> temperatureStream = ksession.getWorkingMemoryEntryPoint( "Temperature
> Reading");
>
> // Create fact handle list
> ArrayList<FactHandle>
> factHandleList = newArrayList<FactHandle>();
>
> // Insert objects into working
> memory while advancing the clock
> for(inti = 0; i <
> tempMetrics.size(); i++) {
>
> factHandleList.add(temperatureStream.insert(tempMetrics.get(i)));
> clock.advanceTime(1,
> TimeUnit.MINUTES);
> System.out.println("Time advances
> by 1 minute");
> }
> System.out.println("Fact Count
> is: "+temperatureStream.getFactCount());
> System.out.println("Fact Entry
> Point is: "+temperatureStream.getEntryPointId());
> System.out.println("Size of
> FactHandleList: "+factHandleList.size()+"\n");
>
> clock.advanceTime(1,
> TimeUnit.MINUTES); //change in
> advanced time alters the rule behavior
>
> StringBuilder stringBuilder = newStringBuilder();
> ksession.setGlobal("alertMessage", stringBuilder);
> ksession.fireAllRules();
>
> // Remove facts
> for(inti = 0; i <
> factHandleList.size(); i++) {
> temperatureStream.retract(factHandleList.get(i));
> }
> System.out.println("After
> Removing facts");
> System.out.println("Fact Count
> is: "+temperatureStream.getFactCount());
>
> String result =
> stringBuilder.substring(0, 32);
> System.out.println("Alert Message
> is: \n"+ stringBuilder.toString());
> assertEquals("Alert Message
> is: ", "Threshold
> temperature breached!!", result);
> }
>
> /**
> *
> Create the knowledge base with stream processing turned on.
> *
> * @return
> * @throwsException
> */
> privatestaticKnowledgeBase
> readKnowledgeBase() throwsException {
> KnowledgeBuilder kbuilder =
> KnowledgeBuilderFactory.newKnowledgeBuilder();
>
> kbuilder.add(ResourceFactory.newClassPathResource("TemperatureAlarm1.drl"),ResourceType.DRL);
> hasErrors(kbuilder);
>
> // Stream processing turned on
> KnowledgeBaseConfiguration conf =
> KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
> conf.setOption(EventProcessingOption.STREAM);
> KnowledgeBase kbase =
> KnowledgeBaseFactory.newKnowledgeBase(conf);
> hasErrors(kbuilder);
> kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
>
> returnkbase;
> }
>
> /**
> *
> Report errors if any
> *
> * @paramkbuilder
> * @throwsException
> */
> privatestaticvoidhasErrors(KnowledgeBuilder kbuilder) throwsException
> {
> KnowledgeBuilderErrors errors =
> kbuilder.getErrors();
> if(errors.size() > 0) {
> for(KnowledgeBuilderError error : errors) {
> System.err.println(error);
> }
> thrownewIllegalArgumentException("Could not parse
> knowledge.");
> }
>
> }
>
> }
>
>
> Could
> anyone please help explain this change in the behavior of the rule?
>
> Regards,
> Sushant
More information about the rules-users
mailing list