Drools 规则引擎(包括动态加载数据库中规则引擎)

news2025/1/23 17:27:36

Drools 规则引擎


文章目录

  • Drools 规则引擎
  • 前言
  • 一、规则引擎是什么?
  • 二、Drools 简介
    • 1.引入规则引擎前后程序架构:
    • 2.Drools API 开发步骤:
    • 在这里插入图片描述
  • 三、Drools 快速入门
    • 1.使用项目文件作为规则引擎
    • 2.使用数据库存储规则引擎
  • 四、Drools 规则引擎构成及其核心类
  • 总结


前言

随着互联网的不断发展,有很多平台存在比较复杂的业务规则并且这些规则会随着需求频繁变换,这时候就需要找到一个可以将活动规则和代码解耦的技术,那就是规则引擎。


一、规则引擎是什么?

规则引擎:全称为业务规则管理系统,英文名为BRMS。规则引擎的主要思想是将应用程序中的业务决策部分分离出来,并使用预定义的语义模块编写业务决策(业务规则),由用户或 开发者在需要时进行配置、管理。需要注意的是规则引擎并不是一个具体的技术框架,而是指的一类系统,即业务规则管理系统。

java开源的规则引擎有:Drools、Easy Rules、Mandarax、IBM ILOG。使用最为广泛并且开源的是Drools。

主要应用场景:

  • 风控系统-------风险贷款、风险评估
  • 反欺诈项目-----银行贷款、征信验证
  • 决策平台-------财务计算
  • 电商平台------满减、打折、加价购

二、Drools 简介

Drools 是用 Java 语言编写的开放源码规则引擎,使用 Rete 算法对所编写的规则求值。Drools 允许使用声明方式表达业务逻辑。可以使用非 XML 的本地语言编写规则,将规则与业务代码解耦,规则以脚本的形式存储在一个文件中,使规则的变化不需要修改代码,重新启动机器即可在线上环境中生效。并且,还可以将 Java 代码直接嵌入到规则文件中,这令 Drools 的学习更加吸引人。

官网:http://www.drools.org/#
官方文档:http://www.drools.org/learn/documentation.html

1.引入规则引擎前后程序架构:

引入前:
在这里插入图片描述
引入后:
在这里插入图片描述

2.Drools API 开发步骤:

在这里插入图片描述


三、Drools 快速入门

1.使用项目文件作为规则引擎

此章节引用的华为云开发者联盟文章中的实例,原文链接如下。 第二章使用数据库作为规则引擎为原创

原文链接:https://huaweicloud.csdn.net/63356f78d3efff3090b56d8f.html

电商平台促销积分规则

100元以下, 不加分 
100-500元 加100500-1000元 加5001000元 以上 加1000

开发实现
第一步:创建Maven项目,添加Drools 规则引擎依赖。

 <!--添加规则引擎依赖-->
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-compiler</artifactId>
            <version>7.73.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-mvel</artifactId>
            <version>7.73.0.Final</version>
        </dependency>
        <!--添加单元测试工具类-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

第二步:根据drools要求创建resources/META-INF/kmodule.xml 配置文件

需要有一个配置文件告诉代码规则文件drl 在哪里,在drools中这个文件就是kmodule.xml。

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
    <!--
    name:指定kbase 名称,可以是任意但必须唯一
    packages:指定规则文件存放目录,依据实际情况进行填写
    default:指定当前的kbase 是否为默认
    -->
    <kbase name="rules" packages="rules" default="true">
        <!--
        name:指定ksession名称,可以是任意但必须唯一
        default:指定ksession 是否为默认
        -->
        <ksession name="ksession-rules" default="true"/>
    </kbase>
</kmodule>

第三步:创建业务实体对象

package com.zzg.model;

public class Order implements java.io.Serializable {

    private int amount; //订单金额

    private int score; //订单积分

    @Override
    public String toString() {
        return "Order{" +
                "amount=" + amount +
                ", score=" + score +
                '}';
    }

    public int getAmount() {
        return amount;
    }

    public void setAmount(int amount) {
        this.amount = amount;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }
}

第四步:创建规则文件,在resources/rules/score-rules.drl

package rules;

import com.zzg.model.Order;

// 100 元以下不加分
rule "score_1"
when
    $order:Order(amount<100);
then
    $order.setScore(0);
    System.out.println("触发100元以下,不加积分");
end
// 100-500 元, 加100积分
rule "score_2"
when
    $order:Order(amount>100 && amount <= 500);
then
    $order.setScore(100);
    System.out.println("触发100-500 元, 加100积分");
end
// 500-10000 元, 加500积分
rule "score_3"
when
    $order:Order(amount>500 && amount <= 1000);
then
    $order.setScore(500);
    System.out.println("触发500-1000 元, 加500积分");
end
// 大于1000 元, 加1000积分
rule "score_4"
when
    $order:Order(amount>1000);
then
    $order.setScore(1000);
    System.out.println("触发大于1000 元, 加1000积分");
end

第五步:单元测试

package com.zzg;

import com.zzg.model.Order;
import org.junit.Test;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

public class TestDrools {
    @Test
    public void test1() {
        // 第一步
        KieServices kieServices = KieServices.Factory.get();
        // 第二步
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        // 第三步
        KieSession kieSession = kieContainer.newKieSession();
        // 业务对象
        Order order = new Order();
        order.setAmount(100);
        // 第四步
        kieSession.insert(order);
        // 第五步:执行规则引擎
        kieSession.fireAllRules();
        // 第六步:关闭session
        kieSession.dispose();

        System.out.println("指定规则引擎后的结果:" + order.getScore());

    }
}

效果截图:

23:01:01.112 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: rules
23:01:01.144 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES
23:01:01.144 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING
23:01:01.144 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE
23:01:01.144 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED
指定规则引擎后的结果:0

2.使用数据库存储规则引擎

电商平台促销积分规则

100元以下, 不加分 
100-500元 加100500-1000元 加5001000元 以上 加1000

开发实现
第一步:创建Maven项目,添加Drools 规则引擎依赖。

 <!--添加规则引擎依赖-->
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-compiler</artifactId>
            <version>7.73.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-api</artifactId>
            <version>7.73.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-core</artifactId>
            <version>7.73.0.Final</version>
        </dependency>
        <!--添加单元测试工具类-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

第二步:根据drools要求创建resources/META-INF/kmodule.xml 配置文件 因在数据库读取规则,经测试发现不写kmodule.xml 配置文件 也可以

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
    <!--
    name:指定kbase 名称,可以是任意但必须唯一
    packages:指定规则文件存放目录,依据实际情况进行填写
    default:指定当前的kbase 是否为默认
    -->
    <kbase name="rules" packages="rules" default="true">
        <!--
        name:指定ksession名称,可以是任意但必须唯一
        default:指定ksession 是否为默认
        -->
        <ksession name="ksession-rules" default="true"/>
    </kbase>
</kmodule>

第三步:创建业务实体对象

package com.zzg.model;

public class Order implements java.io.Serializable {

    private int amount; //订单金额

    private int score; //订单积分

    @Override
    public String toString() {
        return "Order{" +
                "amount=" + amount +
                ", score=" + score +
                '}';
    }

    public int getAmount() {
        return amount;
    }

    public void setAmount(int amount) {
        this.amount = amount;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }
}

第四步:创建规则文件,使用insert into 语句插入数据库(oracle数据库

数据库字段为 serialNo(主键)、rule(规则内容) rule类型为CLOB
这里我使用了另一种写法,如果使用上边那种写法也可以,上边的写法还规范!!!

DECLARE
	V_LANG CLOB :=
	'package rules
	import com.zzg.model.Order;
	
	// 100 元以下不加分
	rule "score_1"
	when
		context:Order(amount<100)
	then
	    context.setScore(0);
	    System.out.println("触发100元以下,不加积分");
	end
	// 100-500 元, 加100积分
	rule "score_2"
	when
	    context:Order(amount>100 &&& amount <= 500);
	then
	    context.setScore(100);
	    System.out.println("触发100-500 元, 加100积分");
	end
	// 500-10000 元, 加500积分
	rule "score_3"
	when
	    context:Order(amount>500 &&& amount <= 1000);
	then
	    context.setScore(500);
	    System.out.println("触发500-1000 元, 加500积分");
	end
	// 大于1000 元, 加1000积分
	rule "score_4"
	when
	    context:Order(amount>1000);
	then
	    context.setScore(1000);
	    System.out.println("触发大于1000 元, 加1000积分");
	end';
BEGIN
	insert into	t_rule(serialNo, rule) values (1, V_LANG);
END;

这里我没测试,如果直接复制可能有错,上边的包引得可能有问题,因为代码不在本地电脑。抱歉。
第五步:单元测试

package com.zzg;

import com.zzg.model.Order;
import org.junit.Test;
import org.kie.io.ResourceType;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieSession;
import org.kie.internal.utils.KieHelper;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.sql.Clob;
import java.sql.SQLException;

public class TestDrools {
    @Test
    public void test1() {
        // 第一步 读取数据库中规则 这里大家按照自己项目持久层框架写就OK 
        // 实体类中 rule 的类型为 private Clob rule;
		RuleEntity ruleEntity = ruleDao.getRuleEntity();
		// 第二步 把clob类型转换为String类型
		String myRule = clobToString(ruleEntity.getRule());
		// 第三步 创建规则对象 将String转换成DRL规则
		KieHelper kieHelper = new KieHelper();
		kieHelper.addContent(myRule, ResourceType.DRL);
		// 第四步 会话对象,用于和规则引擎交互
		KieSession kieSession = kieHelper.build().newKieSession();
        // 业务对象
        Order order = new Order();
        order.setAmount(100);
        // 第四步
        kieSession.insert(order);
        // 第五步:执行规则引擎
        kieSession.fireAllRules();
        // 第六步:关闭session
        kieSession.dispose();

        System.out.println("指定规则引擎后的结果:" + order.getScore());

    }
	
	private String clobToString(Clob clob) throws Exception{
		String str = "";
		//得到流
		Reader rd = clob.getCharacterStream();
		BufferedReader br = new BufferedReader(rd );
		String s = br.readLine();
		StringBuilder sb= new StringBuilder();
        while(s != null) {
          sb.append(s);
          s = br.readLine();
        }
        str = sb.toString();
        return str;
	}
}

附加
这里写一下对此字段的增删改查语法
原文链接:https://huaweicloud.csdn.net/63355c9ad3efff3090b5418d.html?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Eactivity-3-120262609-blog-126691379.pc_relevant_recovery_v2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Eactivity-3-120262609-blog-126691379.pc_relevant_recovery_v2&utm_relevant_index=6

--使用PL/SQL语法,采取绑定变量的方式解决,而不是直接拼接SQL
DECLARE
    V_LANG CLOB := '待插入的海量字符串';
    V_UPDATE CLOB := '更新的海量字符串';
BEGIN
 INSERT INTO temp t VALUES ('Grand.Jon', 22, V_LANG);    --增加
 UPDATE temp t SET t.temp_clob = V_UPDATE WHERE rownum = 1; --修改
 SELECT t.NAME, dbms_lob.substr(t.temp_clob) FROM TEMP t;  --查询  将CLOB转成字符类型
 DELETE temp t WHERE rownum = 1;               --按列删除  
 COMMIT;
END;
/

效果截图:

23:01:01.112 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: rules
23:01:01.144 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES
23:01:01.144 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING
23:01:01.144 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE
23:01:01.144 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED
指定规则引擎后的结果:0

四、Drools 规则引擎构成及其核心类

Drools规则引擎构成
drools规则引擎由以下几部分构成:

  • Working Memory(工作内存)
  • Rules(规则库)
  • Inference Engine(推理引擎)
  • 其中Inference Engine(t推理引擎)又包含如下:

Pattern Match(匹配器)具体匹配那一个规则,由它来完成

  • Agenda(议程)
  • Execution Engine(执行引擎)
    在这里插入图片描述

Drools规则引擎概念
Working Memory: 工作内存,drools规则引擎会从Working Memory中获取数据并和规则文件中定义的规则进行模式匹配,所以我们开发的应用程序只需要将我们的数据插入到Working Memory中即可,例如本案例中我们调用kieSession.insert(order)就是将order对象插入到了工作内存中。

Fact: 事实,是指在drools 规则应用当中,将一个普通的JavaBean插入到Working Memory后的对象就是Fact对象,例如本案例中的Order对象就属于Fact对象。Fact对象是我们的应用和规则引擎进行数据交互的桥梁或通道。

Rules: 规则库,我们在规则文件中定义的规则都会被加载到规则库中。

Pattern Matcher: 匹配器,将Rule Base中的所有规则与Working Memory中的Fact对象进行模式匹配,匹配成功的规则将被激活并放入Agenda中。

Agenda: 议程,用于存放通过匹配器进行模式匹配后被激活的规则。


总结

以上就是今天要讲的内容,本文仅仅简单介绍了Drools 规则引擎,而Drools 提供了大量能使我们快速便捷地处理数据的函数和方法。大家可以看一下原文链接,里边讲解了一些关于Drools 基础语法等内容。

参考文章:
Drools 规则引擎一文读懂 : https://huaweicloud.csdn.net/63356f78d3efff3090b56d8f.html
【Drools】Drools使用入门(一)Drools上手教程(包括动态加载规则文件) : http://t.csdn.cn/jyfF0
ORACLE中CLOB介绍及使用:https://huaweicloud.csdn.net/63355c9ad3efff3090b5418d.html?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Eactivity-3-120262609-blog-126691379.pc_relevant_recovery_v2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Eactivity-3-120262609-blog-126691379.pc_relevant_recovery_v2&utm_relevant_index=6

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

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

相关文章

【shell脚本】条件语句

一、条件测试操作 1.1test命令与 [ ] 符号 测试表达试是否成立&#xff0c;若成立返回0&#xff0c;否则返回其它数值 1.1.1文件测试常用的测试操作符 符号作用-d测试是否为目录-e测试是否为目录或文件-f测试是否为文件-r测试当前用户是否有读取权限-w测试当前用户是否有写…

2023-4-27-深入理解C++指针类型间强制转换

&#x1f37f;*★,*:.☆(&#xffe3;▽&#xffe3;)/$:*.★* &#x1f37f; &#x1f4a5;&#x1f4a5;&#x1f4a5;欢迎来到&#x1f91e;汤姆&#x1f91e;的csdn博文&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f49f;&#x1f49f;喜欢的朋友可以关注一下&#xf…

【致敬未来的攻城狮计划】— 连续打卡第十四天:FSP固件库开发延时函数(时钟详解)

系列文章目录 1.连续打卡第一天&#xff1a;提前对CPK_RA2E1是瑞萨RA系列开发板的初体验&#xff0c;了解一下 2.开发环境的选择和调试&#xff08;从零开始&#xff0c;加油&#xff09; 3.欲速则不达&#xff0c;今天是对RA2E1 基础知识的补充学习。 4.e2 studio 使用教程 5.…

数据结构_线性表、顺序表、单链表

目录 1. 线性表的定义和基本操作 1.1 线性表的定义 1.2 线性表的特点 1.3 线性表的基本操作 2. 线性表的顺序表示 2.1 顺序表的定义 2.2 顺序表上基本操作的实现 2.2.1 插入操作 2.2.2 删除操作 2.2.3 按值查找 2.3 相关练习巩固 3. 线性表的链式表示 3.1 单链表的…

Zynq-7000、FMQL45T900的GPIO控制(五)---linux应用层配置GPIO输出控制

上文中详细阐述了对应原理图MIO/EMIO的编号&#xff0c;怎么计算获取linux下gpio的编号 本文涉及C代码上传&#xff0c;下载地址 Zynq-7000、FMQL45T900的GPIO控制c语言代码资源-CSDN文库 本文详细记录一下针对获取到gpio的编号&#xff0c;进行配置输出模式&#xff0c;并进…

RobotFramework——创建项目

创建项目 实际上在Robot Framework中创建测试项目和创建单元测试项目是一致的。 robotunittest(python)Test ProjectTest ProjectTest SuitTest SuitTest CaseTest Case 1、创建测试项目 选择菜单栏 file —> New Project Name输入"TestRobot01"&#xff1b;…

从奈奎斯特采样定理推导FMCW雷达系统性能参数

本文编辑&#xff1a;调皮哥的小助理 上文从FMCW毫米波雷达系统的性能参数理解4D成像毫米波雷达的设计思路&#xff0c;谈到关于设计4D毫米波成像雷达的思路&#xff0c;其实我还忽略了一点&#xff0c;在这里补充说明一下。 在文中谈到的最小化公式中&#xff0c;分母的有效带…

vscode - 配置Prettier插件和.editorconfig文件使用介绍

文章目录 1&#xff0c;介绍2&#xff0c;Prettier插件安装3&#xff0c;全局配置&#xff08;settings.json&#xff09;4&#xff0c;局部配置&#xff08;新建.prettierrc文件&#xff09;5&#xff0c;Prettier格式化优先级&#xff08;重要&#xff09;6&#xff0c;使用p…

【教程分享】一键部署MySQL,轻松搞定Docker安装和配置!

1 下载 MySQL 我们就可以到 docker hub 来看&#xff1a; 点击后的页面&#xff1a; 直接执行docker pull mysql&#xff0c;会下载最新版本的 MySQL。 点击 tags&#xff0c;找到并下载经典的 MySQL5.7&#xff1a; [rootservice-monitoring ~]# docker pull mysql:5.7.42-o…

Speech and Language Processing-之N-gram语言模型

正如一句老话所说&#xff0c;预测是困难的&#xff0c;尤其是预测未来。但是&#xff0c;如何预测一些看起来容易得多的事情&#xff0c;比如某人接下来要说的几句话后面可能跟着哪个单词。 希望你们大多数人都能总结出一个很可能的词是in&#xff0c;或者可能是over&#x…

【hello Linux】进程间通信——命名管道

目录 1. 命令行的命名管道 2. 命名管道 1. 命名管道的创建 2. 命名管道的使用 Linux&#x1f337; 在上篇中我们说到&#xff0c;可以使用匿名管道完成父子进程间的通信&#xff0c;它是让子进程继承父进程&#xff0c;从而达到让两个进程看到同一份资源&#xff1b; 如果我们…

急急急!Kafka Topic 资源权限紧张怎么办?

我们都知道 Kafka 的 topic 资源比较“贵”&#xff0c;所以一般会给项目 topic 权限限制&#xff0c;按需申请。Milvus 会在建新表时自动申请 kafka topic 资源&#xff0c;这时候自动申请不到怎么办&#xff1f;手动配置 topic 要符合什么规范才能被 Milvus 使用&#xff1f;…

Vue 3 第十六章:组件五(内置组件-teleport)

文章目录 1. Teleport组件的基本用法2. Teleport组件的高级用法2.1. 禁用 Teleport2.2. 多个Teleport组件共享目标元素 1. Teleport组件的基本用法 <teleport>组件用于将组件的内容插入到指定的DOM元素中&#xff0c;而不是插入到组件自身的位置。例如&#xff0c;当我们…

improperIntegral反常积分

(https://img-blog.csdnimg.cn/e5973004aba8484a82839773ff58a390.png)

【刷题记录】leetcode215 数组中的第K个最大元素

题目链接&#xff1a;215. 数组中的第K个最大元素 - 力扣&#xff08;LeetCode&#xff09; 题干&#xff1a; 给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。 请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 k …

cleanmymac到底好不好用?有必要买吗

CleanMyMac是一款Mac电脑清理和保护工具,其最新版本为CleanMyMac X4.13。本版本在性能和功能上有较大提高,在如今的电脑使用过程中&#xff0c;保持电脑干净整洁是一项重要的任务。而随着Mac电脑越来越受欢迎&#xff0c;Mac电脑清理软件也愈发流行。在众多的Mac电脑清理软件中…

2023年PMP证书的含金量有多高?对于企业来说有多大的价值?

这里我就说一下关于PMP证书的含金量问题 1、方便就业 众所周知年这几年就业形势严峻。但是在这种大环境下&#xff0c;PMP证书持有者就业形势依然乐观。在求职市场&#xff0c;职位需求量大且薪资可观。 这种局面的形成主要是因为企项目管理规模化发展是一种发展趋势。随着公…

【error】linux运行java的jar包报错,java.lang.UnsatisfiedLinkError

目录 linux运行串口相关的java.jar报错如下&#xff1a; java.lang.UnsatisfiedLinkError是Java中的一个错误类型&#xff0c;通常发生在调用本地&#xff08;native&#xff09;方法或使用JNI&#xff08;Java Native Interface&#xff09;时。 在Java中&#xff0c;本地…

Vue(内置指令、自定义指令)

一、内置指令 1. v-text 和插值语法的效果类似 <h2>{{name}}</h2><h2 v-text"name">此处v-text绑定的数据替换所有标签内内容</h2> //vuedata: {name: "xlf",}, 注意&#xff1a;不能识别标签数据 <h2 v-text"name2"…

立体堆叠柱图的实现

立体堆叠柱图实现的实现 实现效果示例&#xff1a; 1、技术原理 1.1、技术分析 平面上的立体柱图可以看作是由4个平行四边形拼接而成的图形&#xff0c;分别是&#xff1a; 1、顶部菱形2和3、左右矩形&#xff0c;他们两个色值相同但亮度不同&#xff0c;从而产生立体阴影…