一、Drools 规则引擎

news2024/11/26 15:28:01

一、问题引出

  • 现有一个在线申请信用卡的业务场景,用户需要录入个人信息,如下图所示:
    在这里插入图片描述
  • 通过上图可以看到,用户录入的个人信息包括 姓名、性别、年龄、学历、电话、所在公司、职位、月收入、是否有房、是否有车、是否有信用卡等。录入完成后点击申请按钮提交即可。
  • 用户提交申请后,需要在系统的服务端进行用户信息合法性检查(是否有资格申请信用卡),只有通过合法性检查的用户才可以成功申请到信用卡(注意:不同用户有可能申请到的信用卡额度不同)。
  • 检查用户信息合法性的规则如下:

规则编号名称描述
1检查学历与薪水1如果申请人既没房也没车,同时学历为大专以下,并且月薪少于5000,那么不通过
2检查学历与薪水2如果申请人既没房也没车,同时学历为大专或本科,并且月薪少于3000,那么不通过
3检查学历与薪水3如果申请人既没房也没车,同时学历为本科以上,并且月薪少于2000,同时之前没有信用卡的,那么不通过
4检查申请人已有的信用卡数量如果申请人现有的信用卡数量大于10,那么不通过

  • 用户信息合法性检查通过后,还需要根据如下信用卡发放规则确定用户所办信用卡的额度:
规则编号名称描述
1规则1如果申请人有房有车,或者月收入在20000以上,那么发放的信用卡额度为15000
2规则2如果申请人没房没车,但月收入在10000~20000之间,那么发放的信用卡额度为6000
3规则3如果申请人没房没车,月收入在10000以下,那么发放的信用卡额度为3000
4规则4如果申请人有房没车或者没房但有车,月收入在10000以下,那么发放的信用卡额度为5000
5规则5如果申请人有房没车或者是没房但有车,月收入在10000~20000之间,那么发放的信用卡额度为8000
  • 思考:如何实现上面的业务逻辑呢?
  • 我们最容易想到的就是使用分支判断(if else)来实现,例如通过如下代码来检查用户信息合法性:
//检查用户信息合法性,返回true表示检查通过,返回false表示检查不通过
public boolean checkUser(User user) {
    //如果申请人既没房也没车,同时学历为大专以下,并且月薪少于5000,那么不通过
    if (user.getHouse() == null
            && user.getCar() == null
            && user.getEducation().equals("大专以下")
            && user.getSalary() < 5000) {
        return false;
    }
    //如果申请人既没房也没车,同时学历为大专或本科,并且月薪少于3000,那么不通过
    else if (user.getHouse() == null
            && user.getCar() == null
            && user.getEducation().equals("大专或本科")
            && user.getSalary() < 3000) {
        return false;
    }
    //如果申请人既没房也没车,同时学历为本科以上,并且月薪少于2000,同时之前没有信用卡的,那么不通过
    else if (user.getHouse() == null
            && user.getCar() == null
            && user.getEducation().equals("本科以上")
            && user.getSalary() < 2000
            && !user.getHasCreditCard()) {
        return false;
    }
    //如果申请人现有的信用卡数量大于10,那么不通过
    else return user.getCreditCardCount() <= 10;
}
  • 如果用户信息合法性检查通过后,还需要通过如下代码确定用户所办信用卡的额度:
//根据用户输入信息确定信用卡额度
public Integer determineCreditCardLimit(User user) {
    //如果申请人有房有车,或者月收入在20000以上,那么发放的信用卡额度为15000
    if ((user.getHouse() != null && user.getCar() != null)
            || user.getSalary() > 20000) {
        return 15000;
    }
    //如果申请人没房没车,并且月收入在10000到20000之间,那么发放的信用卡额度为6000
    else if (user.getHouse() == null
            && user.getCar() == null
            && user.getSalary() > 10000
            && user.getSalary() < 20000) {
        return 6000;
    }
    //如果申请人没房没车,并且月收入在10000以下,那么发放的信用卡额度为3000
    else if (user.getHouse() == null
            && user.getCar() == null
            && user.getSalary() < 10000) {
        return 3000;
    }
    //如果申请人有房没车或者没房但有车,并且月收入在10000以下,那么发放的信用卡额度为5000
    else if (((user.getHouse() != null && user.getCar() == null)
            || (user.getHouse() == null && user.getCar() != null))
            && user.getSalary() < 10000) {
        return 5000;
    }
    //如果申请人有房没车或者没房但有车,并且月收入在10000到20000之间,那么发放的信用卡额度为8000
    else if (((user.getHouse() != null && user.getCar() == null)
            || (user.getHouse() == null && user.getCar() != null))
            && (user.getSalary() > 10000 && user.getSalary() < 20000)) {
        return 8000;
    }
    return 0;
}
  • 通过上面的伪代码我们可以看到,我们的业务规则是通过 Java 代码的方式实现的。这种实现方式存在如下问题:
  1. 硬编码实现业务规则难以维护
  2. 硬编码实现业务规则难以应对变化
  3. 业务规则发生变化需要修改代码,重启服务后才能生效

二、规则引擎


1. 规则引擎概述

  • 规则引擎,全称为业务规则管理系统,英文名为BRMS(即 Business Rule Management System)。规则引擎的主要思想是将应用程序中的业务决策部分分离出来,并使用预定义的语义模块编写业务决策(业务规则),由用户或开发者在需要时进行配置、管理。
  • 需要注意的是规则引擎并不是一个具体的技术框架,而是指的一类系统,即业务规则管理系统。目前市面上具体的规则引擎产品有:Drools、VisualRules、iLog 等。
  • 规则引擎实现了将业务决策从应用程序代码中分离出来,接收数据输入,解释业务规则,并根据业务规则做出业务决策。规则引擎其实就是一个输入输出平台。
  • 上面的申请信用卡业务场景使用规则引擎后效果如下:
    在这里插入图片描述
  • 系统中引入规则引擎后,业务规则不再以程序代码的形式驻留在系统中,取而代之的是处理规则的规则引擎,业务规则存储在规则库中,完全独立于程序。业务人员可以像管理数据一样对业务规则进行管理,比如 查询、添加、更新、统计、提交 业务规则等。业务规则被加载到规则引擎中供应用系统调用。

2. 规则引擎优势

  • 使用规则引擎的优势如下:
  1. 业务规则与系统代码分离,实现业务规则的集中管理
  2. 在不重启服务的情况下可随时对业务规则进行扩展和维护
  3. 可以动态修改业务规则,从而快速响应需求变更
  4. 规则引擎是相对独立的,只关心业务规则,使得业务分析人员也可以参与编辑、维护系统的业务规则
  5. 减少了硬编码业务规则的成本和风险
  6. 使用规则引擎提供的规则编辑工具,使复杂的业务规则实现变得的简单

3. 规则引擎应用场景

  • 对于一些存在比较复杂的业务规则并且业务规则会频繁变动的系统比较适合使用规则引擎,如下:
  1. 风险控制系统----风险贷款、风险评估
  2. 反欺诈项目----银行贷款、征信验证
  3. 决策平台系统----财务计算
  4. 促销平台系统----满减、打折、加价购

三、Drools 介绍

  • Drools 是一款由 JBoss 组织提供的基于 Java 语言开发的开源规则引擎,可以将复杂且多变的业务规则从硬编码中解放出来,以规则脚本的形式存放在文件或特定的存储介质中(例如存放在数据库中),使得业务规则的变更不需要修改项目代码、重启服务器就可以在线上环境立即生效。
  • Drools 官网
  • Drools 源码
  • 在项目中使用 Drools 时,即可以单独使用也可以整合 Spring 使用。如果单独使用只需要导入如下 Maven 坐标即可:
<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-compiler</artifactId>
    <version>7.6.0.Final</version>
</dependency>
  • 如果我们使用 IDEA 开发 Drools 应用,IDEA 中已经集成了 Drools 插件。如果使用 Eclipse 开发 Drools 应用还需要单独安装 Drools 插件。
  • Drools API 开发步骤如下:
    在这里插入图片描述

1. Drools 入门案例

  • 本小节通过一个 Drools 入门案例来让大家初步了解 Drools 的使用方式、对 Drools 有一个整体概念。

1.1 业务场景说明

  • 业务场景:消费者在图书商城购买图书,下单后需要在支付页面显示订单优惠后的价格。具体优惠规则如下:
规则编号规则名称描述
1规则一所购图书总价在100元以下的没有优惠
2规则二所购图书总价在100到200元的优惠20元
3规则三所购图书总价在200到300元的优惠50元
4规则四所购图书总价在300元以上的优惠100元
  • 现在需要根据上面的规则计算优惠后的价格。

1.2 开发实现

  • 第一步:创建 Maven 工程 drools 并导入 Drools 相关 Maven 坐标:
<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-compiler</artifactId>
    <version>7.10.0.Final</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

  • 第二步:根据 Drools 要求创建 resources/META-INF/kmodule.xml 配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
    <!--
        name: 指定 kbase 的名称,可以任意,但是需要唯一
        packages: 指定规则文件的目录,需要根据实际情况填写,否则无法加载到规则文件
        default: 指定当前 kbase 是否为默认
    -->
    <kbase name="myKbase1" packages="rules" default="true">
        <!--
            name: 指定 ksession 名称,可以任意,但是需要唯一
            default: 指定当前 session 是否为默认
        -->
        <ksession name="ksession-rule" default="true"/>
    </kbase>
</kmodule>
  • 注意:上面配置文件的名称和位置都是固定写法,不能更改

  • 第三步:创建实体类 Order
/**
 * @author wy
 * describe 订单
 */
@Data
public class Order {

    /**
     * 订单原始价格,即优惠前价格
     */
    private Double originalPrice;

    /**
     * 订单真实价格,即优惠后价格
     */
    private Double realPrice;

}

  • 第四步:创建规则文件 resources/rules/test_bookDiscount.drl
//图书优惠规则
package book.discount
import com.qs.drools.entity.Order

//规则一:所购图书总价在100元以下的没有优惠
rule "book_discount_1"
    when
        $order:Order(originalPrice < 100)
    then
        $order.setRealPrice($order.getOriginalPrice());
        System.out.println("成功匹配到规则一: 所购图书总价在100元以下的没有优惠");
end

//规则二:所购图书总价在100到200元的优惠20元
rule "book_discount_2"
    when
        $order:Order(originalPrice < 200 && originalPrice >= 100)
    then
        $order.setRealPrice($order.getOriginalPrice() - 20);
        System.out.println("成功匹配到规则二: 所购图书总价在100到200元的优惠20元");
end

//规则三:所购图书总价在200到300元的优惠50元
rule "book_discount_3"
    when
        $order:Order(originalPrice <= 300 && originalPrice >= 200)
    then
        $order.setRealPrice($order.getOriginalPrice() - 50);
        System.out.println("成功匹配到规则三: 所购图书总价在200到300元的优惠50元");
end

//规则四:所购图书总价在300元以上的优惠100元
rule "book_discount_4"
    when
        $order:Order(originalPrice >= 300)
    then
        $order.setRealPrice($order.getOriginalPrice() - 100);
        System.out.println("成功匹配到规则四: 所购图书总价在300元以上的优惠100元");
end

  • 第五步:编写单元测试
@Test
public void test1() {
    KieServices kieServices = KieServices.Factory.get();
    KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
    //会话对象,用于和规则引擎交互
    KieSession kieSession = kieClasspathContainer.newKieSession();

    //构造订单对象,设置原始价格,由规则引擎根据优惠规则计算优惠后的价格
    Order order = new Order();
    order.setOriginalPrice(210D);

    //将数据提供给规则引擎,规则引擎会根据提供的数据进行规则匹配
    kieSession.insert(order);

    //激活规则引擎,如果规则匹配成功则执行规则
    kieSession.fireAllRules();
    //关闭会话
    kieSession.dispose();

    System.out.println("order.getOriginalPrice() = " + order.getOriginalPrice());
    System.out.println("order.getRealPrice() = " + order.getRealPrice());
}
  • 通过上面的入门案例我们可以发现,使用 Drools 规则引擎主要工作就是编写规则文件,在规则文件中定义跟业务相关的业务规则,例如本案例定义的就是图书优惠规则。规则定义好后就需要调用 Drools 提供的 API 将数据提供给规则引擎进行规则模式匹配,规则引擎会执行匹配成功的规则并将计算的结果返回给我们。
  • 可能大家会有疑问,就是我们虽然没有在代码中编写规则的判断逻辑,但是我们还是在规则文件中编写了业务规则,这跟在代码中编写规则有什么本质的区别呢?
  • 我们前面其实已经提到,使用规则引擎时业务规则可以做到动态管理。业务人员可以像管理数据一样对业务规则进行管理,比如 查询、添加、更新、统计、提交业务规则 等。这样就可以做到在不重启服务的情况下调整业务规则。

1.3 案例小结

规则引擎构成

  • Drools 规则引擎由以下三部分构成:
  1. Working Memory(工作内存)
  2. Rule Base(规则库)
  3. Inference Engine(推理引擎)
  • 其中 Inference Engine(推理引擎)又包括:
  1. Pattern Matcher(匹配器)
  2. Agenda(议程)
  3. Execution Engine(执行引擎)
  • 如下图所示:
    在这里插入图片描述

相关概念说明

  • Working Memory:工作内存,Drools 规则引擎会从 Working Memory 中获取数据并和规则文件中定义的规则进行模式匹配,所以我们开发的应用程序只需要将我们的数据插入到 Working Memory 中即可,例如本案例中我们调用 kieSession.insert(order) 就是将 order 对象插入到了工作内存中。
  • Fact:事实,是指在 Drools 规则应用当中,将一个普通的 JavaBean 插入到 Working Memory 后的对象就是 Fact 对象,例如本案例中的 Order 对象就属于 Fact 对象。Fact 对象是我们的应用和规则引擎进行数据交互的桥梁或通道。
  • Rule Base:规则库,我们在规则文件中定义的规则都会被加载到规则库中。
  • Pattern Matcher:匹配器,将 Rule Base 中的所有规则与 Working Memory 中的 Fact 对象进行模式匹配,匹配成功的规则将被激活并放入 Agenda 中。
  • Agenda:议程,用于存放通过匹配器进行模式匹配后被激活的规则。
  • Execution Engine:执行引擎,执行 Agenda 中被激活的规则。

规则引擎执行过程
在这里插入图片描述


KIE 介绍

  • 我们在操作 Drools 时经常使用的 API 以及它们之间的关系如下图:
    在这里插入图片描述
  • 通过上面的核心 API 可以发现,大部分类名都是以 Kie 开头。Kie 全称为(Knowledge Is Everything,即"知识就是一切"的缩写),是 Jboss 一系列项目的总称。如下图所示,Kie 的主要模块有 OptaPlanner、Drools、UberFire、jBPM。
    在这里插入图片描述
  • 通过上图可以看到,Drools 是整个 KIE 项目中的一个组件,Drools 中还包括一个 Drools-WB 的模块,它是一个可视化的规则编辑器。

2. Drools 基础语法


2.1 规则文件构成

  • 在使用 Drools 时非常重要的一个工作就是编写规则文件,通常规则文件的后缀为 .drl。
  • drl 是Drools Rule Language 的缩写。在规则文件中编写具体的规则内容。
  • 一套完整的规则文件内容构成如下:
关键字描述
package包名,只限于逻辑上的管理,同一个包名下的查询或者函数可以直接调用
import用于导入类或者静态方法
global全局变量
function自定义函数
query查询
rule end规则体
  • Drools 支持的规则文件,除了drl 形式,还有 Excel 文件类型的。

2.2 规则体语法结构

  • 规则体是规则文件内容中的重要组成部分,是进行 业务规则判断、处理业务结果 的部分。
  • 规则体语法结构如下:
rule "ruleName"
    attributes
    when
        LHS
    then
        RHS
end
  • rule:关键字,表示规则开始,参数为规则的唯一名称。
  • attributes:规则属性,是 rule 与 when 之间的参数,为可选项。
  • when:关键字,后面跟规则的条件部分。
  • LHS(Left Hand Side):是规则的条件部分的通用名称。它由零个或多个条件元素组成。如果 LHS 为空,则它将被视为始终为 true 的条件元素。
    then:关键字,后面跟规则的结果部分。
  • RHS(Right Hand Side):是规则的后果或行动部分的通用名称。
  • end:关键字,表示一个规则结束。

2.3 注释

  • 在 drl 形式的规则文件中使用注释和 Java 类中使用注释一致,分为单行注释和多行注释。
  • 单行注释用 “//” 进行标记,多行注释以 “/" 开始,以 "/” 结束。如下示例:
//规则rule1的注释,这是一个单行注释
rule "rule1"
    when
    then
        System.out.println("rule1触发");
end
​
/*
规则rule2的注释,
这是一个多行注释
*/
rule "rule2"
    when
    then
        System.out.println("rule2触发");
end

2.4 Pattern 模式匹配

  • 前面我们已经知道了 Drools 中的匹配器可以将 Rule Base 中的所有规则与 Working Memory 中的 Fact 对象进行模式匹配,那么我们就需要在规则体的 LHS 部分定义规则并进行模式匹配。LHS 部分由一个或者多个条件组成,条件又称为 Pattern。
  • Pattern 的语法结构为:绑定变量名:Object(Field 约束)
  • 其中绑定变量名可以省略,通常绑定变量名的命名一般建议以 $ 开始。如果定义了绑定变量名,就可以在规则体的 RHS 部分使用此绑定变量名来操作相应的 Fact对象。Field 约束部分是需要返回 true 或者 false 的 0 个或多个表达式。
  • 例如我们的入门案例中:
//规则二:所购图书总价在100到200元的优惠20元
rule "book_discount_2"
    when
        //Order为类型约束,originalPrice为属性约束
        $order:Order(originalPrice < 200 && originalPrice >= 100)
    then
        $order.setRealPrice($order.getOriginalPrice() - 20);
        System.out.println("成功匹配到规则二:所购图书总价在100到200元的优惠20元");
end
  • 通过上面的例子我们可以知道,匹配的条件为:
  1. 工作内存中必须存在Order这种类型的Fact对象-----类型约束
  2. Fact 对象的 originalPrice 属性值必须小于200------属性约束
  3. Fact 对象的 originalPrice 属性值必须大于等于100------属性约束
  • 以上条件必须同时满足当前规则才有可能被激活。

  • 绑定变量既可以用在对象上,也可以用在对象的属性上。例如上面的例子可以改为:
//规则二:所购图书总价在100到200元的优惠20元
rule "book_discount_2"
    when
        $order:Order($op:originalPrice < 200 && originalPrice >= 100)
    then
        System.out.println("$op=" + $op);
        $order.setRealPrice($order.getOriginalPrice() - 20);
        System.out.println("成功匹配到规则二:所购图书总价在100到200元的优惠20元");
end

  • LHS 部分还可以定义多个 Pattern,多个 Pattern 之间可以使用 and 或者 or 进行连接,也可以不写,默认连接为 and。
//规则二:所购图书总价在100到200元的优惠20元
rule "book_discount_2"
    when
        $order:Order($op:originalPrice < 200 && originalPrice >= 100) and
        $customer:Customer(age > 20 && gender=='male')
    then
        System.out.println("$op=" + $op);
        $order.setRealPrice($order.getOriginalPrice() - 20);
        System.out.println("成功匹配到规则二:所购图书总价在100到200元的优惠20元");
end

2.5 比较操作符

  • Drools 提供的比较操作符,如下表:
符号说明
>大于
<小于
>=大于等于
<=小于等于
==等于
!=不等于
contains检查一个Fact对象的某个属性值是否包含一个指定的对象值
not contains检查一个Fact对象的某个属性值是否不包含一个指定的对象值
memberOf判断一个Fact对象的某个属性是否在一个或多个集合中
not memberOf判断一个Fact对象的某个属性是否不在一个或多个集合中
matches判断一个Fact对象的属性是否与提供的标准的Java正则表达式进行匹配
not matches判断一个Fact对象的属性是否不与提供的标准的Java正则表达式进行匹配
  • 前 6 个比较操作符和 Java 中的完全相同,下面我们重点学习后 6 个比较操作符。
// contains | not contains语法结构
Object(Field[Collection/Array] contains value)
Object(Field[Collection/Array] not contains value)

//memberOf | not memberOf语法结构
Object(field memberOf value[Collection/Array])
Object(field not memberOf value[Collection/Array])

//matches | not matches语法结构
Object(field matches "正则表达式")
Object(field not matches "正则表达式")

操作步骤

  • 第一步:创建实体类,用于测试比较操作符
/**
 * @author wy
 * describe
 */
@Data
public class ComparisonOperatorEntity {

    private String names;
    private List<String> list;

}

  • 第二步:在. /resources/rules 下创建规则文件test_comparisonOperator.drl
package comparisonOperator
import com.qs.drools.entity.ComparisonOperatorEntity
/*
 当前规则文件用于测试Drools提供的比较操作符
*/

//测试比较操作符contains
rule "rule_comparison_contains"
    when
        ComparisonOperatorEntity(names contains "张三")
        ComparisonOperatorEntity(list contains names)
    then
        System.out.println("规则rule_comparison_contains触发");
end

//测试比较操作符not contains
rule "rule_comparison_notContains"
    when
        ComparisonOperatorEntity(names not contains "张三")
        ComparisonOperatorEntity(list not contains names)
    then
        System.out.println("规则rule_comparison_notContains触发");
end

//测试比较操作符memberOf
rule "rule_comparison_memberOf"
    when
        ComparisonOperatorEntity(names memberOf list)
    then
        System.out.println("规则rule_comparison_memberOf触发");
end

//测试比较操作符not memberOf
rule "rule_comparison_notMemberOf"
    when
        ComparisonOperatorEntity(names not memberOf list)
    then
        System.out.println("规则rule_comparison_notMemberOf触发");
end

//测试比较操作符matches
rule "rule_comparison_matches"
    when
        ComparisonOperatorEntity(names matches "张.*")
    then
        System.out.println("规则rule_comparison_matches触发");
end

//测试比较操作符not matches
rule "rule_comparison_notMatches"
    when
        ComparisonOperatorEntity(names not matches "张.*")
    then
        System.out.println("规则rule_comparison_notMatches触发");
end

  • 第三步:编写单元测试
@Test
public void test() {
    KieServices kieServices = KieServices.Factory.get();
    KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
    KieSession kieSession = kieClasspathContainer.newKieSession();

    ComparisonOperatorEntity comparisonOperatorEntity = new ComparisonOperatorEntity();
    comparisonOperatorEntity.setNames("张三");
    List<String> list = new ArrayList<String>();
    list.add("张三");
    list.add("李四");
    comparisonOperatorEntity.setList(list);

    //将数据提供给规则引擎,规则引擎会根据提供的数据进行规则匹配,如果规则匹配成功则执行规则
    kieSession.insert(comparisonOperatorEntity);

    kieSession.fireAllRules();
    kieSession.dispose();
}

2.6 执行指定规则

  • 通过前面的案例可以看到,我们在调用规则代码时,满足条件的规则都会被执行。那么如果我们只想执行其中的某个规则如何实现呢?
  • Drools 给我们提供的方式是通过规则过滤器来实现执行指定规则。对于规则文件不用做任何修改,只需要修改 Java 代码即可,如下:
@Test
public void test2() {
    KieServices kieServices = KieServices.Factory.get();
    KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
    KieSession kieSession = kieClasspathContainer.newKieSession();

    ComparisonOperatorEntity comparisonOperatorEntity = new ComparisonOperatorEntity();
    comparisonOperatorEntity.setNames("张三");
    List<String> list = new ArrayList<String>();
    list.add("张三");
    list.add("李四");
    comparisonOperatorEntity.setList(list);
    kieSession.insert(comparisonOperatorEntity);

    //通过规则过滤器实现只执行指定规则
    kieSession.fireAllRules(new RuleNameEqualsAgendaFilter("rule_comparison_memberOf"));

    kieSession.dispose();
}

2.7 关键字

  • Drools 的关键字分为:硬关键字(Hard keywords)和软关键字(Soft keywords)。
  • 硬关键字是我们在规则文件中定义包名或者规则名时明确不能使用的,否则程序会报错。软关键字虽然可以使用,但是不建议使用。
  • 硬关键字包括:true、false、null
  • 软关键字包括:lock-on-active、date-effective、date-expires、no-loop、auto-focus、activation-group、agenda-group、ruleflow-group、entry-point、duration、package、import、dialect、salience、enabled、attributes、rule、extend、when、then、template、query、declare、function、global、eval、not、in、or、and、exists、forall、accumulate、collect、from、action、reverse、result、end、over、init

2.8 Drools 内置方法

  • 规则文件的 RHS 部分的主要作用是通过插入,删除或修改工作内存中的 Fact 数据,来达到控制规则引擎执行的目的。Drools 提供了一些方法可以用来操作工作内存中的数据,操作完成后规则引擎会重新进行相关规则的匹配,原来没有匹配成功的规则在我们修改数据完成后有可能就会匹配成功了。

  • 创建如下实体类:
/**
 * @author wy
 * describe 学生
 */
@Data
public class Student {

    private int id;
    private String name;
    private int age;

}

  • update 方法
    update 方法的作用是更新工作内存中的数据,并让相关的规则重新匹配。
  • 第一步:编写规则文件 /resources/rules/student.drl,文件内容如下
package student
import com.qs.drools.entity.Student

/*
 当前规则文件用于测试Drools提供的内置方法
*/

rule "rule_student_age小于10岁"
    when
        $s:Student(age < 10)
    then
        $s.setAge(15);
        update($s);//更新数据,导致相关的规则会重新匹配
        System.out.println("规则rule_student_age小于10岁触发");
end

rule "rule_student_age小于20岁同时大于10岁"
    when
        $s:Student(age < 20 && age > 10)
    then
        $s.setAge(25);
        update($s);//更新数据,导致相关的规则会重新匹配
        System.out.println("规则rule_student_age小于20岁同时大于10岁触发");
end

rule "rule_student_age大于20岁"
    when
        $s:Student(age > 20)
    then
        System.out.println("规则rule_student_age大于20岁触发");
end
  • 第二步:编写单元测试
@Test
public void test() {
    KieServices kieServices = KieServices.Factory.get();
    KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
    KieSession kieSession = kieClasspathContainer.newKieSession();

    Student student = new Student();
    student.setAge(5);

    //将数据提供给规则引擎,规则引擎会根据提供的数据进行规则匹配,如果规则匹配成功则执行规则
    kieSession.insert(student);

    kieSession.fireAllRules();
    kieSession.dispose();
}
  • 通过控制台的输出可以看到规则文件中定义的三个规则都触发了。
  • 在更新数据时需要注意防止发生死循环。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/627412.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Netty中ServerBootstrap类介绍

一、Netty基本介绍 Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具&#xff0c;用以快速开发高性能、高可靠性的网络服务器和客户端程序。Netty 在保证易于开发的同时还保证了其应用的性能&#xff0c;稳定性和伸缩性。 Netty 是一…

UE5 PCG模块学习1

这次来学习一下UE5.2中正式加入的PCG功能。网上较多的案例是在Landscape地形上创建贴合地面的物体&#xff0c;博主研究了一下&#xff0c;这个案例将创建贴合Mesh的物体&#xff1a; 1.基础生成 1.首先在插件中检查Procedural Content Generation Framework是否已经被开启&…

自学黑客的12个步骤

黑客攻防是一个极具魅力的技术领域&#xff0c;但成为一名黑客毫无疑问也并不容易。你必须拥有对新技术的好奇心和积极的学习态度&#xff0c;具备很深的计算机系统、编程语言和操作系统知识&#xff0c;并乐意不断地去学习和进步。 如果你想成为一名优秀的黑客&#xff0c;下…

Java 获取七牛云存储空间中的所有图片列表

文章目录 获取七牛云密钥导入依赖编辑 YAML 配置文件添加七牛云配置类编写 QiNiuImgUrls 方法测试结果 七牛云官方文档&#xff1a;https://developer.qiniu.com/kodo/sdk/java 如果有还不会使用SpringBoot整合七牛云存储的小伙伴们&#xff0c;可以跳转查看这篇文章&#xff1…

Revit中如何画弯曲的轴网和显示实时轴号?

一、Revit中如何画弯曲的轴网 生活中&#xff0c;有很多圆筒样式的建筑&#xff0c;比如说鸟巢和土楼&#xff0c;他们的外壁是弯曲的。所以&#xff0c;当我们用Revit创建这类模型时&#xff0c;轴网就要画弯曲的&#xff0c;那么&#xff0c;Revit中如何画弯曲的轴网呢&#…

JMeter接口压测和性能监测

引言 今天我来和大家分享一篇关于JMeter接口压测和性能监测的文章。在现代互联网时代&#xff0c;应用程序的性能已经成为了一个非常重要的问题&#xff0c;并且对于许多公司的生存和发展都起着至关重要的作用。 而在这其中&#xff0c;JMeter是一个非常实用的工具&#xff0…

CSAPP - AttackLab实验(阶段1-5)

AttackLab实验 实验内容 官网&#xff1a;http://csapp.cs.cmu.edu/3e/labs.html “AttackLab”是一个Linux下的可执行C程序&#xff0c;包含了5个阶段&#xff08;phase1~phase5&#xff09;的不同内容。程序运行过程中&#xff0c;要求学生能够根据缓冲区的工作方式和程序…

【Flutter】如何移除 Flutter 右上角的 DEBUG 标识

文章目录 一、前言二、什么是 DEBUG 标识三、为什么我们需要移除 DEBUG 标识四、如何移除 DEBUG 标识五、完整代码六、总结 一、前言 欢迎来到 Flutter 的世界&#xff01;在这篇文章中&#xff0c;我们将探索 Flutter 的一些基础知识。但是&#xff0c;你知道吗&#xff1f;这…

Science:“消除噪音”量子比特实现了纠错的重大突破

光子盒研究院 在《科学》杂志的一篇新论文中&#xff0c;芝加哥大学普利兹克分子工程学院Hannes Bernien助教实验室的研究人员描述了一种不断监测量子系统周围噪音并实时调整量子比特以减少误差的方法——他们引入了“旁观者量子比特(spectator qubit)”。 尽管他们有解决新型问…

数字图像处理实验报告

目录 实验二、图像在空间域上的处理方法 实验三、图像在频率域上的处理方法 实验二、图像在空间域上的处理方法 一、实验目的 了解图像亮&#xff08;灰&#xff09;度变换与空间滤波的意义和手段&#xff1b;熟悉图像亮&#xff08;灰&#xff09;度变换与空间滤波的MATLA…

买法拍房需要注意什么

法拍房&#xff0c;由于其价格亲民、房屋信息透明度高、竞拍过程公平公正而受到越来越多的人开始关注。但是其中又有着许多的风险及相关的注意事项。那么&#xff0c;如何做到成功“捡漏”&#xff0c;买法拍房需要注意什么呢? 买法拍房需要注意什么 1、隐藏的各种收费 税费&a…

优思学院|质量和可靠性是同一件事吗?

什么是质量&#xff1f; 质量是什么&#xff1f;早期的定义是“整体上用来决定产品或服务能否满足使用目的之固有性质与性能总合”&#xff0c;换言之&#xff0c;质量就是“可显示出品质与服务好坏的东西”。 不过&#xff0c;关于质量的想法随时代变化&#xff0c;有范围愈…

专访:诺奖得主Alain Aspect谈量子的挑战与未来

光子盒研究院出品 近期&#xff0c;诺贝尔物理学奖获得者Alain Aspect在接受电子工程专辑(EE Times Europe)采访时说&#xff1a;“诺贝尔奖是由于显示了纠缠的非凡特性而获得的&#xff0c;但我还研究了许多其他惊人的量子现象&#xff0c;包括将原子冷却到一光子反冲力以下。…

JavaWebHtmlCSS总结

目录 JavaWeb概述1.访问web的原理2.C/S软件和B/S软件区别3.静态网站和动态网站 HTMLHTML的概述Table表格详细用法见W3CSchool.chm合并单元格课程表 img标签table和img标签组合使用a标签表单表单Get提交和post提交 div和span CSS1.CSS概述2.CSS语法3.CSS三种写法行内样式内部样式…

专访泛境科技:如何借助3DCAT实时云渲染打造元宇宙解决方案

随着5G、VR/AR等技术的发展&#xff0c;元宇宙&#xff08;Metaverse&#xff09;这一概念越来越受到关注。元宇宙是一个由虚拟世界构成的网络空间&#xff0c;其中人们可以通过数字化的身份和形象进行各种社交、娱乐、创作和商业活动。元宇宙的核心是虚拟场景&#xff0c;它是…

教育信息化时代,如何打造中学理科信息化实验操作考场方案

近年来&#xff0c;我国考试招生制度不断改进完善&#xff0c;初步形成了相对完整的考试招生体系。但随着教育事业的逐步发展&#xff0c;国务院明确提出了改革考试形式和内容&#xff1a;完善中学学业水平考试&#xff0c;规范中考学生综合素质评价&#xff0c;加快推进中学院…

Promise.allSettled优化并行接口报错

问题背景 后端需要前端请求同一个接口三次&#xff0c;每次传参不同可以获取到不同的结果>构成计算资源的选项。 其中一个接口传参获取数据报错&#xff0c;导致整个计算资源都没有可选择的options&#xff1a; 前端代码使用Promise.all获取res1, res2, res3返回结果&…

云原生docker-cgroup资源限制

概述 Docker 通过 Cgroup 来控制容器使用的资源配额&#xff0c;包括 CPU、内存、磁盘三大方面&#xff0c; 基本覆盖了常见的资源配额和使用量控制。 Cgroup 是 ControlGroups 的缩写&#xff0c;是 Linux 内核提供的一种可以限制、记录、隔离进程组所使用的物理资源(如 CPU、…

【剑指offer】调整数组顺序使奇数位于偶数前面

文章目录 题目思路相对位置可以改变的思路相对位置不能改变的思路 题目 题目链接入口&#xff1a;调整数组顺序使奇数位于偶数前面 示例1&#xff1a; 输入&#xff1a;[1,2,3,4,5,6] 结果&#xff1a;[1,3,5,2,4,6] 示例2&#xff1a; 输入&#xff1a;[1,2,2,3,4,4,5,6,7…

2023年前端面试高频考点之 通信(渲染、http、缓存、异步、跨域)

目录 浏览器从输入url到渲染页面 过程⭐⭐⭐ Http和Https区别⭐⭐⭐ GET和POST发送请求⭐⭐⭐ 异同 http版本⭐⭐⭐ http状态码⭐⭐⭐ TCP⭐⭐⭐ 三次握手 四次挥手 流量控制&#xff08;滑动窗口机制&#xff09; 拥塞控制 keep-alive持久连接 TCP⭐⭐⭐ 三次握手…