2

我正在尝试编写一个规则来检测给定事件是否在最后“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 秒内发生的确切 LogMessage 集。

问题是,一旦处理了这些消息,它们就不应参与下一个评估周期。这是我无法实现的。我将举例说明这一点。

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

预期结果

-- 日志 -- 警报

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从其工作记忆中删除已处理的事实。但是当我在规则的then部分添加retract 时,规则完全停止触发。我无法弄清楚为什么添加retract后规则停止触发。

请让我知道我哪里出错了。

4

1 回答 1

0

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

1 无触发 1,2 无触发 1,2,3 触发 2,3,4 触发,因为添加了新事实,2 和 3 在列表中 3,4,5 触发,因为添加了新事实,3 和 4在列表中

等等

希望这可以帮助

于 2013-08-01T16:03:42.850 回答