当前位置: 首页 > 工具软件 > Drools Flow > 使用案例 >

Drools 学习

慕凌
2023-12-01

What ?

Drools(JBoss Rules )具有一个易于访问企业策略、易于调整以及易于管理的开源业务规则引擎,符合业内标准,速度快、效率高。业务分析师或审核人员可以利用它轻松查看业务规则,从而检验是否已编码的规则执行了所需的业务规则。

-- 百度百科

  • 理解:

Drools 把业务决策从代码中抽取出来,可以让我们更加灵活的去编写代码,无需在编码时仍要考虑相关的业务决策,在编码时我们只需关注输入和输出,业务决策相关都交给规则文件处理。

  • 应用场景
    1. 风险控制系统
    2. 决策平台系统
    3. 促销平台系统
  • 名词解释
    • Wokring Memory : 工作内存,drools规则引擎会从Working Memory中获取数据并和规则文件中定义的规则进行模式匹配。
    • Fact : 事实,我们把一个javaBean插入到Working Memory后的对象就是Fact对象。
    • Rule Base : 规则库,规则文件中定义的规则都会被加载到规则库中。
  • 开发步骤
    • 获取KieService
    • 获取kieContainer
    • 获取KieSession
    • Insert Fact
    • 触发规则
    • 关闭kieSession
  • 规则文件构成
    • package 包路径,同一个包名下的查询或者函数可以直接调用
    • import 导入规则文件所使用的外部变量、类、静态方法
    • global 全局变量
    • function 自定义函数
    • query 查询
    • rule end 规则体

 

  • 语法结构
// 注释:第一种
/*
     注释:第二种
*/
rule "ruleName"
    attributes
    when
        LHS
    then
        RHS
end
    • rule : 关键字
    • attributes : 规则属性,可选
    • when : 关键字,后面是规则的条件部分
    • LHS (Left Hand Side) : 规则文件通用名称。 多个条件使用 and 连接 (也可以不写)
    • then : 关键字,后面是规则的结果部分
    • RHS (Right Hand Side) : 规则的结果通用名称
    • end :关键字,规则结束

例: 购物时,如果总消费在1000元以上,则享受打8折的服务

//创建javaBean Order
public class Order {
    // 总消费
    private double totalPrice;
    // 折后消费
    private double disCountPrice;

    public double getTotalPrice() {
        return totalPrice;
    }

    public void setTotalPrice(double totalPrice) {
        this.totalPrice = totalPrice;
    }

    public double getDisCountPrice() {
        return disCountPrice;
    }

    public void setDisCountPrice(double disCountPrice) {
        this.disCountPrice = disCountPrice;
    }
}
// 规则文件编写如下 -- 手敲未验证
rule "shopping_disount"
    when
    //  $order 绑定变量名,以$开始,使用其可以操作相应的Fact对象。
    //  $tp 绑定变量也可以用于属性上
        $order:Order($tp:Price >= 1000)
    then
        $order.setDisountPrice($order.getOriginalPrice()*0.8);
        System.out.println("规则匹配,打八折");
end
// 测试
  public void testDrools() {
        // 1. 获取KieService
        KieServices kieServices = KieServices.Factory.get();
        // 2. 获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        // 3. 获取kieSession
        KieSession kieSession = container.newKieSession();
        Order o = new Order();
        o.setTotalPrice(1020);
        // 4. insert fact
        kieSession.insert(p);
        // 5. 触发规则
        kieSession.fireAllRules();
        // 6. 关闭 kieSession
        kieSession.dispose();
    }

 

  • 部分比较操作符
    • contains | not contains 语法结构 检查一个Fact对象的某个属性值是否包含一个指定的对象值

Object(Field[Collection/Array] contains value)

Object(Field[Collection/Array] not contains value)

    • memberOf | not memberOf 语法结构 判断一个Fact对象的某个属性是否在一个或多个集合中

Object(field memberOf value[Collection/Array])

Object(field not memberOf value[Collection/Array])

    • matches | not matches 语法结构 判断一个Fact对象的属性是否与提供的标准的Java正则表达式进行匹配

Object(field matches "正则表达式")

Object(field not matches "正则表达式")

例:测试 contains / not contains

// 为了测试比较操作符创建的javaBean
public class CompareEntity {
    private String name;
    private List<String> list;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }
}
// 测试操作符 contains,其他操作符使用方法也是如此
rule "testContains"
    when
        CompareEntity(name contains "张三")
        CompareEntity(list contains $na:name)
    then
    System.out.println("contains - $name:"+$na);
        System.out.println("contains - 规则触发");
end

// 测试操作符 not contains
rule "testNotContains"
    when
        CompareEntity(name not contains "李四")
        CompareEntity(list not contains $na:name)
    then
    System.out.println("not contains - $name="+$na);
    System.out.println("not contains - 规则触发");
end
public void testDrools() {
        // 1. 获取KieService
        KieServices kieServices = KieServices.Factory.get();
        // 2. 获取kieContainer
        KieContainer container = kieServices.getKieClasspathContainer();
        // 3. 获取kieSession
        KieSession kieSession = container.newKieSession();
        CompareEntity o = new CompareEntity();
        o.setNames("张三");
        List<String> list = new ArrayList<String>();
        list.add("张三");
        list.add("李四");
        o.setList(list);
        // 4. insert fact
        kieSession.insert(p);
        // 5. 触发规则
        kieSession.fireAllRules();
        // 6. 关闭 kieSession
        kieSession.dispose();
    }

注:多个规则,如果想要只触发一条规则可以使用 RuleNameEqualsAgendaFilter("规则名")实现

 

  • 内置方法

在规则文件的RHS部分,Drools提供了一些方法,帮助我们操作工作内存中的数据,操作完成后,工作引擎会重新进行匹配。

    • update 更新工作内存中的数据,并让相关的规则重新匹配
    • insert 向工作内存中插入数据,并让相关的规则重新匹配
    • retract 删除工作内存中的数据,并让相关的规则重新匹配

例: 创建Student,规则文件判断条件,使用内置方法更改年龄(age),让多个规则都匹配

public class Student {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
rule "insertDrl"
    when
        $s:Student(age<10)
    then
        // 插入新的数据,重新匹配
        Student s1 = new Student();
        s1.setAge(15);
        insert(s1);
        System.out.println("age<10 规则匹配,插入新的fact,age=15");
end

rule "insert2"
    when
        $s:Student(age>=10 && age<=15)
    then
        $s.setAge(25);
        // 更新数据
        update($s);
        System.out.println("age>=10 && age<=15 规则触发,更新age=25");
end

rule "inset3"
    when
        Student(age>=25)
    then
    System.out.println("age>=25 规则触发");
end
  • 规则属性(部分)

属性名

作用

salience

指定规则优先级

dialect

指定规则使用语言类型,java/mvel

enabled

指定规则是否启用

no-loop

防止死循环

例:测试salience

// 按照优先级数值越大的先执行,未设置,按照由上到下的顺序执行。
rule "rule_1"
    salience 9
    when
        eval(true)
    then
        System.out.println("规则rule_1触发");
end

rule "rule_2"
    salience 10
    when
        eval(true)
    then
        System.out.println("规则rule_2触发");
end

rule "rule_3"
    salience 8
    when
        eval(true)
    then
        System.out.println("规则rule_3触发");
end
  • Global全局变量
    • 语法结构为:global 对象类型 对象名称

在使用global定义的全局变量时有两点需要注意:

1、对象类型为包装类型时,在一个规则中改变了global的值,那么只针对当前规则有效,对其他规则中的global不会有影响。可以理解为它是当前规则代码中的global副本,规则内部修改不会影响全局的使用。

2、如果对象类型为集合类型或JavaBean时,在一个规则中改变了global的值,对java代码和所有规则都有效。

 

  • Query 查询
    • 查询working memory中符合约束条件的Fact对象
// 语法结构如下
query 查询的名称(可选参数)
    LHS
end

例:

//不带参数的查询
//当前query用于查询Working Memory中age>10的Student对象
query "query_1"
    $student:Student(age > 15)
end
//带有参数的查询
query "query_2"(String sname)
    $student:Student(age > 15 && name == sname)
end
public void testQuery(){

        KieServices services = KieServices.Factory.get();
        KieContainer container = services.getKieClasspathContainer();
        KieSession kieSession = container.newKieSession();

        Student s1 = new Student();
        Student s2 = new Student();
        Student s3 = new Student();
        s1.setAge(11);
        s1.setName("张三");
        s2.setAge(20);
        s2.setName("李四");
        s3.setAge(25);
        s3.setName("王五");

        kieSession.insert(s1);
        kieSession.insert(s2);
        kieSession.insert(s3);

        QueryResults results = kieSession.getQueryResults("query_1");
        System.out.println("result.size="+results.size());
        for (QueryResultsRow row:results){
            Student s = (Student) row.get("$student");
            System.out.println(s.getName());
        }

        System.out.println("----------------------------------------------");

        QueryResults res = kieSession.getQueryResults("query_2","张三");
        System.out.println(res.size());
        for (QueryResultsRow row:res){
            Student s = (Student) row.get("$student");
            System.out.println(s.getName());
        }
        //关闭
        kieSession.dispose();
    }
  • funtion 函数
    • function关键字用于在规则文件中定义函数,类似于java中的方法。
function 返回值类型 函数名(可选参数){
    //逻辑代码
}

 

 类似资料: