两条规则中的一条未触发

One out of two rules not firing

我是 JAVA 的新手,尤其是 Drools,所以不要问我为什么这样做 :D 任务是实现一个简单的系统来计算 2 的关税和价格项目(不同颜色)。我用 getter 和 setter 做了一个简单的 class :

package com.sample;

public class Pen {

    private String color;
    private int quantity;
    private double tariff;
    private double subTotal;

    public String getColor(){
        return color;
    }

    public void setColor(String color){
        this.color=color;
    }

    public int getQuantity(){
        return quantity;
    }

    public void setQuantity(int quantity){
        this.quantity=quantity;
    }

    public double getTariff(){
        return tariff;
    }

    public void setTariff(double tariff){
        this.tariff=tariff;
    }

    public double getSubTotal(){
        return subTotal;
    }

    public void setSubTotal(double subTotal){
        this.subTotal=subTotal;
    }

}

任务是从 CSV 文件中读取一些预定义的数据并将其写入另一个 CSV(写入尚未实现)。 Class 处理输入并调用会话如下:

public class CSVReader {
    public void CSVToJava() {
        String CSVFile = "csvExample.csv";
        BufferedReader buffer = null;
        String line = "";
        String delimiter = ",";
        List<Pen> penList = new ArrayList<Pen>();

        try {
            // load up the knowledge base
            KnowledgeBase kbase = readKnowledgeBase();
            StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
            buffer = new BufferedReader(new FileReader(CSVFile));
            while ((line = buffer.readLine()) != null) {
                String[] pens = line.split(delimiter);
                Pen redPen = new Pen();
                Pen bluePen = new Pen();
                if (pens[0].equalsIgnoreCase("Blue Pen")) {
                    bluePen.setColor(pens[0]);
                    bluePen.setQuantity(Integer.parseInt(pens[1].trim()));
                    penList.add(bluePen);
                    ksession.insert(bluePen);
                } else {
                    redPen.setColor(pens[0]);
                    redPen.setQuantity(Integer.parseInt(pens[1].trim()));
                    penList.add(redPen);
                    ksession.insert(redPen);
                }
            }
            ksession.fireAllRules();
            printPenList(penList);        
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Throwable t) {
            t.printStackTrace();
        } finally {
            if (buffer != null) {
                try {
                    buffer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void printPenList(List<Pen> penListToPrint) {
        for (int i = 0; i < penListToPrint.size(); i++) {
            System.out.println(penListToPrint.get(i).getColor() + "," + penListToPrint.get(i).getQuantity() + ","
                    + penListToPrint.get(i).getTariff() + "," + penListToPrint.get(i).getSubTotal());
        }

    }

    private static KnowledgeBase readKnowledgeBase() throws Exception {

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();

        kbuilder.add(ResourceFactory.newClassPathResource("com/Drools/BluePen.drl"), ResourceType.DRL);
        kbuilder.add(ResourceFactory.newClassPathResource("com/Drools/RedPen.drl"), ResourceType.DRL);

        KnowledgeBuilderErrors errors = kbuilder.getErrors();

        if (errors.size() > 0) {
            for (KnowledgeBuilderError error : errors) {
                System.err.println(error);
            }
            throw new IllegalArgumentException("Could not parse knowledge.");
        }

        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());

        return kbase;
    }

}

我还有 2 个单独的 DRL 文件,用于每种项目颜色。根据规则的计算,我需要打印出 2 个附加属性,简单乘法(小计)。每个文件有 2 条规则:

import com.sample.Pen; //FIRST ONE

rule "less or equal to 10"

    when
        item : Pen(item.getColor().equalsIgnoreCase("BLUE PEN"), (item.getQuantity()) <= 10.0)
    then
        item.setTariff(3.0);
        item.setSubTotal(3.0 * ((double) item.getQuantity()));      
end

rule "more than 10"
    when
        item : Pen(item.getColor().equalsIgnoreCase("BLUE PEN"), (item.getQuantity()) > 10.0)
    then
        item.setTariff(2.5);
        item.setSubTotal(2.5 * ((double) item.getQuantity()));
end



import com.sample.Pen; //SECOND ONE


rule "less or equal to 10"

        when
            item : Pen(item.getColor().equalsIgnoreCase("RED PEN"), (item.getQuantity()) <= 10.0)
        then
            item.setTariff(3.5);
            item.setSubTotal(3.5 * ((double) item.getQuantity()));      
    end

    rule "more than 10"
        when
            item : Pen(item.getColor().equalsIgnoreCase("RED PEN"),   (item.getQuantity()) > 10.0)
        then
            item.setTariff(3.0);
            item.setSubTotal(3.0 * ((double) item.getQuantity()));
    end

此外,还有一个 class,我在其中调用启动流程的整个方法:

public class App {

    public static void main(String[] args) {
          CSVReader csvReader = new CSVReader();
          csvReader.CSVToJava();
    }

}

一切看起来像这样packageExplorer

我的主要问题是打印输出看起来像这样 -->

Red Pen,6,3.5,21.0
Blue Pen,12,0.0,0.0

每行应包含 4 个字段,前两个字段是在 while 循环中通过 CSVReader class 计算得出的,而后两个字段(本例中的 3.5 和 21.0 或 Red Pen)是使用 Drools 计算的。如您所见,蓝笔的规则根本没有触发,我无法解决问题...如果有人可以提供帮助,我将不胜感激:)

编辑:解决这个问题后,我用分布在 2 个 DRL 文件中的另外 3 条规则编辑了代码:

package com.drools //First.drl

import com.sample.Pen;

rule "Subtotal for blue pen" salience 2

    when
        item : Pen(item.getColor().equalsIgnoreCase("BLUE PEN"))
    then
        item.setTotal(item.getTotal() + item.getSubTotal());    
end

rule "Subtotal for red pen" salience 2

    when
        item : Pen(item.getColor().equalsIgnoreCase("RED PEN"))
    then
        item.setTotal(item.getTotal() + item.getSubTotal());    
end


package com.drools //Second.drl

import com.sample.Pen;

rule "Discounted total price" salience 1

    when
        item : Pen((item.getTotal()) > 100.0)
    then
        item.setTotal(0.85 * item.getTotal());
end

我还在我的会话中添加了文件 classpaths,以便可以触发。调用 fireAll 方法时,没有规则触发第二次 drl 火灾,其中总量乘以 0.85(total 是在 Pen class 中声明的静态变量,所以我可以从每种颜色中收集 suTotals 的加法),尽管显着性是最低的 --> 应该最后触发并且正确的数量应该是 140*0.85 = 119.

看起来像这样:

Red Pen,30,3.0,90.0
Blue Pen,20,2.5,50.0
140 

也许有人也能解决这个问题,到目前为止你们的建议都很好 :)

我不是专家,但我建议将RED PEN和BLUE PEN切换一下,看看它是否在第一个规则后不触发规则。或者它可能是 CSV 文件读取的问题。谢谢

规则条件中的字符串比较不应使用Java equals 方法。 Drools 使用自己的 rule language。 (但请注意 - 5.x 语法比参考文档中显示的语法更受限制。而且它在次要版本 5.2/3/... [laune] 之间也有所不同)

查看示例 4.4(我更正了示例中缺失的 "):

1: rule simple_rule
2:   when
3:     Student( name == "Andy" )
4:   then
5: end

您应该为您的规则尝试这种语法(还要注意您的数量是整数而不是浮点数):

when
    item : Pen(color == "BLUE PEN", quantity > 10)

附带说明一下,您在规则的动作部分中的 (double) 转换不是强制性的。 Java 中的双精度和整数相乘最终得到双精度值,这已经是您的 tariff 和 subTotal 成员的类型。

两个文件都有规则

rule "less or equal to 10"
rule "more than 10"

你不能这样。规则由名称标识;与另一个规则同名的规则将默默地覆盖第一个规则。来自不同 DRL 文件的加载顺序未定义。

在 Drools 5.x 期间就是否应该以及如何工作进行了长时间的讨论,但现在这是桥下的水,你必须坚持下去。 (我不确定 Drools 6.x 是否允许这样做。请查阅文档。)

感谢@Wis 确认 Drools 6.x 在编译中存在具有相同名称的规则时引发编译错误,无论是在同一 DRL 文件中还是在不同文件中。