两个规则中有一个没有解雇

时间:2016-05-09 01:06:12

标签: java drools priority-queue rule-engine

我特别喜欢JAVA和Drools的初学者,所以不要问为什么我这样做:D任务是实施一个简单的系统来计算2项(不同颜色)的关税和价格。我用吸气剂和二传手制作了一个简单的课程:

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(写入尚未实现)。处理输入并调用会话的类如下:

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个额外的属性,简单的乘法(subTotal)。每个文件都有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

此外,还有一个类,我调用整个方法来启动过程:

public class App {

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

}

所有内容都是packageExplorer

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

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

每行应包含4个字段,前两个字段在while循环中的CSVReader类中计算,而后两个字段(在案例中为3.5和21.0或Red Pen)使用Drools计算。正如你所看到的,蓝笔的规则根本没有解决,我无法解决问题......如果有人可以提供帮助,我会非常感激:)

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

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

我在会话中也添加了文件类路径,以便可以触发。当调用fireAll方法时,第二个drl fire没有规则触发,其中总量乘以0.85(total是在Pen类中声明的静态变量,所以我可以从每种颜色收集suTotal s的添加,尽管显着性最低 - &gt;应该最后开火,正确的数量应该是140 * 0.85 = 119。

看起来像这样:

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

也许有人可以解决这个问题,到目前为止,你们的建议很棒!)

3 个答案:

答案 0 :(得分:2)

两个文件都有规则

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

你无法做到这一点。规则按名称标识;与另一个规则同名的规则将以静默方式覆盖第一个规则。未定义来自不同DRL文件的加载顺序。

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

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

答案 1 :(得分:1)

我不是专家,但我建议切换RED PEN和BLUE PEN以查看它是否在第一次规则后没有触发规则。或者它可能是CSV文件读取的问题。 THX

答案 2 :(得分:1)

规则条件中的字符串比较不应使用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中乘以一个整数和一个整数会得到一个double值,这个值已经是你的关税和subTotal成员的类型。