3 次后未触发 Drools 规则
Drools rules is not being fired after 3 times
我创建了一个知识库,然后循环使用知识库创建
- 无状态知识会话
- 并在会话上调用执行,每次迭代使用相同的数据。
-----这里是主要功能------
public static final void main(String[] args)
{
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("diskRules.drl"), ResourceType.DRL);
if (kbuilder.hasErrors())
{
System.err.println(kbuilder.getErrors().toString());
}
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
CollectorPluginData cpd = getData();
for (int i = 0; i < 10; i++)
{
System.out.println("Iteration number: " + i);
StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
ksession.execute(cpd);
}
------------这里是drl文件
rule "Disk State: Unconfigured Bad-ERROR"
when
$diskData : CollectorPluginData(pluginName == "DiskCollectorPlugin", $componentList : componentList)
$component: Component( type == "Disk"
&& ((properties contains "eventType" && properties["eventType"] == "PD Event"
&& properties contains "newComponentState"&& properties["newComponentState"] == "Unconfigured Bad")
|| (properties contains "scsiDeviceType" && properties["scsiDeviceType"] == "Disk"
&& properties contains "currentComponentState" && properties["currentComponentState"] == "Unconfigured Bad"))
) from $componentList
then
System.out.println("Rule Fired");
end
rule "Disk State: Unconfigured Bad-OK"
when
$diskData : CollectorPluginData(pluginName == "DiskCollectorPlugin", $componentList : componentList)
$component: Component( type == "Disk"
&& ((properties contains "eventType" && properties["eventType"] == "PD Event"
&& properties contains "newComponentState"&& properties["newComponentState"] != "Unconfigured Bad")
|| (properties contains "scsiDeviceType" && properties["scsiDeviceType"] == "Disk"
&& properties contains "currentComponentState" && properties["currentComponentState"] != "Unconfigured Bad"))
) from $componentList
then
System.out.println("Rule Fired");
end
至于每次迭代都使用相同的数据来执行会话,因此预计会执行相同的规则集,但我观察到在一些迭代之后没有规则被触发。
这是每次迭代的控制台输出:
Iteration number: 0
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Iteration number: 1
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Iteration number: 2
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Iteration number: 3
Iteration number: 4
Iteration number: 5
Iteration number: 6
Iteration number: 7
Iteration number: 8
Iteration number: 9
一些观察:
在每条规则中我都有 $componentList 用于匹配,当我们减少组件列表中的组件数量时,需要更多的迭代才能达到没有规则被触发的情况。
当我们将规则文件中的条件更改为简单(如下所述)时,每次迭代都会生成相同的输出。
$component: 来自 $componentList
的组件(类型 == "Disk")
这看起来像是流口水、某种内存或数据结构损坏的问题。
我也尝试过有状态会话,看到了相同的行为。
我在这里遗漏了什么吗?我的理解是知识库是只读的,我们可以从中创建任意数量的会话。
这里使用的是 5.6.0.Final 版本,也尝试过使用 drools 6.1.0,但看到了相同的行为。
我因这个问题而陷入困境,将不胜感激任何帮助。
如果您想重现此问题,遵循 class 定义将有所帮助
MainClass.java
package com.test
import com.test.CollectorPluginData;
import com.test.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseFactory;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.ResourceFactory;
import org.drools.runtime.StatelessKnowledgeSession;
public class MainClass
{
public static final void main(String[] args)
{
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("diskRules.drl"), ResourceType.DRL);
if (kbuilder.hasErrors())
{
System.err.println(kbuilder.getErrors().toString());
}
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
CollectorPluginData cpd = getData();
for (int i = 0; i < 10; i++)
{
System.out.println("Iteration number: " + i);
StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
ksession.execute(cpd);
}
}
public static CollectorPluginData getData()
{
CollectorPluginData cpd = new CollectorPluginData();
cpd.setPluginName("DiskCollectorPlugin");
List<Component> components = getDiskComponets("Online", 5);
components.addAll(getDiskComponets("Unconfigured Good", 5));
components.addAll(getDiskComponets("Unconfigured Bad", 5));
components.addAll(getDiskComponets("Offline", 5));
components.addAll(getDiskComponets("Failed", 5));
cpd.setComponentList(components);
return cpd;
}
private static List<Component> getDiskComponets(String status, int num)
{
List<Component> components = new ArrayList<Component>();
int enclosure = new Random().nextInt();
for (int i = 0; i < num; i++)
{
Component c = new Component();
c.setType("Disk");
c.setName("Enclosure " + enclosure + " Disk " + String.valueOf(i + 1));
c.setId(enclosure + "_" + String.valueOf(i + 1));
c.setproperty("isSupported", 1);
c.setproperty("pdMediaType", "Rotating Media, HDD");
c.setproperty("mediaErrorCount", 0);
c.setproperty("scsiDeviceType", "Disk");
c.setproperty("lastFailedPredEventSeqNum", 0);
c.setproperty("currentComponentState", status);
c.setproperty("otherErrorCount", 0);
c.setproperty("isGlobalHotSpare", 0);
c.setproperty("isForcedPdGuid", 0);
c.setproperty("maxSupportedSpeed", "6G");
c.setproperty("isDedicatedHotSpare", 0);
c.setproperty("isForeign", 0);
c.setproperty("predFailCount", 0);
c.setproperty("driveReadyForRemoval", 0);
c.setproperty("linkSpeed", 3);
c.setproperty("isPdInVd", 0);
c.setproperty("pdDeviceType", "SAS");
c.setproperty("rawSize", 1953525168);
c.setproperty("enclosureId", 252);
c.setproperty("nonCoercedSize", 1952476592);
c.setproperty("coercedSize", 1951170560);
c.setproperty("temperatureInCelsius", 255);
c.setproperty("slotNumber", 2);
c.setproperty("pdPowerState", "Spun Down");
c.setproperty("shieldCounter", 0);
c.setproperty("shieldDiagCompletionTime", "0000-00-00T00:00:00");
components.add(c);
}
return components;
}
}
Component.java
package com.test;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import java.util.HashMap;
import java.util.Map;
public class Component
{
protected String type;
protected String id;
protected String name;
protected Map<String, Object> properties;
public String getType()
{
return type;
}
public void setType(String type)
{
this.type = type;
}
public Map<String, Object> getProperties()
{
return properties;
}
public void setProperties(Map<String, Object> properties)
{
this.properties = properties;
}
public void setproperty(String key, Object value)
{
if (this.properties == null)
{
this.properties = new HashMap<String, Object>();
}
this.properties.put(key, value);
}
public Component()
{
super();
}
public Component(String type, String id, int status)
{
this.type = type;
this.id = id;
setproperty("status", status);
}
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
CollectorPluginData.java
package com.test;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import java.util.ArrayList;
import java.util.List;
public class CollectorPluginData
{
private String pluginName;
private String timeStamp;
private String hostName;
private String serialNumber;
private String model;
private List<Component> componentList;
public String getSerialNumber()
{
return serialNumber;
}
public void setSerialNumber(String serialNumber)
{
this.serialNumber = serialNumber;
}
public String getModel()
{
return model;
}
public void setModel(String model)
{
this.model = model;
}
public String getHostName()
{
return hostName;
}
public void setHostName(String hostName)
{
this.hostName = hostName;
}
public String getPluginName()
{
return pluginName;
}
public void setPluginName(String pluginName)
{
this.pluginName = pluginName;
}
public String getTimeStamp()
{
return timeStamp;
}
public void setTimeStamp(String timeStamp)
{
this.timeStamp = timeStamp;
}
public List<Component> getComponentList()
{
return componentList;
}
public void setComponentList(List<Component> componentList)
{
this.componentList = componentList;
}
public void addComponent(Component component)
{
if (componentList == null)
{
componentList = new ArrayList<Component>();
}
componentList.add(component);
}
}
确实是个bug。
问题在于 "contains" 的使用:Drools (MVEL) 非常自由
假设 properties contains "X"
应该被解释为 properties.containsKey("X")
。
但是,在一些迭代之后,约束的即时编译会强制执行更严格的模式,在这种模式下,无法正确评估前一个表达式。
我们将讨论最佳解决方案是什么。在任何情况下,我都建议使用 properties.containsKey
... 或者甚至删除包含检查,因为当键不存在时,地图访问器将只是 return null。
我创建了一个知识库,然后循环使用知识库创建
- 无状态知识会话
- 并在会话上调用执行,每次迭代使用相同的数据。
-----这里是主要功能------
public static final void main(String[] args)
{
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("diskRules.drl"), ResourceType.DRL);
if (kbuilder.hasErrors())
{
System.err.println(kbuilder.getErrors().toString());
}
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
CollectorPluginData cpd = getData();
for (int i = 0; i < 10; i++)
{
System.out.println("Iteration number: " + i);
StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
ksession.execute(cpd);
}
------------这里是drl文件
rule "Disk State: Unconfigured Bad-ERROR"
when
$diskData : CollectorPluginData(pluginName == "DiskCollectorPlugin", $componentList : componentList)
$component: Component( type == "Disk"
&& ((properties contains "eventType" && properties["eventType"] == "PD Event"
&& properties contains "newComponentState"&& properties["newComponentState"] == "Unconfigured Bad")
|| (properties contains "scsiDeviceType" && properties["scsiDeviceType"] == "Disk"
&& properties contains "currentComponentState" && properties["currentComponentState"] == "Unconfigured Bad"))
) from $componentList
then
System.out.println("Rule Fired");
end
rule "Disk State: Unconfigured Bad-OK"
when
$diskData : CollectorPluginData(pluginName == "DiskCollectorPlugin", $componentList : componentList)
$component: Component( type == "Disk"
&& ((properties contains "eventType" && properties["eventType"] == "PD Event"
&& properties contains "newComponentState"&& properties["newComponentState"] != "Unconfigured Bad")
|| (properties contains "scsiDeviceType" && properties["scsiDeviceType"] == "Disk"
&& properties contains "currentComponentState" && properties["currentComponentState"] != "Unconfigured Bad"))
) from $componentList
then
System.out.println("Rule Fired");
end
至于每次迭代都使用相同的数据来执行会话,因此预计会执行相同的规则集,但我观察到在一些迭代之后没有规则被触发。
这是每次迭代的控制台输出:
Iteration number: 0
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Iteration number: 1
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Iteration number: 2
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Rule Fired
Iteration number: 3
Iteration number: 4
Iteration number: 5
Iteration number: 6
Iteration number: 7
Iteration number: 8
Iteration number: 9
一些观察:
在每条规则中我都有 $componentList 用于匹配,当我们减少组件列表中的组件数量时,需要更多的迭代才能达到没有规则被触发的情况。
当我们将规则文件中的条件更改为简单(如下所述)时,每次迭代都会生成相同的输出。
$component: 来自 $componentList
的组件(类型 == "Disk")
这看起来像是流口水、某种内存或数据结构损坏的问题。
我也尝试过有状态会话,看到了相同的行为。
我在这里遗漏了什么吗?我的理解是知识库是只读的,我们可以从中创建任意数量的会话。
这里使用的是 5.6.0.Final 版本,也尝试过使用 drools 6.1.0,但看到了相同的行为。
我因这个问题而陷入困境,将不胜感激任何帮助。
如果您想重现此问题,遵循 class 定义将有所帮助
MainClass.java
package com.test
import com.test.CollectorPluginData;
import com.test.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseFactory;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.ResourceFactory;
import org.drools.runtime.StatelessKnowledgeSession;
public class MainClass
{
public static final void main(String[] args)
{
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("diskRules.drl"), ResourceType.DRL);
if (kbuilder.hasErrors())
{
System.err.println(kbuilder.getErrors().toString());
}
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
CollectorPluginData cpd = getData();
for (int i = 0; i < 10; i++)
{
System.out.println("Iteration number: " + i);
StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
ksession.execute(cpd);
}
}
public static CollectorPluginData getData()
{
CollectorPluginData cpd = new CollectorPluginData();
cpd.setPluginName("DiskCollectorPlugin");
List<Component> components = getDiskComponets("Online", 5);
components.addAll(getDiskComponets("Unconfigured Good", 5));
components.addAll(getDiskComponets("Unconfigured Bad", 5));
components.addAll(getDiskComponets("Offline", 5));
components.addAll(getDiskComponets("Failed", 5));
cpd.setComponentList(components);
return cpd;
}
private static List<Component> getDiskComponets(String status, int num)
{
List<Component> components = new ArrayList<Component>();
int enclosure = new Random().nextInt();
for (int i = 0; i < num; i++)
{
Component c = new Component();
c.setType("Disk");
c.setName("Enclosure " + enclosure + " Disk " + String.valueOf(i + 1));
c.setId(enclosure + "_" + String.valueOf(i + 1));
c.setproperty("isSupported", 1);
c.setproperty("pdMediaType", "Rotating Media, HDD");
c.setproperty("mediaErrorCount", 0);
c.setproperty("scsiDeviceType", "Disk");
c.setproperty("lastFailedPredEventSeqNum", 0);
c.setproperty("currentComponentState", status);
c.setproperty("otherErrorCount", 0);
c.setproperty("isGlobalHotSpare", 0);
c.setproperty("isForcedPdGuid", 0);
c.setproperty("maxSupportedSpeed", "6G");
c.setproperty("isDedicatedHotSpare", 0);
c.setproperty("isForeign", 0);
c.setproperty("predFailCount", 0);
c.setproperty("driveReadyForRemoval", 0);
c.setproperty("linkSpeed", 3);
c.setproperty("isPdInVd", 0);
c.setproperty("pdDeviceType", "SAS");
c.setproperty("rawSize", 1953525168);
c.setproperty("enclosureId", 252);
c.setproperty("nonCoercedSize", 1952476592);
c.setproperty("coercedSize", 1951170560);
c.setproperty("temperatureInCelsius", 255);
c.setproperty("slotNumber", 2);
c.setproperty("pdPowerState", "Spun Down");
c.setproperty("shieldCounter", 0);
c.setproperty("shieldDiagCompletionTime", "0000-00-00T00:00:00");
components.add(c);
}
return components;
}
}
Component.java
package com.test;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import java.util.HashMap;
import java.util.Map;
public class Component
{
protected String type;
protected String id;
protected String name;
protected Map<String, Object> properties;
public String getType()
{
return type;
}
public void setType(String type)
{
this.type = type;
}
public Map<String, Object> getProperties()
{
return properties;
}
public void setProperties(Map<String, Object> properties)
{
this.properties = properties;
}
public void setproperty(String key, Object value)
{
if (this.properties == null)
{
this.properties = new HashMap<String, Object>();
}
this.properties.put(key, value);
}
public Component()
{
super();
}
public Component(String type, String id, int status)
{
this.type = type;
this.id = id;
setproperty("status", status);
}
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
CollectorPluginData.java
package com.test;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import java.util.ArrayList;
import java.util.List;
public class CollectorPluginData
{
private String pluginName;
private String timeStamp;
private String hostName;
private String serialNumber;
private String model;
private List<Component> componentList;
public String getSerialNumber()
{
return serialNumber;
}
public void setSerialNumber(String serialNumber)
{
this.serialNumber = serialNumber;
}
public String getModel()
{
return model;
}
public void setModel(String model)
{
this.model = model;
}
public String getHostName()
{
return hostName;
}
public void setHostName(String hostName)
{
this.hostName = hostName;
}
public String getPluginName()
{
return pluginName;
}
public void setPluginName(String pluginName)
{
this.pluginName = pluginName;
}
public String getTimeStamp()
{
return timeStamp;
}
public void setTimeStamp(String timeStamp)
{
this.timeStamp = timeStamp;
}
public List<Component> getComponentList()
{
return componentList;
}
public void setComponentList(List<Component> componentList)
{
this.componentList = componentList;
}
public void addComponent(Component component)
{
if (componentList == null)
{
componentList = new ArrayList<Component>();
}
componentList.add(component);
}
}
确实是个bug。
问题在于 "contains" 的使用:Drools (MVEL) 非常自由
假设 properties contains "X"
应该被解释为 properties.containsKey("X")
。
但是,在一些迭代之后,约束的即时编译会强制执行更严格的模式,在这种模式下,无法正确评估前一个表达式。
我们将讨论最佳解决方案是什么。在任何情况下,我都建议使用 properties.containsKey
... 或者甚至删除包含检查,因为当键不存在时,地图访问器将只是 return null。