当前位置: 首页 > news >正文

尚硅谷----智尚代驾项目----Day7(续)------预估乘客订单数据之Drools

Hello uu 们!感谢你们的收看,话不多说,今天开始我们的Drools之旅

Drools介绍


drools是一款由JBoss组织提供的基于Java语言开发的开源规则引擎,可以将复杂且多变的业务规则从硬编码中解放出来,以规则脚本的形式存放在文件或特定的存储介质中(例如存放在数据库中),使得业务规则的变更不需要修改项目代码、重启服务器就可以在线上环境立即生效。

drools官网地址:https://drools.org/

drools源码下载地址:https://github.com/kiegroup/drools

Drools入门案例
1.创建springboot项目

groupId:com.atguigu.drools
artifactId:drools_demo

2.引入依赖

    <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.0.5</version><relativePath/> <!-- lookup parent from repository --></parent><properties><java.version>17</java.version><drools.version>8.41.0.Final</drools.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.drools</groupId><artifactId>drools-core</artifactId><version>${drools.version}</version></dependency><dependency><groupId>org.drools</groupId><artifactId>drools-compiler</artifactId><version>${drools.version}</version></dependency><dependency><groupId>org.drools</groupId><artifactId>drools-decisiontables</artifactId><version>${drools.version}</version></dependency><dependency><groupId>org.drools</groupId><artifactId>drools-mvel</artifactId><version>${drools.version}</version></dependency></dependencies>
3.添加Drools配置类
package com.atguigu.drools.config;import org.kie.api.KieServices;
import org.kie.api.builder.*;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.internal.io.ResourceFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** 规则引擎配置类*/
@Configuration
public class DroolsConfig {private static final KieServices kieServices = KieServices.Factory.get();//制定规则文件的路径private static final String RULES_CUSTOMER_RULES_DRL = "rules/order.drl";@Beanpublic KieContainer kieContainer() {//获得Kie容器对象KieFileSystem kieFileSystem = kieServices.newKieFileSystem();kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_CUSTOMER_RULES_DRL));KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);kieBuilder.buildAll();KieModule kieModule = kieBuilder.getKieModule();KieContainer kieContainer = kieServices.newKieContainer(kieModule.getReleaseId());return kieContainer;}}

说明:

  • 定义了一个 KieContainer的Spring Bean ,KieContainer用于通过加载应用程序的/resources文件夹下的规则文件来构建规则引擎。
  • 创建KieFileSystem实例并配置规则引擎并从应用程序的资源目录加载规则的 DRL 文件。
  • 使用KieBuilder实例来构建 drools 模块。我们可以使用KieSerive单例实例来创建 KieBuilder 实例。
  • 最后,使用 KieService 创建一个 KieContainer 并将其配置为 spring bean


4.创建实体类Orde

package com.atguigu.drools.model;public class Order {private double amout;private double score;public double getAmout() {return amout;}public void setAmout(double amout) {this.amout = amout;}public double getScore() {return score;}public void setScore(double score) {this.score = score;}
}
5.order.drl

创建规则文件resources/rules/order.drl

//订单积分规则
package com.order
import com.atguigu.drools.model.Order//规则一:100元以下 不加分
rule "order_rule_1"when$order:Order(amout < 100)then$order.setScore(0);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//规则三:500元 - 1000元 加500分
rule "order_rule_3"when$order:Order(amout >= 500 && amout < 1000)then$order.setScore(500);System.out.println("成功匹配到规则三:500元 - 1000元 加500分");
end//规则四:1000元以上 加1000分
rule "order_rule_4"when$order:Order(amout >= 1000)then$order.setScore(1000);System.out.println("成功匹配到规则四:1000元以上 加1000分");
end

6.编写测试类

package com.atguigu.drools;import org.junit.jupiter.api.Test;
import com.atguigu.drools.model.Order;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class DroolsDemosApplicationTests {@Autowiredprivate KieContainer kieContainer;@Testpublic void test(){//从Kie容器对象中获取会话对象KieSession session = kieContainer.newKieSession();//Fact对象,事实对象Order order = new Order();order.setAmout(1300);//将Order对象插入到工作内存中session.insert(order);//激活规则,由Drools框架自动进行规则匹配,如果规则匹配成功,则执行当前规则session.fireAllRules();//关闭会话session.dispose();System.out.println("订单金额:" + order.getAmout() +",添加积分:" + order.getScore());}}
  • 通过上面的入门案例我们可以发现,使用drools规则引擎主要工作就是编写规则文件,在规则文件中定义跟业务相关的业务规则。规则定义好后就需要调用drools提供的API将数据提供给规则引擎进行规则模式匹配,规则引擎会执行匹配成功的规则并将计算的结果返回给我们。
  • 可能大家会有疑问,就是我们虽然没有在代码中编写规则的判断逻辑,但是我们还是在规则文件中编写了业务规则,这跟在代码中编写规则有什么本质的区别呢?
  • 我们前面其实已经提到,使用规则引擎时业务规则可以做到动态管理。业务人员可以像管理数据一样对业务规则进行管理,比如查询、添加、更新、统计、提交业务规则等。这样就可以做到在不重启服务的情况下调整业务规则。

Drools基础语法

  • 规则文件构成
  • 在使用Drools时非常重要的一个工作就是编写规则文件,通常规则文件的后缀为.drl。
  • drl是Drools Rule Language的缩写。在规则文件中编写具体的规则内容。

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

Drools支持的规则文件,除了drl形式,还有Excel文件类型的。

2.规则体语法结构

规则体是规则文件内容中的重要组成部分,是进行业务规则判断、处理业务结果的部分。
规则体语法结构如下:

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

3.注释
在drl形式的规则文件中使用注释和Java类中使用注释一致,分为单行注释和多行注释。
单行注释用"//“进行标记,多行注释以”/“开始,以”/"结束。如下示例:

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

4.Pattern模式匹配

  • 前面我们已经知道了Drools中的匹配器可以将Rule Base中的所有规则与Working Memory中的Fact对象进行模式匹配,那么我们就需要在规则体的LHS部分定义规则并进行模式匹配。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属性值必须小于500------属性约束
  • 以上条件必须同时满足当前规则才有可能被激活。

5.比较操作符

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

前6个比较操作符和Java中的完全相同。

6.Drools内置方法

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

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

参数:

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

规则:

//规则一:100元以下 不加分
rule "order_rule_1"when$order:Order(amout < 100)then$order.setAmout(150);update($order) //update方法用于更新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

在更新数据时需要注意防止发生死循环。

6.2.insert方法

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

//规则一:100元以下 不加分
rule "order_rule_1"when$order:Order(amout < 100)thenOrder 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
6.3.retract方法

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

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

前面我们已经知道了规则体的构成如下

rule "ruleName"attributeswhenLHSthenRHS
end

本章节就是针对规则体的attributes属性部分进行讲解。Drools中提供的属性如下表(部分属性):

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

可以通过创建规则文件salience.drl来测试salience属性,内容如下

package com.orderrule "rule_1"wheneval(true)thenSystem.out.println("规则rule_1触发");
endrule "rule_2"wheneval(true)thenSystem.out.println("规则rule_2触发");
endrule "rule_3"wheneval(true)thenSystem.out.println("规则rule_3触发");
end

通过控制台可以看到,由于以上三个规则没有设置salience属性,所以执行的顺序是按照规则文件中规则的顺序由上到下执行的。接下来我们修改一下文件内容:

package com.orderrule "rule_1"salience 9wheneval(true)thenSystem.out.println("规则rule_1触发");
endrule "rule_2"salience 10wheneval(true)thenSystem.out.println("规则rule_2触发");
endrule "rule_3"salience 8wheneval(true)thenSystem.out.println("规则rule_3触发");
end

通过控制台可以看到,规则文件执行的顺序是按照我们设置的salience值由大到小顺序执行的。
建议在编写规则时使用salience属性明确指定执行优先级。

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

编写规则文件/resources/rules/activationgroup.drl

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

通过控制台可以看到,由于我们没有设置no-loop属性的值,所以发生了死循环。接下来设置no-loop的值为true再次测试则不会发生死循环。

8.Drools高级语法

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

8.1.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.Orderglobal com.atguigu.drools.model.Integral integral;//规则一:100元以下 不加分
rule "order_rule_1"no-loop true         //防止陷入死循环when$order:Order(amout < 100)thenintegral.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());
}

上午先到这啦~~~下午continue!

相关文章:

  • 第五届计算机科学与管理科技国际学术会议(ICCSMT 2024)
  • ROS与无人驾驶学习笔记(一)——ROS基本操作
  • KRTS虚拟网络适配器和 Windows 连接
  • 相机、镜头参数详解以及相关计算公式
  • 2024 Python3.10 系统入门+进阶(十六):正则表达式
  • Eureka原理实践:构建高可用、可扩展的微服务架构
  • 《C++无锁编程:解锁高性能并发的新境界》
  • day01——登录功能
  • npm切换到淘宝镜像
  • Redis——缓存
  • 15年408-数据结构
  • Stable Diffusion绘画 | SDXL模型的优缺点及模型推荐
  • 【linux进程】进程状态僵尸进程孤儿进程
  • 遥感影像-语义分割数据集:山体滑坡数据集详细介绍及训练样本处理流程
  • 计算机毕业设计 基于Hadoop的智慧校园数据共享平台的设计与实现 Python 数据分析 可视化大屏 附源码 文档
  • ----------
  • [js高手之路]搞清楚面向对象,必须要理解对象在创建过程中的内存表示
  • 《用数据讲故事》作者Cole N. Knaflic:消除一切无效的图表
  • 【跃迁之路】【463天】刻意练习系列222(2018.05.14)
  • 30秒的PHP代码片段(1)数组 - Array
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • CentOS7 安装JDK
  • classpath对获取配置文件的影响
  • ECMAScript6(0):ES6简明参考手册
  • es6
  • exports和module.exports
  • express.js的介绍及使用
  • extract-text-webpack-plugin用法
  • JAVA 学习IO流
  • java小心机(3)| 浅析finalize()
  • Linux编程学习笔记 | Linux IO学习[1] - 文件IO
  • Netty+SpringBoot+FastDFS+Html5实现聊天App(六)
  • node入门
  • Vim 折腾记
  • 理解在java “”i=i++;”所发生的事情
  • 如何学习JavaEE,项目又该如何做?
  • 项目实战-Api的解决方案
  • 小程序 setData 学问多
  • 延迟脚本的方式
  • 移动互联网+智能运营体系搭建=你家有金矿啊!
  • 智能情侣枕Pillow Talk,倾听彼此的心跳
  • ​io --- 处理流的核心工具​
  • ‌‌雅诗兰黛、‌‌兰蔻等美妆大品牌的营销策略是什么?
  • #define用法
  • #免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • #我与虚拟机的故事#连载20:周志明虚拟机第 3 版:到底值不值得买?
  • (13)Hive调优——动态分区导致的小文件问题
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (3)(3.5) 遥测无线电区域条例
  • (AngularJS)Angular 控制器之间通信初探
  • (day18) leetcode 204.计数质数
  • (ISPRS,2021)具有遥感知识图谱的鲁棒深度对齐网络用于零样本和广义零样本遥感图像场景分类
  • (待修改)PyG安装步骤
  • (翻译)terry crowley: 写给程序员