规则引擎Drools基础应用

语音版博客点击收听

上一期入门篇:点击跳转

规则文件构成


在使用Drools时,通常规则文件的后缀为 .drlDrools Rule Language

完整规则文件内容的构成如下:

关键字描述
package包名,只限于逻辑上的管理,同一个包名下的查询或函数可以直接调用
import用于导入类或静态方法
global全局变量
function自定义函数
query查询
rule end规则体
Drools之城的规则文件,除了drl,还有 Excel 文件类型的。

规则语法结构


规则语法结构如下:

rule "ruleName"
	attributes
	when
		LHS
	then
		RHS
end
  • rule:关键字,表示规则开始,参数为规则的唯一名称。
  • attributes:规则属性,是rule与when之间的参数,可为选项。
  • when:关键字,后面跟规则的条件部分
    • LHSLeft Hand Side):是规则的条件部分的通用名称。它由零个或多个条件元素组成。如果LHS为空,则它将视为始终为true的条件元素 【左手边】
  • then:关键字,后面跟规则的结果部分。
    • RHSRight Hand Side):是规则的后果或行动部分的通用名称。 【右手边】
  • end:关键字,表示一个规则的结束。

注释


drl 形式的规则文件中,使用注释和Java类中使用注释一致,分为 单行注释多行注释

示例:

//规则rule1的注释,这是一个单行注释
rule "rule1"
    when
    then
        System.out.println("rule1触发");
end

/*
规则rule2的注释,
这是一个多行注释
*/
rule "rule2"
    when
    then
        System.out.println("rule2触发");
end

Pattern模式匹配


LHS部分由一个或者多个条件组成,条件又称为pattern。

pattern的语法结构为:绑定变量名:Object(Field约束)

其中绑定变量名可以省略,通常变量名以 $ 开始。
如果定义了绑定变量名,就可以在规则体的 RHS 部分使用此变量名来操作对应的 Fact 对象。Field约束部分是需要返回true或false的0个或多个表达式。

例如我们的入门案例中:

//规则二:100元 - 500元 加100分  
rule "order_rule_2"  
    when  
        $order:Order(amout >= 100 && amout < 500)  
    then  
         $order.setScore(100);  
         System.out.println("成功匹配到规则二:100元 - 500元 加100分");  
end

通过上面的例子我们可以知道,匹配的条件为:

  1. 工作内存中必须存在Order这种类型的Fact对象-----类型约束
  2. Fact对象的amout属性值必须大于等于100------属性约束
  3. Fact对象的amout属性值必须小于100------属性约束

以上条件必须同时满足当前规则才有可能被激活。

比较操作符


Drools提供的比较操作符,如下表:

符号说明
>大于
<小于
>=大于等于
<=小于等于
==等于
!=不等于
contains检查一个Fact对象的某个属性值是否包含一个指定的对象值
not contains检查一个Fact对象的某个属性值是否不包含在一个指定对象值
memberOf判断一个Fact对象的某个属性是否在一个或多个集合中
not memberOf判断一个Fact对象的某个属性是否不在一个或多个集合中
matches判断一个Fact对象的属性是否与提供的标准的Java正则表达式进行匹配
not matches判断一个Fact对象的属性是否不与提供的标准的Java正则表达式进行匹配

Drools内置方法


Drools提供了一些方法可以用来操作工作内存中的数据,**操作完成后规则引擎会重新进行相关规则的匹配,**原来没有匹配成功的规则在我们修改数据完成后有可能就会匹配成功了。

update方法

update方法的作用是更新工作内存中的数据,并让相关的规则重新匹配。 (要避免死循环)

参数:

// Fact对象,事实对象
Order order = new Order();
order.setAmount(30);

规则:

package  com.order  
import com.zxb.drools.model.Order  
  
// 规则一:100元以下 不加分  
rule "order_rule_1"  
    when  
        $order:Order(amount < 100)  
    then  
        $order.setAmount(150);  
        update($order) // update方法用于更新Fact对象, 会导致相关规则重新匹配  
        System.out.println("成功匹配规则1,不加分");  
end  
  
// 规则二:100 - 150 加100分  
rule "order_rule_2"  
when  
    $order:Order(amount >= 100, amount < 150)  
then  
    $order.setScore(100);  
    System.out.println("成功匹配规则2,订单加分100分");  
end

测试结果:

2025-07-27T21:47:56.644+08:00  INFO 20424 --- [drools_demo] [           main] o.d.c.kie.builder.impl.KieContainerImpl  : Start creation of KieBase: defaultKieBase
2025-07-27T21:47:56.742+08:00  INFO 20424 --- [drools_demo] [           main] o.d.c.kie.builder.impl.KieContainerImpl  : End creation of KieBase: defaultKieBase
成功匹配到规则二:100 - 500 元 加100分
订单金额: 100.0, 添加积分: 100.0

insert方法

insert方法的作用是向工作内存中插入数据,并让相关的规则重新匹配。

//规则一:100元以下 不加分
rule "order_rule_1"
    when
        $order:Order(amout < 100)
    then
        Order order = new Order();
        order.setAmout(130);
        insert(order);      //insert方法的作用是向工作内存中插入Fact对象,会导致相关规则重新匹配
        System.out.println("成功匹配到规则一:100元以下 不加分");
end

//规则二:100元 - 500元 加100分
rule "order_rule_2"
    when
        $order:Order(amout >= 100 && amout < 500)
    then
         $order.setScore(100);
         System.out.println("成功匹配到规则二:100元 - 500元 加100分");
end

效果如下:

2025-07-27T21:59:03.920+08:00  INFO 23920 --- [drools_demo] [           main] o.d.c.kie.builder.impl.KieContainerImpl  : Start creation of KieBase: defaultKieBase
2025-07-27T21:59:04.021+08:00  INFO 23920 --- [drools_demo] [           main] o.d.c.kie.builder.impl.KieContainerImpl  : End creation of KieBase: defaultKieBase
成功匹配规则1,不加分
成功匹配规则2,订单加分100分
订单金额: 90.0, 添加积分: 0.0

retract方法

retract方法的作用是删除工作内存中的数据,并让相关的规则重新匹配。

//规则一:100元以下 不加分
rule "order_rule_1"
    when
        $order:Order(amout < 100)
    then
        retract($order)      //retract方法的作用是删除工作内存中的Fact对象,会导致相关规则重新匹配
        System.out.println("成功匹配到规则一:100元以下 不加分");
end

效果如下:

2025-07-27T22:00:55.500+08:00  INFO 41324 --- [drools_demo] [           main] o.d.c.kie.builder.impl.KieContainerImpl  : Start creation of KieBase: defaultKieBase
2025-07-27T22:00:55.595+08:00  INFO 41324 --- [drools_demo] [           main] o.d.c.kie.builder.impl.KieContainerImpl  : End creation of KieBase: defaultKieBase
成功匹配规则1,不加分
订单金额: 90.0, 添加积分: 0.0

规则属性


Drools中提供的属性如下表(部分属性):

属性名说明
salience指定规则执行优先级
dialect指定规则使用的语言类型,取值为java和mvel
enabled指定规则是否启用
date-effective指定规则生效时间
date-expires指定规则失效时间
activation-group激活分组,具有相同分组名称的规则只能有一个规则触发
agenda-group议程分组,只有获取焦点的组中的规则才有可能触发
timer定时器,指定规则触发的时间
auto-focus自动获取焦点,一般结合agenda-group一起使用
no-loop防止死循环
salience属性

salience属性用于指定规则的执行优先级,取值类型为Integer数值越大越优先执行。每个规则都有一个默认的执行顺序,如果不设置salience属性,规则题默认的执行顺序为由上到下

可以通过创建规则文件 salience.drl 来测试:

package com.order  
  
rule "rule_1"  
    when  
        eval(true)  
    then  
        System.out.println("规则rule_1触发");  
end  
  
rule "rule_2"  
    when  
        eval(true)  
    then  
        System.out.println("规则rule_2触发");  
end  
  
rule "rule_3"  
    when  
        eval(true)  
    then  
        System.out.println("规则rule_3触发");  
end

输出:

规则rule_1触发
规则rule_2触发
规则rule_3触发

修改为使用 salience 的:

package com.order  
  
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

输出:

规则rule_2触发
规则rule_1触发
规则rule_3触发
no-loop属性

no-loop属性用于防止死循环,当规则通过update之类的函数修改了Fact对象时,可能使当前规则再次被激活从而导致死循环。取值类型为Boolean,默认值为false,测试规则如下:

// 订单积分规则  
package com.order  
import com.zxb.drools.model.Order  
  
// 规则一:100元以下 不加分  
rule "order_rule_1"  
    no-loop true // 防止陷入死循环  
    when  
        $order:Order(amount < 100)  
    then  
        $order.setScore(0);  
        update($order)  
        System.out.println("成功匹配规则一: 100元以下 不加分");  
end

输出结果:

成功匹配规则一: 100元以下 不加分
订单金额: 90.0, 添加积分: 0.0

Drools高级语法


前面章节我们已经知道了一套完整的规则文件内容构成如下:

关键字描述
package包名,只限于逻辑上的管理,同一个包名下的查询或者函数可以直接调用
import用于导入类或者静态方法
global全局变量
function自定义函数
query查询
rule end规则体

重点说一下我们项目需要使用的属性

global全局变量

global关键字用于在规则文件中定义全局变量,它可以让应用程序的对象在规则文件中能够被访问。可以用来为规则文件提供数据或服务。

语法结构为:global 对象类型 对象名称

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

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

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

订单Order:

package com.atguigu.drools.model;public class Order {private double amout;public double getAmout() {  
        return amout;  
    }public void setAmout(double amout) {  
        this.amout = amout;  
    }}

积分Integral:

package com.atguigu.drools.model;public class Integral {private double score;public double getScore() {  
        return score;  
    }public void setScore(double score) {  
        this.score = score;  
    }  
}

规则文件:

//订单积分规则  
package com.order  
import com.atguigu.drools.model.Order  
​  
global com.atguigu.drools.model.Integral integral;//规则一:100元以下 不加分  
rule "order_rule_1"  
    no-loop true         //防止陷入死循环  
    when  
        $order:Order(amout < 100)  
    then  
        integral.setScore(10);  
        update($order)  
        System.out.println("成功匹配到规则一:100元以下 不加分");  
end

测试:

@Test  
public void test1(){  
    //从Kie容器对象中获取会话对象  
    KieSession session = kieContainer.newKieSession();//Fact对象,事实对象  
    Order order = new Order();  
    order.setAmout(30);//全局变量  
    Integral integral = new Integral();  
    session.setGlobal("integral", integral);//将Order对象插入到工作内存中  
    session.insert(order);//激活规则,由Drools框架自动进行规则匹配,如果规则匹配成功,则执行当前规则  
    session.fireAllRules();  
    //关闭会话  
    session.dispose();System.out.println("订单金额:" + order.getAmout());  
    System.out.println("添加积分:" + integral.getScore());  
}

欢迎关注我的公众号【zxb的博客】!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值