在当时的规则条件下使用撤消的问题

时间:2013-02-28 21:54:08

标签: drools drools-fusion

我正在尝试编写一条规则来检测某个特定事件是否在最后'm'持续时间内发生'n'次。 我正在使用drools版本5.4.Final。我也试过5.5.Final没有效果。

我发现有几个条件元素,因为Drools称之为,累积和收集。我在下面的示例规则中使用了收集

rule "check-login-attack-rule-1"
dialect "java"
when
    $logMessage: LogMessage()
    $logMessages : ArrayList ( size >= 3 ) 
                    from collect(LogMessage(getAction().equals(Action.Login) 
                    && isProcessed() == false) 
                    over window:time(10s))
then
    LogManager.debug(Poc.class, "!!!!! Login Attack detected. Generating alert.!!!"+$logMessages.size());
    LogManager.debug(Poc.class, "Current Log Message: "+$logMessage.getEventName()+":"+(new Date($logMessage.getTime())));
    int size = $logMessages.size();
    for(int i = 0 ; i < size; i++) {
        Object msgObj = $logMessages.get(i);
        LogMessage msg = (LogMessage) msgObj;
        LogManager.debug(Poc.class, "LogMessage: "+msg.getEventName()+":"+(new Date(msg.getTime())));
        msg.setProcessed(true);
        update(msgObj); // Does not work. Rule execution does not proceed beyond this point.
        // retract(msgObj) // Does not work. Rule execution does not proceed beyond this point.
    }
    // Completed processing the logs over a given window. Now removing the processed logs.
    //retract($logMessages) // Does not work. Rule execution does not proceed beyond this point.

注入日志的代码如下。该代码每3秒注入一次日志并触发规则。

        final StatefulKnowledgeSession kSession = kBase.newStatefulKnowledgeSession();
        long msgId = 0;
        while(true) {
            // Generate Log messages every 3 Secs.
            // Every alternate log message will satisfy a rule condition
            LogMessage log = null;
            log = new LogMessage();
            log.setEventName("msg:"+msgId);
            log.setAction(LogMessage.Action.Login);
            LogManager.debug(Poc.class, "PUSHING LOG: "+log.getEventName()+":"+log.getTime());
            kSession.insert(log);
            kSession.fireAllRules();
            LogManager.debug(Poc.class, "PUSHED LOG: "+log.getEventName()+":"+(new Date(log.getTime())));
            // Sleep for 3 secs
            try {
                sleep(3*1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            msgId++;
        }

有了这个,我能够实现的是在过去10秒内检查上述LogMessage是否存在。我还可以找出触发规则的最后10秒内发生的确切LogMessages集。

问题是,一旦这些消息被处理,他们就不应该参与下一个评估周期。这是我无法实现的。我将以示例解释这一点。

考虑下面的时间表,时间表显示日志消息的插入以及应该发生的警报生成状态。

预期结果

- 记录 - 提醒

0 - LogMessage1 - 无警报

3 - LogMessage2 - 无警报

6 - LogMessage3 - Alert1(LogMessage1,LogMessage2,LogMessage3)

9 - LogMessage4 - 无警报

12 - LogMessage5 - 无警报

15 - LogMessage6 - Alert2(LogMessage4,LogMessage5,LogMessage6)

但是当前代码发生了什么?

实际结果

- 记录 - 提醒

0 - LogMessage1 - 无警报

3 - LogMessage2 - 无警报

6 - LogMessage3 - Alert1(LogMessage1,LogMessage2,LogMessage3)

9 - LogMessage4 - Alert2(LogMessage2,LogMessage3,LogMessage4)

12 - LogMessage5 - Alert3(LogMessage3,LogMessage4,LogMessage5)

15 - LogMessage6 - Alert4(LogMessage4,LogMessage5,LogMessage6)

基本上,我无法丢弃已处理并参与警报生成的消息。我尝试使用 retract 从工作内存中删除已处理的事实。但是当我在规则的然后部分添加了撤消时,规则就停止了。在添加撤消之后,我无法弄清楚为什么规则会停止触发。

请告诉我哪里出错了。

1 个答案:

答案 0 :(得分:0)

您似乎忘记将列表中的其他3个事实设置为已处理。你需要一个辅助类作为全局,因为它应该在for循环中完成。否则,这些消息组也可以触发规则:

1没有触发 1,2没有触发 1,2,3触发器 2,3,4触发因为添加了新事实,列表中有2个和3个 3,4,5触发因为添加了新事实而列表中有3和4

等等

希望这会有所帮助