Drools 规则引擎案例

公众号文章 专栏收录该内容
1 篇文章 0 订阅

目前市面上比较热门的规则引擎有几款:

  1. Ilog JRules 是最有名的商用BRMS;
  2. Drools 是最活跃的开源规则引擎;
  3. Jess 是Clips的java实现,就如JRuby之于Ruby,是AI系的代表;
  4. Visual Rules(旗正规则引擎)国内商业规则引擎品牌。

本文将着重介绍Drools。

一 为什么要使用规则引擎

有如下案例,充值得积分的案例 ,规则如下:

充值金额及所得积分的分数原价金额 
	100以下, 不加分;
	100-500100分; 
	500-1000500分; 
	1000 以上 加1000分;

传统java业务实现如下:

public class JavaScoreExample {
      
    public static void main(String[] args) throws Exception {  
          
        List<Order> orderList = getInitData();
        for (int i=0; i<orderList.size(); i++){  
            Order order = orderList.get(i);  
            if (order.getAmout() <= 100){  
                order.setScore(0);  
                addScore(order);  
            }else if(order.getAmout() > 100 && order.getAmout() <= 500){  
                order.setScore(100);  
                addScore(order);  
            }else if(order.getAmout() > 500 && order.getAmout() <= 1000){  
                order.setScore(500);  
                addScore(order);  
            }else{  
                order.setScore(1000);  
                addScore(order);  
            }  
        }            
    }  
      
    private static void addScore(Order o){  
        System.out.println("用户" + o.getUser().getName() + "享受额外增加积分: " + o.getScore());  
    }  
      
    private static List<Order> getInitData() throws Exception {  
        List<Order> orderList = new ArrayList<Order>();
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        {
            Order order = new Order();  
            order.setAmout(80);  
            order.setBookingDate(df.parse("2020-11-01"));  
            User user = new User();
            user.setLevel(1);  
            user.setName("Name1");  
            order.setUser(user);  
            orderList.add(order);  
        }
        {
            Order order = new Order();  
            order.setAmout(200);  
            order.setBookingDate(df.parse("2020-11-01"));  
            User user = new User();
            user.setLevel(2);  
            user.setName("Name2");  
            order.setUser(user);  
            orderList.add(order);  
        }  
       
        return orderList;  
    }  
} 

这时候由于市场需求变化,又要调整规则时候,则又要进行业务层面的代码修改、部署,十分麻烦。如果我们可以把决策规则从应用程序中分离出来,将对系统提供很大的便利!

例如 下面业务变更

	100 以下 加10分;
	100-500100分; 
	500-1000500分; 
	1000 以上 加1000分;

由此,诞生了规则引擎!如下如所示:
规则
规则引擎优势:

对系统的使用人员

  1. 把业务策略(规则)的创建、修改和维护的权利交给业务经理
  2. 提高业务灵活性
  3. 加强业务处理的透明度,业务规则可以被管理
  4. 减少对IT人员的依赖程度
  5. 避免将来升级的风险

对IT开发人员

  1. 简化系统架构,优化应用
  2. 提高系统的可维护性和维护成本
  3. 方便系统的整合
  4. 减少编写“硬代码”业务规则的成本和风险

二、什么是Drools

Drools 是一个基于Charles Forgy’s的RETE算法的,易于访问企业策略、易于调整以及易于管理的开源业务规则引擎,符合业内标准,速度快、效率高。

业务分析师人员或审核人员可以利用它轻松查看业务规则,从而检验是否已编码的规则执行了所需的业务规则。

Drools 是用Java语言编写的开放源码规则引擎,使用Rete算法对所编写的规则求值。Drools允许使用声明方式表达业务逻辑。可以使用非XML的本地语言编写规则,从而便于学习和理解。并且,还可以将Java代码直接嵌入到规则文件中,这令Drools的学习更加吸引人。

三、Drools 实战

下面我们将展示测试项目中使用drools的一个案例 数字匹配操作

  • 循环打印 1 到 50,
  • 是 5 的倍數就印 five,
  • 是 7 的倍數就印 seven,
  • 同時是 5 和 7 的倍數就印 five and seven,
  • 否则打印数字本身

1、引入核心依赖jar包

<!-- Drools 规则引擎相关依赖 -->
<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-core</artifactId>
    <version>7.44.0.Final</version>
</dependency>
<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-compiler</artifactId>
    <version>7.44.0.Final</version>
</dependency>

2、定义controller层接口

/**
 * 循环打印 1 到 50,
 * 是 5 的倍數就印 five,
 * 是 7 的倍數就印 seven,
 * 同時是 5 和 7 的倍數就印  five and seven,
 * 否则打印数字本身
 *
 * @author Alnex
 * @date: 2020/11/3 9:05
 */
@RestController
@RequestMapping("number")
public class NumberGameController {

    @GetMapping("/")
    public Object numberGame() {
        // KieServices is the factory for all KIE services
        KieServices kieServices = KieServices.Factory.get();

        // From the kie services, a container is created from the classpath
        KieContainer kieContainer = kieServices.getKieClasspathContainer();

        KieSession kieSession = null;
        // 初始化数据
        List<Number> lists = getDataInit();
        for (Number number : lists) {
            // From the container, a session is created based on
            // its definition and configuration in the META-INF/kmodule.xml file
            kieSession = kieContainer.newKieSession("numberGame");

            kieSession.insert(number);
            kieSession.fireAllRules();
            System.out.println("第" + number.getNumber() + "条数据的匹配数据为" + number.getStyle());
        }
        assert kieSession != null;
        kieSession.dispose();
        return "规则匹配完成";
    }

    private List<Number> getDataInit() {
        List<Number> list = new ArrayList<>();
        Number number = null;
        for (int i = 0; i < 50; i++) {
            number = new Number();
            number.setNumber(i);

            list.add(number);
        }
        return list;
    }
}

3、定义rule规则

package rules.numbers;

import com.alnex.drools.pojo.Number

rule "number is native matching native"
    lock-on-active true
    no-loop true
    salience 1
    when
        $number : Number(number != null ,(number % 5) != 0 ,(number % 7) != 0)
        $style : Number(style == null)
    then
        $style.setStyle($number.getNumber().toString());
end

rule "number is five times matching five"
    lock-on-active true
    no-loop true
    salience 1
    when
        $number : Number(number != null ,(number % 5) == 0 ,(number % 7) != 0)
        $style : Number(style == null)
    then
        $style.setStyle("five");
end

rule "number is seven times matching seven"
    lock-on-active true
    no-loop true
    salience 1
    when
        $number : Number(number != null ,(number % 5) != 0 ,(number % 7) == 0)
        $style : Number(style == null)
    then
        $style.setStyle("seven");
end

rule "number is five times and seven times matching  five and seven,"
    lock-on-active true
    no-loop true
    salience 1
    when
        $number : Number(number != null ,(number % 5) == 0 ,(number % 7) == 0)
        $style : Number(style == null)
    then
        $style.setStyle("five and seven");
end

4、定义kmodule文件

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
    <kbase name="numberGame" packages="rules.numbers">
        <ksession name="numberGame"/>
    </kbase>
</kmodule>

5、启动项目 执行相关接口 [ 部分数据示例 ]

26条数据的匹配数据为2627条数据的匹配数据为2728条数据的匹配数据为seven
	第29条数据的匹配数据为2930条数据的匹配数据为five
	第31条数据的匹配数据为3132条数据的匹配数据为3233条数据的匹配数据为3334条数据的匹配数据为3435条数据的匹配数据为five and seven

四、Drools规则属性

1、No-loop
作用:防止规则通过update之类的函数修改了Fact对象时,可能使规则再次被激活,从而导致死循环。
什么时候用?
当被修改的事实对象与规则LHS部分的约束条件为包含关系时。例如

rule No-loop1
        no-loop true
        when 
      $p:Person(name=="张三", age==30);
     then
      $p.setAge(50);
      update($p);
        System.out.println("设置no-loop时的效果");
end

否则,设置了no-loop为true也会出现死循环,例如

rule No-loop2
        no-loop true
        when 
      $p:Person(name=="张三");
     then
      $p.setAge(50);
      update($p);
      System.out.println("设置no-loop时的效果");
  end

2、lock-on-active
作用:no-loop的升级版,一个更强大的解决死循环的属性。当规则提设置该属性为True时,则当前只会被触发一次。无论如何更新规则事实对象,当前规则也只能被触发一次。
例如

rule lock-on-active
    	lock-on-active true
        when 
      $p:Person(name=="张三");
     then
      $p.setAge(50);
      update($p);
      System.out.println("设置no-loop时的效果");
  end

3、salience
作用:如果不设置salience属性,规则体的执行顺序为由上到下,否者,salience值越大,执行顺序越高。
例如:

rule "salience1"
	salience 10
  when 
    //这里如果为空,则表示eval(true)
  then
    System.out.println("hello word");
end
rule "salience2"
	salience 5
  when 
    //这里如果为空,则表示eval(true)
  then
    System.out.println("hello word");
end

4、enabled
作用:指规则是否可以被执行,若规则体设置为 enabled false,即将规则体视为永不激活。
例如:

rule "enabled1"
		enabled true
  when 
    //这里如果为空,则表示eval(true)
  then
    System.out.println("hello word");
end
rule "enabled2"
		enabled false
  when 
    //这里如果为空,则表示eval(true)
  then
    System.out.println("hello word");
end

5、dialect
作用:用来定义规则中要使用的语言类型,支持Mvel和Java两种类型的语言,默认情况下由包指定。

6、date-effective
作用:只有当前系统时间大于等于设置的时间或者日期,规则才会被激活。
例如:

rule "date-effective"
	date-effective "07-August-2018"
  when 
    //这里如果为空,则表示eval(true)
  then
    System.out.println("hello word");
end

7、date-expires
作用:与date-effective相反,只有当前系统时间小于设置的时间或者日期,规则才会被激活。

8、duration
作用:表示定时器,如果当前规则LHS部分为True,规则继续执行。如果该属性已经被弃用,那么通过新的属性timer来控制。

9、activation-group
作用:activation-group指激活分组,通过字符串定义分组名称,具有相同组名名称的规则体有且只有一个规则被激活,其他规则体的LHS部分仍然为true也不会被执行。该属性受salience属性的影响,如当前规则文件中的其他规则未设计该属性,则视为规则处于被激活状态,并不受该属性的影响。

rule "activation-group1"
	salience 10
	activation-group "testAgs"
  when 
    //这里如果为空,则表示eval(true)
  then
    System.out.println("hello word");
end
rule "activation-group2"
	salience 10
	activation-group "testAgs"
  when 
    //这里如果为空,则表示eval(true)
  then
    System.out.println("hello word");
end
rule "activation-group3"
	activation-group "testAgs"
  when 
    //这里如果为空,则表示eval(true)
  then
    System.out.println("hello word");
end
rule "activation-group4"
	activation-group "testAgs"
  when 
    //这里如果为空,则表示eval(true)
  then
    System.out.println("hello word");
end

10、agenda-group
作用:agenda-group是议程分组,属于另一种可控的规则执行方式,是指用户可以通过配置agenda-group的参数来控制规则的执行,而且只有获取焦点的规则才会被激活。
例如:ks.getAgenda().getAgendaGroup(“ag1”).setFocus();

rule "agenda-group1"
	agenda-group "ag1"
  when 
    //这里如果为空,则表示eval(true)
  then
    System.out.println("hello word");
end
rule "agenda-group2"
	agenda-group "ag2"
  when 
    //这里如果为空,则表示eval(true)
  then
    System.out.println("hello word");
end

如果有两个规则体的agenda-group属性相同,都可以被激活

agenda-groupactivation-group结果说明
是否同一Focus只会执行其中一个规则。执行顺序根据优化级控制,默认为从上到下
只有获取焦点的规则才会被激活
会执行多个规则,但只有获取Focus的规则才会被激活
只有获取焦点的规则才会被激活

11、auto-focus
作用:auto-focus 属性为自动获取焦点,即当前规则是否被激活,如果一个规则被执行,那么认为auto-focus为true;如果单独设置,一般结合agenda-group。当一个agenda-group没有获取焦点时,可以用auto-focus来控制。

12、timer
作用:用来控制规则的执行时间。
用法:
①timer(int:30s) timer(int:30s 5m)
②timer(cron:0/1****?)
③timer(int:30s 10s; start=3-JAN-2018,end=5-JAN-2018)
示例:

rule "timer1"
	timer(int:3s) //每三秒执行一次
  when 
    //这里如果为空,则表示eval(true)
  then
    System.out.println("hello word");
end
rule "timer2"
	timer(cron:0/1****?) //每一秒执行一次
  when 
    //这里如果为空,则表示eval(true)
  then
    System.out.println("hello word");
end

项目地址

项目源码获取方式,识别下方二维码,回复 【drools】即可获取下载链接
公众号链接

  • 0
    点赞
  • 0
    评论
  • 4
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 1024 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值