英文:
How to fix a non-firing rule in drools
问题
我正在尝试学习Drools。以下是代码 - 尽管调用了fireAllRules
,但规则没有触发。
Product类
package com.abc.main;
public class Product {
private String RegionName = "South";
private String CouponCode = "A";
public String getType() {
return RegionName;
}
public void setType(String regionName) {
this.RegionName = regionName;
}
public String getCouponCode() {
return CouponCode;
}
public void setCouponCode(String couponCode) {
this.CouponCode = couponCode;
}
}
Rules.drl文件
package com.abc.main;
import com.abc.main.Product;
rule "Offer for Diamond"
when
productObject: Product(RegionName=="South")
then
productObject.setCouponCode("B");
end
rule "Offer for Gold"
when
productObject: Product(RegionName=="North")
then
productObject.setCouponCode("C");
end
Class6(测试类)
package com.abc.main;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.drools.compiler.compiler.DroolsParserException;
import org.drools.compiler.compiler.PackageBuilder;
import org.drools.core.RuleBase;
import org.drools.core.RuleBaseFactory;
import org.drools.core.WorkingMemory;
public class Class6 {
public static void main(String[] args) throws DroolsParserException, IOException
{
Class6 droolsTest = new Class6();
System.out.println("Reached point 1A");
droolsTest.executeDrools2();
}
public void executeDrools2() throws DroolsParserException, IOException
{
System.out.println("Reached point 2J");
PackageBuilder packageBuilder = new PackageBuilder();
String ruleFile = "Rules.drl";
InputStream resourceAsStream = getClass().getResourceAsStream(ruleFile);
System.out.println("Reached point 3");
String result = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8);
System.out.println("Reached point 3b - " + result);
System.out.println("Reached point 3C");
Reader reader = new InputStreamReader(resourceAsStream);
System.out.println("Reached point 4K");
packageBuilder.addPackageFromDrl(reader);
System.out.println("Reached point 5");
org.drools.core.rule.Package rulesPackage = packageBuilder.getPackage();
RuleBase ruleBase = RuleBaseFactory.newRuleBase();
ruleBase.addPackage(rulesPackage);
WorkingMemory workingMemory = ruleBase.newStatefulSession();
Product product = new Product();
product.setType("South");
System.out.println("Original product " + product.getType()+ "'s coupon code is " + product.getCouponCode());
//Working Memory
workingMemory.insert(product);
workingMemory.fireAllRules();
System.out.println("The coupon code for the product " + product.getType() + " is " + product.getCouponCode());
}
}
尽管我在内存中添加了事实和规则,但规则似乎没有通过“fireAllRules”调用触发。如何使此规则触发?是stateful
会话(使用“newStatefulSession”)导致了这个问题吗?
英文:
I am trying to learn drools. Following is the code – and the rule is not firing though fireAllRules is called .
Product class
package com.abc.main;
public class Product {
private String RegionName = "South";
private String CouponCode = "A";
public String getType() {
return RegionName;
}
public void setType(String regionName) {
this.RegionName = regionName;
}
public String getCouponCode() {
return CouponCode;
}
public void setCouponCode(String couponCode) {
this.CouponCode = couponCode;
}
}
Rules.drl file
package com.abc.main;
import com. abc.main.Product
rule "Offer for Diamond"
when
productObject: Product(RegionName=="South")
then
productObject.setCouponCode("B");
end
rule "Offer for Gold"
when
productObject: Product(RegionName=="North")
then
productObject.setCouponCode("C");
end
Class6 (Test class)
package com.abc.main;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.drools.compiler.compiler.DroolsParserException;
import org.drools.compiler.compiler.PackageBuilder;
import org.drools.core.RuleBase;
import org.drools.core.RuleBaseFactory;
import org.drools.core.WorkingMemory;
public class Class6 {
public static void main(String[] args) throws DroolsParserException,IOException
{
Class6 droolsTest = new Class6();
System.out.println("Reached point 1A");
droolsTest.executeDrools2();
}
public void executeDrools2() throws DroolsParserException, IOException
{
System.out.println("Reached point 2J");
PackageBuilder packageBuilder = new PackageBuilder();
String ruleFile = "Rules.drl";
InputStream resourceAsStream = getClass().getResourceAsStream(ruleFile);
System.out.println("Reached point 3");
String result = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8);
System.out.println("Reached point 3b - " + result);
System.out.println("Reached point 3C");
Reader reader = new InputStreamReader(resourceAsStream);
System.out.println("Reached point 4K");
packageBuilder.addPackageFromDrl(reader);
System.out.println("Reached point 5");
org.drools.core.rule.Package rulesPackage = packageBuilder.getPackage();
RuleBase ruleBase = RuleBaseFactory.newRuleBase();
ruleBase.addPackage(rulesPackage);
WorkingMemory workingMemory = ruleBase.newStatefulSession();
Product product = new Product();
product.setType("South");
System.out.println("Original product " + product.getType()+ "'s coupon code is " + product.getCouponCode());
//Working Memory
workingMemory.insert(product);
workingMemory.fireAllRules();
System.out.println("The coupon code for the product " + product.getType() + " is " + product.getCouponCode());
}
}
Output
Though I added the fact and rule in memory, looks like the rules are not fired with “fireAllRules” call. How to make this rule firing? Is the stateful
session causing this issue (with “newStatefulSession” ) ?
答案1
得分: 2
我认为您的代码是基于这个示例编写的。
在审查了两个代码片段后,我认为您的代码问题与以下与调试相关的代码片段有关:
System.out.println("Reached point 3");
String result = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8);
System.out.println("Reached point 3b - " + result);
System.out.println("Reached point 3C");
请注意,使用该代码片段会消耗指向在此处获取的规则定义文件的InputStream
:
String ruleFile = "Rules.drl";
InputStream resourceAsStream = getClass().getResourceAsStream(ruleFile);
因此,当运行此代码片段时,您的规则包不会关联任何规则:
Reader reader = new InputStreamReader(resourceAsStream);
System.out.println("Reached point 4K");
packageBuilder.addPackageFromDrl(reader);
这导致了您稍后尝试激活规则时看到的错误行为。
请根据上述说明解决问题,考虑注释掉调试代码片段:
package com.abc.main;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.drools.compiler.compiler.DroolsParserException;
import org.drools.compiler.compiler.PackageBuilder;
import org.drools.core.RuleBase;
import org.drools.core.RuleBaseFactory;
import org.drools.core.WorkingMemory;
public class Class6 {
public static void main(String[] args) throws DroolsParserException,IOException
{
Class6 droolsTest = new Class6();
System.out.println("Reached point 1A");
droolsTest.executeDrools2();
}
public void executeDrools2() throws DroolsParserException, IOException
{
System.out.println("Reached point 2J");
PackageBuilder packageBuilder = new PackageBuilder();
String ruleFile = "Rules.drl";
InputStream resourceAsStream = getClass().getResourceAsStream(ruleFile);
/*System.out.println("Reached point 3");
String result = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8);
System.out.println("Reached point 3b - " + result);
System.out.println("Reached point 3C");*/
Reader reader = new InputStreamReader(resourceAsStream);
System.out.println("Reached point 4K");
packageBuilder.addPackageFromDrl(reader);
System.out.println("Reached point 5");
org.drools.core.rule.Package rulesPackage = packageBuilder.getPackage();
RuleBase ruleBase = RuleBaseFactory.newRuleBase();
ruleBase.addPackage(rulesPackage);
WorkingMemory workingMemory = ruleBase.newStatefulSession();
Product product = new Product();
product.setType("South");
System.out.println("Original product " + product.getType()+ "'s coupon code is " + product.getCouponCode());
//Working Memory
workingMemory.insert(product);
workingMemory.fireAllRules();
System.out.println("The coupon code for the product " + product.getType() + " is " + product.getCouponCode());
}
}
或者,如果您喜欢保留调试跟踪,您可以尝试以下方式构建传递给addPackageFromDrl
的Reader
:
Reader reader = new StringReader(result);
System.out.println("Reached point 4K");
packageBuilder.addPackageFromDrl(reader);
System.out.println("Reached point 5");
请注意使用了StringReader
。整个代码片段如下:
package com.abc.main;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.drools.compiler.compiler.DroolsParserException;
import org.drools.compiler.compiler.PackageBuilder;
import org.drools.core.RuleBase;
import org.drools.core.RuleBaseFactory;
import org.drools.core.WorkingMemory;
public class Class6 {
public static void main(String[] args) throws DroolsParserException,IOException
{
Class6 droolsTest = new Class6();
System.out.println("Reached point 1A");
droolsTest.executeDrools2();
}
public void executeDrools2() throws DroolsParserException, IOException
{
System.out.println("Reached point 2J");
PackageBuilder packageBuilder = new PackageBuilder();
String ruleFile = "Rules.drl";
InputStream resourceAsStream = getClass().getResourceAsStream(ruleFile);
System.out.println("Reached point 3");
String result = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8);
System.out.println("Reached point 3b - " + result);
System.out.println("Reached point 3C");
Reader reader = new StringReader(result);
System.out.println("Reached point 4K");
packageBuilder.addPackageFromDrl(reader);
System.out.println("Reached point 5");
org.drools.core.rule.Package rulesPackage = packageBuilder.getPackage();
RuleBase ruleBase = RuleBaseFactory.newRuleBase();
ruleBase.addPackage(rulesPackage);
WorkingMemory workingMemory = ruleBase.newStatefulSession();
Product product = new Product();
product.setType("South");
System.out.println("Original product " + product.getType()+ "'s coupon code is " + product.getCouponCode());
//Working Memory
workingMemory.insert(product);
workingMemory.fireAllRules();
System.out.println("The coupon code for the product " + product.getType() + " is " + product.getCouponCode());
}
}
这将输出:
无论哪种方式,要使示例工作,您需要更改规则文件,并使用type
而不是RegionName
:
package com.abc.main
import com.abc.main.Product
rule "Offer for Diamond"
when
productObject: Product(type=="South")
then
productObject.setCouponCode("B");
end
rule "Offer for Gold"
when
productObject: Product(type=="North")
then
productObject.setCouponCode("C");
end
请注意,Drools使用JavaBeans约定来访问模型属性,至少我一直以来都是这么理解的:与C#一样,属性由读(get
)和写(set
)可选方法的组合来定义,但不同的是,在Java中,您需要在get
和set
方法中显式包括属性名称。例如,在Product
中定义属性type
,您需要定义适当的getType
和/或setType
方法。在您的示例中,用于保存
英文:
I think you based your code in this example.
After reviewing both code snippets, I think the problem with your code is related to this debug related code fragment:
System.out.println("Reached point 3");
String result = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8);
System.out.println("Reached point 3b - " + result);
System.out.println("Reached point 3C");
Note that with that code fragment you are consuming the InputStream
that points to the rules definition file obtained here:
String ruleFile = "Rules.drl";
InputStream resourceAsStream = getClass().getResourceAsStream(ruleFile);
As a consequence, no rules are associated with your rule package when running this code fragment:
Reader reader = new InputStreamReader(resourceAsStream);
System.out.println("Reached point 4K");
packageBuilder.addPackageFromDrl(reader);
and that causes the wrong behavior you see later when trying activating then.
Please, as stated, to solve the problem, consider comment that debug code fragment:
package com.abc.main;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.drools.compiler.compiler.DroolsParserException;
import org.drools.compiler.compiler.PackageBuilder;
import org.drools.core.RuleBase;
import org.drools.core.RuleBaseFactory;
import org.drools.core.WorkingMemory;
public class Class6 {
public static void main(String[] args) throws DroolsParserException,IOException
{
Class6 droolsTest = new Class6();
System.out.println("Reached point 1A");
droolsTest.executeDrools2();
}
public void executeDrools2() throws DroolsParserException, IOException
{
System.out.println("Reached point 2J");
PackageBuilder packageBuilder = new PackageBuilder();
String ruleFile = "Rules.drl";
InputStream resourceAsStream = getClass().getResourceAsStream(ruleFile);
/*System.out.println("Reached point 3");
String result = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8);
System.out.println("Reached point 3b - " + result);
System.out.println("Reached point 3C");*/
Reader reader = new InputStreamReader(resourceAsStream);
System.out.println("Reached point 4K");
packageBuilder.addPackageFromDrl(reader);
System.out.println("Reached point 5");
org.drools.core.rule.Package rulesPackage = packageBuilder.getPackage();
RuleBase ruleBase = RuleBaseFactory.newRuleBase();
ruleBase.addPackage(rulesPackage);
WorkingMemory workingMemory = ruleBase.newStatefulSession();
Product product = new Product();
product.setType("South");
System.out.println("Original product " + product.getType()+ "'s coupon code is " + product.getCouponCode());
//Working Memory
workingMemory.insert(product);
workingMemory.fireAllRules();
System.out.println("The coupon code for the product " + product.getType() + " is " + product.getCouponCode());
}
}
As an alternative, if you prefer to keep your debug traces, you can try building the Reader
passed as argument to addPackageFromDrl
in the following way:
Reader reader = new StringReader(result);
System.out.println("Reached point 4K");
packageBuilder.addPackageFromDrl(reader);
System.out.println("Reached point 5");
Please, note the use of StringReader
. The entire code fragment:
package com.abc.main;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.drools.compiler.compiler.DroolsParserException;
import org.drools.compiler.compiler.PackageBuilder;
import org.drools.core.RuleBase;
import org.drools.core.RuleBaseFactory;
import org.drools.core.WorkingMemory;
public class Class6 {
public static void main(String[] args) throws DroolsParserException,IOException
{
Class6 droolsTest = new Class6();
System.out.println("Reached point 1A");
droolsTest.executeDrools2();
}
public void executeDrools2() throws DroolsParserException, IOException
{
System.out.println("Reached point 2J");
PackageBuilder packageBuilder = new PackageBuilder();
String ruleFile = "Rules.drl";
InputStream resourceAsStream = getClass().getResourceAsStream(ruleFile);
System.out.println("Reached point 3");
String result = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8);
System.out.println("Reached point 3b - " + result);
System.out.println("Reached point 3C");
Reader reader = new StringReader(result);
System.out.println("Reached point 4K");
packageBuilder.addPackageFromDrl(reader);
System.out.println("Reached point 5");
org.drools.core.rule.Package rulesPackage = packageBuilder.getPackage();
RuleBase ruleBase = RuleBaseFactory.newRuleBase();
ruleBase.addPackage(rulesPackage);
WorkingMemory workingMemory = ruleBase.newStatefulSession();
Product product = new Product();
product.setType("South");
System.out.println("Original product " + product.getType()+ "'s coupon code is " + product.getCouponCode());
//Working Memory
workingMemory.insert(product);
workingMemory.fireAllRules();
System.out.println("The coupon code for the product " + product.getType() + " is " + product.getCouponCode());
}
}
Which outputs:
In any case, to make the example work you will need to change your rules file and use type
instead of RegionName
as well:
package com.abc.main
import com. abc.main.Product
rule "Offer for Diamond"
when
productObject: Product(type=="South")
then
productObject.setCouponCode("B");
end
rule "Offer for Gold"
when
productObject: Product(type=="North")
then
productObject.setCouponCode("C");
end
Note that Drools uses JavaBeans conventions to access model properties, al least I always took it for sure: like in C#, the property is defined by the combination of a read (get
) and write (set
) optional methods but, in contrast, in Java you need to explicitly include the property name in the get
and set
methods. for instance, for defining the property type
in Product
you need to define the proper getType
and/or setType
methods. The name of the internal variable used to hold the property value, in your example, RegionName
, doesn't actually matter. By convention in Java you will use always camel case syntax for property names, with the first letter being lowercase, not uppercase such as in C#.
As described, the use of the stateful session is not related to the problem.
Having said all that, as pointed out by @RoddyoftheFrozenPeas in his comment, you could let Drools trying finding the different rules defined in your classpath. You can follow his answer as reference. This Github repository provides great guidance as well for this and other stuff.
Please note that the last references provided use the new KIE APIs instead of the old Drools ones that you are using. This excellent blog post provides a great introduction about the change.
If, as you mentioned, you are learning Drools, the aforementioned blog contains posts of very good quality that could be of help. Drools itself provides an excellent documentation and additional help resources too.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论