drools 介绍

article/2025/10/1 10:06:41

1 .场景

1.1需求

商城系统消费赠送积分

100元以下, 不加分

100元-500元 加100分

500元-1000元 加500分

1000元 以上 加1000分

......

1.2传统做法

1.2.1 if...else

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);

}

1.2.2 策略

interface Strategy {

   addScore(int num1,int num2);

}

class Strategy1 {

addScore(int num1);

}

......................

interface StrategyN {

    addScore(int num1);

}

class Environment {

    private Strategy strategy;

    public Environment(Strategy strategy) {

        this.strategy = strategy;

}

public int addScore(int num1) {

        return strategy.addScore(num1);

}

}

1.2.3 问题?

以上解决方法问题思考:
如果需求变更,积分层次结构增加,积分比例调整?
数据库?

遇到的问题瓶颈:
第一,我们要简化if else结构,让业务逻辑数据分离
第二,分离出的业务逻辑必须要易于编写,至少单独编写这些业务逻辑,要比写代码快!
第三,分离出的业务逻辑必须要比原来的代码更容易读懂!
第四,分离出的业务逻辑必须比原来的易于维护,至少改动这些逻辑,应用程序不用重启!

2.是什么

2.1概念

规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据业务规则做出业务决策

需要注意的是规则引擎并不是一个具体的技术框架,而是指的一类系统,即业务规则管理系统。目前市面上具体的规则引擎产品有:drools、VisualRules、iLog等

在很多企业的 IT 业务系统中,经常会有大量的业务规则配置,而且随着企业管理者的决策变化,这些业务规则也会随之发生更改。为了适应这样的需求,我们的 IT 业务系统应该能快速且低成本的更新。适应这样的需求,一般的作法是将业务规则的配置单独拿出来,使之与业务系统保持低耦合。目前,实现这样的功能的程序,已经被开发成为规则引擎。

2.2 起源

 

2.3 原理--基于 rete 算法的规则引擎

2.3.1 原理

在 AI 领域,产生式系统是一个很重要的理论,产生式推理分为正向推理和逆向推理产生式,其规则的一般形式是:IF 条件 THEN 操作。rete 算法是实现产生式系统中正向推理的高效模式匹配算法,通过形成一个 rete 网络进行模式匹配,利用基于规则的系统的时间冗余性和结构相似性特征 ,提高系统模式匹配效率

正向推理(Forward-Chaining)和反向推理(Backward-Chaining)

(1)正向推理也叫演绎法,由事实驱动,从一个初始的事实出发,不断地从应用规则得出结论。首先在候选队列中选择一条规则作为启用规则进行推理,记录其结论作为下一步推理的证据。如此重复这个过程,直到再无可用规则可被选用或者求得了所要求的解为止。

(2)反向推理也叫归纳法,由目标驱动,首先提出某个假设,然后寻找支持该假设的证据,若所需的证据都能找到,说明原假设是正确的,若无论如何都找不到所需要的证据,则说明原假设不成立,此时需要另作新的假设。

2.3.2 rete算法

Rete 算法最初是由卡内基梅隆大学的 Charles L.Forgy 博士在 1974 年发表的论文中所阐述的算法 , 该算法提供了专家系统的一个高效实现。自 Rete 算法提出以后 , 它就被用到一些大型的规则系统中 , 像 ILog、Jess、JBoss Rules 等都是基于 RETE 算法的规则引擎 。

Rete 在拉丁语中译为”net”,即网络。Rete 匹配算法是一种进行大量模式集合和大量对象集合间比较的高效方法,通过网络筛选的方法找出所有匹配各个模式的对象和规则。

其核心思想是将分离的匹配项根据内容动态构造匹配树,以达到显著降低计算量的效果。Rete 算法可以被分为两个部分:规则编译和规则执行 。当 Rete 算法进行事实的断言时,包含三个阶段:匹配、选择和执行,称做 match-select-act cycle。

 

2.5 Drools 介绍

Drools 具有一个易于访问企业策略、易于调整以及易于管理的开源业务 规则引擎,符合业内标准,速度快、效率高。业务分析师或审核人员可以利用它轻松查看业务规则,从而检验已编码的规则是否执行了所需的业务规则。其前身是 Codehaus 的一个开源项目叫 Drools,后被纳入 JBoss 门下,更名为 JBoss Rules,成为了 JBoss 应用服务器的规则引擎。

Drools 被分为两个主要的部分:编译和运行时。编译是将规则描述文件按 ANTLR 3 语法进行解析,对语法进行正确性的检查,然后产生一种中间结构“descr”,descr 用 AST 来描述规则。目前,Drools 支持四种规则描述文件,分别是:drl 文件、 xls 文件、brl 文件和 dsl 文件,其中,常用的描述文件是 drl 文件和 xls 文件,而 xls 文件更易于维护,更直观,更为被业务人员所理解。运行时是将 AST传到 PackageBuilder,由 PackagBuilder来产生 RuleBase,它包含了一个或多个 Package 对象。

3 .消费赠送积分案例

 

 

上图为实际用法:

3.1 第一步: 创建工程,引入jar

由于当前java开发,普通使用springboot ,本课程以springboot为基本框架演示

jar 依赖,注意,排除spring相关依赖

<!-- 规则引擎 -->

        <dependency>

            <groupId>org.kie</groupId>

            <artifactId>kie-spring</artifactId>

            <version>${drools.version}</version>

            <exclusions>

                <exclusion>

                    <groupId>org.springframework</groupId>

                    <artifactId>spring-tx</artifactId>

                </exclusion>

                <exclusion>

                    <groupId>org.springframework</groupId>

                    <artifactId>spring-beans</artifactId>

                </exclusion>

                <exclusion>

                    <groupId>org.springframework</groupId>

                    <artifactId>spring-core</artifactId>

                </exclusion>

                <exclusion>

                    <groupId>org.springframework</groupId>

                    <artifactId>spring-context</artifactId>

                </exclusion>

            </exclusions>

        </dependency>

3.2 创建 drools 自动配置类

drools 在spring 或者springboot中用法一样,其实就是创建好一些bean

package com.ityml.drools.config;

 

import org.kie.api.KieBase;

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.kie.spring.KModuleBeanFactoryPostProcessor;

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.core.io.Resource;

import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import org.springframework.core.io.support.ResourcePatternResolver;

 

import java.io.IOException;

 

 

/**

 * <p> 规则引擎自动配置类 </p>

 * @author ityml

 * @date 2019/9/10 11:20

 */

@Configuration

public class DroolsAutoConfiguration {

 

    private static final String RULES_PATH = "rules/";

 

    private KieServices getKieServices() {

        return KieServices.Factory.get();

    }

 

    @Bean

    @ConditionalOnMissingBean(KieFileSystem.class)

    public KieFileSystem kieFileSystem() throws IOException {

        KieFileSystem kieFileSystem = getKieServices().newKieFileSystem();

        for (Resource file : getRuleFiles()) {

            kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_PATH + file.getFilename(), "UTF-8"));

        }

        return kieFileSystem;

    }

 

    private Resource[] getRuleFiles() throws IOException {

        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

        return resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "**/*.*");

    }

 

    @Bean

    @ConditionalOnMissingBean(KieContainer.class)

    public KieContainer kieContainer() throws IOException {

        final KieRepository kieRepository = getKieServices().getRepository();

 

        kieRepository.addKieModule(() -> kieRepository.getDefaultReleaseId());

 

        KieBuilder kieBuilder = getKieServices().newKieBuilder(kieFileSystem());

        kieBuilder.buildAll();

 

        KieContainer kieContainer = getKieServices().newKieContainer(kieRepository.getDefaultReleaseId());

 

        return kieContainer;

    }

 

    @Bean

    @ConditionalOnMissingBean(KieBase.class)

    public KieBase kieBase() throws IOException {

        return kieContainer().getKieBase();

    }

 

}

3.2订单实体类

@Data

@Accessors(chain = true)

public class Order {

 

    /**

     * 订单原价金额

     */

    private int price;

 

    /**

     *下单人

     */

    private User user;

 

    /**

     *积分

     */

    private int score;

 

    /**

     * 下单日期

     */

    private Date bookingDate;

}

3.3规则引擎文件

package rules

 

import com.ityml.drools.entity.Order

 

rule "zero"

    no-loop true

    lock-on-active true

    salience 1

    when

        $s : Order(amout <= 100)

    then

        $s.setScore(0);

        update($s);

end

 

rule "add100"

    no-loop true

    lock-on-active true

    salience 1

    when

        $s : Order(amout > 100 && amout <= 500)

    then

        $s.setScore(100);

        update($s);

end

 

rule "add500"

    no-loop true

    lock-on-active true

    salience 1

    when

        $s : Order(amout > 500 && amout <= 1000)

    then

        $s.setScore(500);

        update($s);

end

 

rule "add1000"

    no-loop true

    lock-on-active true

    salience 1

    when

        $s : Order(amout > 1000)

    then

        $s.setScore(1000);

        update($s);

end

3.4客户端

/**

 * 需求

 * 计算额外积分金额 规则如下: 订单原价金额

 * 100以下, 不加分

 * 100-500 加100分

 * 500-1000 加500分

 * 1000 以上 加1000分

 */

public class DroolsOrderTests extends DroolsApplicationTests {

    @Resource

    private KieContainer kieContainer;

 

    @Test

    public void Test() throws Exception {

        List<Order> orderList = getInitData();

        for (Order order : orderList) {

            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);

            }

        }

    }

 

    @Test

    public void droolsOrderTest() throws Exception {

        KieSession kieSession = kieContainer.newKieSession();

        List<Order> orderList = getInitData();

        for (Order order: orderList) {

            // 1-规则引擎处理逻辑

            kieSession.insert(order);

            kieSession.fireAllRules();

            // 2-执行完规则后, 执行相关的逻辑

            addScore(order);

        }

        kieSession.dispose();

    }

 

 

 

    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<>();

        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");

        {

            Order order = new Order();

            order.setAmout(80);

            order.setBookingDate(df.parse("2015-07-01"));

            User user = new User();

            user.setLevel(1);

            user.setName("Name1");

            order.setUser(user);

            order.setScore(111);

            orderList.add(order);

        }

        {

            Order order = new Order();

            order.setAmout(200);

            order.setBookingDate(df.parse("2015-07-02"));

            User user = new User();

            user.setLevel(2);

            user.setName("Name2");

            order.setUser(user);

            orderList.add(order);

        }

        {

            Order order = new Order();

            order.setAmout(800);

            order.setBookingDate(df.parse("2015-07-03"));

            User user = new User();

            user.setLevel(3);

            user.setName("Name3");

            order.setUser(user);

            orderList.add(order);

        }

        {

            Order order = new Order();

            order.setAmout(1500);

            order.setBookingDate(df.parse("2015-07-04"));

            User user = new User();

            user.setLevel(4);

            user.setName("Name4");

            order.setUser(user);

            orderList.add(order);

        }

        return orderList;

    }

}


http://chatgpt.dhexx.cn/article/LOmX1THY.shtml

相关文章

计组——定点数原码反码补码移码以及它们之间的转换

原码 用尾数表示真值的绝对值&#xff0c;符号位“0/1”对应“正/负” 若机器字长n1位&#xff0c;原码整数的表示范围&#xff1a; − ( 2 n − 1 ) ≤ x ≤ 2 n − 1 {\color{Red} -(2^{n}-1)\leq x\leq 2^{n}-1} −(2n−1)≤x≤2n−1&#xff08;关于原点对称&#xff09;…

数据的表示:原码、反码、补码、移码以及浮点数的运算

前言 复习到数据表示方面相关的知识&#xff0c;所以在这里做一下记录&#xff0c;也方便大家参考。 什么是 R 进制 对于 R 机制&#xff0c;如果要实现与十进制的转换&#xff0c;则使用 按权展开法&#xff0c;其具体操作为&#xff1a; 将 R 进制数的每一位数值用 R k R…

五分钟理解原码补码反码和移码

这是计算机的基本知识了&#xff0c;一定要好好学。哈哈废话不多说&#xff0c;直接进入正题吧。计算机中有无符号数和有符号数两大类。 有符号数就是正负数&#xff0c;在计算机中正好用0和1分别去代表正和负。(ps:好多人不理解机器数和真值&#xff0c;机器数就是把符号数字…

原码、反码、补码、移码的表示

若字长n为8时&#xff0c;那么45的二进制表示0 0101101 &#xff0c;若数值X 1.原码 [X]原&#xff0c;在二进制数值中&#xff0c;正数保持不变&#xff0c;负数符号位置1. 2.反码 [X]反&#xff0c;的正数保持不变 &#xff0c; 负数对数值的绝对值每一位按位求反 3.补码…

关于补码移码各自和原码的联系、来历、功能及I EEE754标准中移码范围问题

最近在学习计算机组成原理时,遇到一些问题,记录在此。 如果你对下面这段话有疑惑或者兴趣&#xff0c;我或许能说点什么你感兴趣的。 真值-128的补码&#xff1a;1000 0000&#xff0c;这个补码本身表示的二进制数&#xff08;无符号&#xff09;是128&#xff0c;其对应着真…

移码的计算方式

规则&#xff1a;对应真值的补码的符号位取反&#xff1b; 计算公式&#xff1a; 式中&#xff1a;x为真值&#xff0c;n为整数的位数&#xff1b; 形式上补码是先减后增的&#xff0c;移码是递增的&#xff1b;根据人类的习惯&#xff0c;移码可以清楚的反映对应真值的大小…

计算机组成原理学习笔记:定点数、浮点数、原码、反码、补码、移码

定点数与浮点数 所谓定点数就是指小数点的位置固定不变而浮点数是小数点的位置是不固定的&#xff0c;会浮动 1 ) 定点数 用熟悉的十进制数来类比&#xff0c;定点数就是我们平时更习惯使用的常规的计数方式&#xff0c;我们会显式的标明小数点的位置Eg: 110.12 2 &#xf…

原码,补码,移码

一、原码 ①最高位为符号位&#xff0c;0表示正数&#xff0c;1表示负数&#xff1b; ②除符号位其它数值部分&#xff0c;就是数值本身绝对值的二进制数&#xff1b; ③负数的原码是在其绝对值得的基础上&#xff0c;符号位变为1&#xff1b; 但是&#xff1a; 0的表示不唯一&…

移码补码原理

计算机中的“数”&#xff0c;花样很多&#xff0c;又是ASCII码、又是BCD码等等&#xff0c;下面&#xff0c;做而论道写了一些关于移码、补码的一些看法&#xff0c;欢迎拍砖。 机器数 计算机中的“数”&#xff0c;其实都不是数字&#xff0c;它们都是一些高、低电平。其中&a…

浮点数与移码

浮点数的组成和计数原理 浮点数是什么浮点数的表示与规定浮点数的规定&#xff08;IEEE754 标准&#xff09;浮点数的表示范围&#xff08;IEE7标准瞎&#xff09;阶码用移码表示 浮点数是什么 浮点数就是小数点可以任意浮动的数字。   因为在计算机的机器语言中&#xff0c;…

图神经网络时代的深度聚类

©PaperWeekly 原创 作者&#xff5c;纪厚业 学校&#xff5c;北京邮电大学博士生 研究方向&#xff5c;图神经网络和推荐系统 聚类作为经典的无监督学习算法在数据挖掘/机器学习的发展历史中留下了不可磨灭的印记。其中&#xff0c;经典的聚类算法 K-Means 也被选为数据挖…

聊聊测试工程师的核心能力模型

这是鼎叔的第二篇原创文章。 行业大牛和刚毕业的小白&#xff0c;都可以进来聊聊。 多年大厂技术总监和质量通道委员经验&#xff0c;横跨多个不同领域&#xff0c;微信公众号“敏捷测试转型”&#xff0c;欢迎多多交流。 鼎叔过往接触过各个团队的测试&#xff08;测试开发&…

对比学习有多火?文本聚类都被刷爆了…

文 | 花小花Posy 大家好&#xff0c;我是小花。 对比学习的大火???? 越来越旺了&#xff0c;已然从CV蔓延到NLP了。今天给大家介绍的正是一篇将对比学习应用到文本聚类上的工作&#xff0c;NAACL21新鲜出炉的paper——《Supporting Clustering with Contrastive Learning》…

(附源码)小程序 记账微信小程序 毕业设计 180815

记账微信小程序 摘 要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;记账微信小程序被用户普遍使用&#xff0…

使用Python+OpenCV+Tensorflow实现图像聚类

介绍 大家好&#xff0c;最近在参加深度学习竞赛时&#xff0c;遇到了一个有趣的问题&#xff0c;即如何将给定的图像集进行聚类&#xff0c;你可能会说&#xff0c;这不是一个简单的分类问题吗&#xff1f;使用卷积神经网络&#xff0c; 就实现&#xff0c;但关键在于没有合适…

论文阅读笔记(15):Deep Subspace Clustering with Data Augmentation,深度子空间聚类+数据增强

论文阅读笔记&#xff08;15&#xff09;&#xff1a;Deep Subspace Clustering with Data Augmentation&#xff0c;深度子空间聚类数据增强 摘要1 介绍2 相关工作带增强的聚类方法具有一致性损失的自监督子空间聚类中的自表达模型 3 深度子空间聚类数据增强总结 4 寻找有效增…

【SaaS金羊毛】微信小程序We分析

微信前几天发布了通告https://mp.weixin.qq.com/cgi-bin/announce?actiongetannouncement&announce_id11652079103ziYFG&version&langzh_CN&token&#xff0c;小程序统计模块会升级为”We分析“这样一款独立的产品。实际上这也符合很多B端产品的趋势&#xff…

Python 如何确定K-Means聚类的簇数

背景 “人以类聚&#xff0c;物以群分”&#xff0c;在大千世界中总有那么一些人&#xff0c;性格爱好、行为习惯比较相近&#xff0c;我们就会把他们归为一类人&#xff0c;这就是我们人脑自动进行的一个聚类(归类)。 在数据分析中&#xff0c;我们也经常拿数据来进行K-Means聚…

【机器学习】聚类代码练习

本课程是中国大学慕课《机器学习》的“聚类”章节的课后代码。 课程地址&#xff1a; https://www.icourse163.org/course/WZU-1464096179 课程完整代码&#xff1a; https://github.com/fengdu78/WZU-machine-learning-course 代码修改并注释&#xff1a;黄海广&#xff0c;ha…

【聚类算法】10种Python聚类算法完整操作示例(建议收藏

点击上方&#xff0c;选择星标&#xff0c;每天给你送干货&#xff01; 来源&#xff1a;海豚数据科学实验室 著作权归作者所有&#xff0c;本文仅作学术分享&#xff0c;若侵权&#xff0c;请联系后台删文处理 聚类或聚类分析是无监督学习问题。它通常被用作数据分析技术&…