我正在尝试编写一个规则来检测给定事件是否在最后“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后规则停止触发。
请让我知道我哪里出错了。