如何修复Drools中不触发的规则。

huangapple go评论85阅读模式
英文:

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

如何修复Drools中不触发的规则。

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” ) ?

如何修复Drools中不触发的规则。

答案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());
  }
}

或者,如果您喜欢保留调试跟踪,您可以尝试以下方式构建传递给addPackageFromDrlReader

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());
  }
}

这将输出:

如何修复Drools中不触发的规则。

无论哪种方式,要使示例工作,您需要更改规则文件,并使用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中,您需要在getset方法中显式包括属性名称。例如,在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:

如何修复Drools中不触发的规则。

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.

huangapple
  • 本文由 发表于 2023年6月22日 14:57:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76529287.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定