• Drools:概述和入门案例


    问题引出

    现有一个在线申请信用卡的业务场景,用户需要录入个人信息,如下图所示:

    image-20210915151009889

    通过上图可以看到,用户录入的个人信息包括姓名、性别、年龄、学历、电话、所在公司、职位、月收入、是否有房、是否有车、是否有信用卡等。录入完成后点击申请按钮提交即可。

    用户提交申请后,需要在系统的服务端进行用户信息合法性检查(是否有资格申请信用卡),只有通过合法性检查的用户才可以成功申请到信用卡(注意:不同用户有可能申请到的信用卡额度不同)。

    检查用户信息合法性的规则如下:

    规则编号 名称 描述
    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

    使用java代码实现如下:

    //此处为伪代码
    
    //检查用户信息合法性,返回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() == false){
            return false;
        }
        //如果申请人现有的信用卡数量大于10,那么不通过
        else if(user.getCreditCardCount() > 10){
            return false;
        }
        return true;
    }
    

    如果用户信息合法性检查通过后,还需要通过如下代码确定用户所办信用卡的额度:

    //此处为伪代码
    
    //根据用户输入信息确定信用卡额度
    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;
        }
    }
    

    通过上面的伪代码我们可以看到,我们的业务规则是通过Java代码的方式实现的。这种实现方式存在如下问题:

    1、硬编码实现业务规则难以维护

    2、硬编码实现业务规则难以应对变化

    3、业务规则发生变化需要修改代码,重启服务后才能生效

    那么面对上面的业务场景,还有什么好的实现方式吗?

    答案是规则引擎

    什么是规则引擎

    规则引擎,全称为业务规则管理系统,英文名为BRMS(即Business Rule Management System)。规则引擎的主要思想是将应用程序中的业务决策部分分离出来,并使用预定义的语义模块编写业务决策(业务规则),由用户或开发者在需要时进行配置、管理。

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

    规则引擎实现了将业务决策从应用程序代码中分离出来,接收数据输入,解释业务规则,并根据业务规则做出业务决策。规则引擎其实就是一个输入输出平台。

    上面的申请信用卡业务场景使用规则引擎后效果如下:

    image-20210915151355710

    系统中引入规则引擎后,业务规则不再以程序代码的形式驻留在系统中,取而代之的是处理规则的规则引擎,业务规则存储在规则库中,完全独立于程序。业务人员可以像管理数据一样对业务规则进行管理,比如查询、添加、更新、统计、提交业务规则等。业务规则被加载到规则引擎中供应用系统调用。

    使用规则引擎的优势

    使用规则引擎的优势如下:

    1、业务规则与系统代码分离,实现业务规则的集中管理

    2、在不重启服务的情况下可随时对业务规则进行扩展和维护

    3、可以动态修改业务规则,从而快速响应需求变更

    4、规则引擎是相对独立的,只关心业务规则,使得业务分析人员也可以参与编辑、维护系统的业务规则

    5、减少了硬编码业务规则的成本和风险

    6、使用规则引擎提供的规则编辑工具,使复杂的业务规则实现变得的简单

    规则引擎应用场景

    对于一些存在比较复杂的业务规则并且业务规则会频繁变动的系统比较适合使用规则引擎,如下:

    1、风险控制系统----风险贷款、风险评估

    2、反欺诈项目----银行贷款、征信验证

    3、决策平台系统----财务计算

    4、促销平台系统----满减、打折、加价购

    Drools介绍

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

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

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

    在项目中使用drools时,即可以单独使用也可以整合spring使用。如果单独使用只需要导入如下maven坐标即可:

    <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-compiler</artifactId>
        <version>7.6.0.Final</version>
    </dependency>
    

    drools API开发步骤如下:

    image-20210915152410731

    Drools入门案例

    业务场景说明

    业务场景:消费者在图书商城购买图书,下单后需要在支付页面显示订单优惠后的价格。具体优惠规则如下:

    规则编号 规则名称 描述
    1 规则一 所购图书总价在100元以下的没有优惠
    2 规则二 所购图书总价在100到200元的优惠20元
    3 规则三 所购图书总价在200到300元的优惠50元
    4 规则四 所购图书总价在300元以上的优惠100元

    现在需要根据上面的规则计算优惠后的价格。

    开发实现

    第一步:创建maven工程drools_quickstart并导入drools相关maven坐标

        <dependencies>
            <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>
        </dependencies>
    

    第二步:根据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

    /**
     * 订单
     */
    public class Order {
        private Double originalPrice;//订单原始价格,即优惠前价格
        private Double realPrice;//订单真实价格,即优惠后价格
        public String toString() {
            return "Order{" +
                    "originalPrice=" + originalPrice +
                    ", realPrice=" + realPrice +
                    '}';
        }
        public Double getOriginalPrice() {
            return originalPrice;
        }
        public void setOriginalPrice(Double originalPrice) {
            this.originalPrice = originalPrice;
        }
        public Double getRealPrice() {
            return realPrice;
        }
        public void setRealPrice(Double realPrice) {
            this.realPrice = realPrice;
        }
    }
    

    第四步:创建规则文件resources/rules/bookDiscount.drl

    //图书优惠规则
    package book.discount
    import com.wj.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();
            //获取kie容器对象
            KieContainer kieContainer = kieServices.newKieClasspathContainer();
            //从kie容器对象中获取session对象
            KieSession kieSession = kieContainer.newKieSession();
    
            //Fact对象
            Order order = new Order();
            order.setOriginalPrice(240d);
            //插入Fact对象
            kieSession.insert(order);
    
            //激活规则,由Drools框架自动进行规则匹配,匹配成功,则执行当前规则
            kieSession.fireAllRules();
    
            //关闭会话
            kieSession.dispose();
    
            System.out.println(order.getRealPrice());
        }
    

    运行结果:

    image-20210915154759125

    规则引擎构成

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

    • Working Memory(工作内存)
    • Rule Base(规则库)
    • Inference Engine(推理引擎)

    其中Inference Engine(推理引擎)又包括:

    • Pattern Matcher(匹配器)
    • Agenda(议程)
    • Execution Engine(执行引擎)

    image-20210915155846392

    相关概念说明

    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中被激活的规则。

    规则引擎执行过程

    image-20210915160221273

    KIE介绍

    我们在操作Drools时经常使用的API以及它们之间的关系如下图:

    image-20210915160601582

    通过上面的核心API可以发现,大部分类名都是以Kie开头。Kie全称为Knowledge Is Everything,即"知识就是一切"的缩写,是Jboss一系列项目的总称。如下图所示,Kie的主要模块有OptaPlanner、Drools、UberFire、jBPM

    image-20210915160624030

    通过上图可以看到,Drools是整个KIE项目中的一个组件,Drools中还包括一个Drools-WB的模块,它是一个可视化的规则编辑器。

  • 相关阅读:
    解决Ubuntu Kylin 1610安装ANSYS17.2的NVIDIA显卡驱动问题
    ubuntu安装ANSYS17.2全过程
    Ubuntu1604下安装Liggghts及CFDEM Coupling
    【Pyrosim案例】02:简单燃烧
    【Pyrosim案例】01:空气流动
    【FLUENT案例】06:与EDEM耦合计算
    【FLUENT案例】05:DDPM模型
    【FLUENT案例】04:利用DDPM+DEM模拟鼓泡流化床
    DataTables学习:从最基本的入门静态页面,使用ajax调用Json本地数据源实现前端开发深入学习,根据后台数据接口替换掉本地的json本地数据,以及报错的处理地方,8个例子(显示行附加信息,回调使用api,动态显示和隐藏列...),详细教程
    Python的下载和安装
  • 原文地址:https://www.cnblogs.com/wwjj4811/p/15272639.html
Copyright © 2020-2023  润新知