我正在尝试编写一条规则来检测某个特定事件是否在最后'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 从工作内存中删除已处理的事实。但是当我在规则的然后部分添加了撤消时,规则就停止了。在添加撤消之后,我无法弄清楚为什么规则会停止触发。
请告诉我哪里出错了。
答案 0 :(得分:0)
您似乎忘记将列表中的其他3个事实设置为已处理。你需要一个辅助类作为全局,因为它应该在for循环中完成。否则,这些消息组也可以触发规则:
1没有触发 1,2没有触发 1,2,3触发器 2,3,4触发因为添加了新事实,列表中有2个和3个 3,4,5触发因为添加了新事实而列表中有3和4
等等
希望这会有所帮助