21

Drools 规则引擎在销售绩效核算中应用实战

 4 years ago
source link: https://mp.weixin.qq.com/s/UEBQ1j80eKkxHA8W-dPMaQ
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

总篇77篇 2020年 第1篇

一、背景 

公司销售绩效核算管理前期,绩效数据主要通过不同业务系统,经历人工数据采集、人工核算、薪酬核算、线下确认等多个环节。为了更贴合业务应用,对此进行了具体分析,针对现有模式中存在沟通效率低、缺乏安全监管、核算精准度低、审批流程不完整、运营成本高等问题。随着公司业务的快速发展,解决销售人员,线上自动高效的全生命周期管理,成为了当下重点任务。

因此,为适应之家发展,快速支持业务更规范、高效的开展, 规划建立一套“标准”、“安全”、“便捷”的规则引擎管理体系,致力于为业务提供统一规则管控中心,聚合用户规则诉求,简化各业务规则频繁变更的痛点,实现基础信息自动化管理、业务制度变更快速响应的建设目标,提高绩效数据安全性、准确性及合规性,降低维护成本。

二、规则引擎使用

2.1 什么是规则引擎  

规则引擎是由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策 从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据业务规则做出业务决策。大多数规则引擎都支持规则的次序和规则冲突检验,支持简单脚本语言的规则实现,支 持通用开发语言的嵌入开发。目前业内有多个规则引擎可供使用,其中包括商业和开放源码选择。开源的代表是 Drools,商业的代表是 Visual Rules,I Log。

2.2 为什么要使用规则引擎  

使用规则引擎前现状:

1、从10万条合同数据中清洗出符合规则的数据,传统开发都是把业务规则逻辑写在JAVA或者SQL代码中,导致业务逻辑和代码无法分离、维护业务规则成本较高。

2、新增或修改一个规则条件都需要修改代码、无法单独在线调试业务规则、确认分支环境、最后发布上线,开发维护高效率低。

3、业务规则管理无修改版本记录、升级如有问题线上环境无法快速回滚至低版本等风险。 

使用规则引擎带来的好处:

1、实现了从应用逻辑和数据中将业务逻辑分离,在线规则调试可见即可得、热更新等特点提高业务灵活性、提高系统的开发效率及可维护性;

2、实现了规则可视化管理、版本可追溯、通过历史版本反之可以统计业务变更过程,以及后续方便系统的整合。

qIN3i2V.png!web

2.3 规则定义 

对于一个规则而言,首先声明 package 是必须的,除 package 之外,其它对象在规则中的顺序是任意的,也就是说在规则当中必须要有一个 package 声明,同时package 声明必须要放在规则的第一行。一个规则通常包括三个部分:

package 包名 
rule "规则名"

(属性)attribute when   

(条件) - 也叫作规则的 LHS(Left Hand Side)

then

(动作/结果) - 也叫作规则的 RHS(Right Hand Side)

end

2.4 绩效核算实现

场景: 经销商顾问业绩核算  

经销商顾问绩效包含车商汇、硬广、智慧网销、智能展厅等产品,其中 车商汇产品中又区分签约版本类型(标准版、豪华版、智慧版、智慧科技版等)、升版本续约、降版本续约、平版本续约等业绩,详细步骤如下: 

2.4.1 数据抽取 

数据抽取是由统一调度中心设定执行周期、可按月、天、时执行任务,从媒介系统、CRM系统、HR系统等业务系统抽取基础数据并且进行基本条件过滤,记录同步数据日志,历史数据归档等数据存储;比如:从媒介系统抽取合同信息、合同订单信息、框架信息、回款信息、发布额等信息;CRM及主数据系统抽取拜访、培训记录、经销商数据、经销商与顾问关系等数据;HR系统抽取人员、组织等基本信息。

2.4.2 数据加工  

车商汇业绩核算流程(如下图):

步骤一(合同范围):每隔一小时由调度中心执行任务遍历合同表的所有数据,把符合合同范围为部门是经销商-营销管理部 AND 合同为正式合同AND 合同订单类型是i车商的合同数据结果数据插入业绩基础表(A1),并且记录不符合合同的具体原因信息以便查找核对,继续执行步骤二任务;

步骤二(签约版本):遍历结果(A1)的合同从合同订单宽表中查找到根据时间排序获取到该合同最后一个订单的版本类型,根据版本类型来确定合同的签约版本类型,如版本类型是"i车商(智慧版)"则合同签约类型为: 智慧版;如版本类型是"i车商(智慧科技版)"则合同签约类型为:智慧科技版;如版本类型包含 "豪华版" 的则合同版本类型为:豪华版;其他的合同版本类型为标准版;执行完规则后更新业绩基础表(A1)中的签约版本类型字段等相关信息字段,并执行步骤三;

步骤三(签约性质):遍历结果(A1)的合同从合同订单宽表中查找到该订单信息(B1),根据订单信息在合同订单宽表中查找 B1开始时间-730天内该经销商所有订单信息 ,如果没有记录则合同签约性质为"新签" ;如果有根据订单合同开始时间倒序,查找前2个订单信息,进行版本对比,第一个订单版本大于第二个版本则合同签约性质为"升级"(智慧科技版>智慧版>豪华版>标准版),如果版本一致则为"平级",第一个订单版本小于第二个版本则合同签约性质为"降级",其他的情况合同签约性质则为 "其他"; 

步骤四(0天续约):遍历结果(A1)的合同从合同宽表中查找该经销商小于当前合同的开始时间取结束时间最晚的一条数据(C1),如果有数据的情况下,C1的结束时间+1天=当前合同的开始时间 则为 0天续约成功,如果C1的结束时间+1天 != 当前合同的开始时间则为 0天续约失败;执行完成后更新业绩基础表(A1)中的是否0天续约成功字段;

步骤五:遍历结果(A1)的合同数据,如果 0天续约字段是成功并且签约性质是升级的合同则业绩类型为"升版本续约",如果 0天续约字段是成功并且签约性质是平级的合同则业绩类型为"平版本续约",如果0天续约字段是成功并且签约性质是降级的合同则业绩类型为"降版本续约"

VNRnIrV.png!web

数据流转图

2.5 规则管理

如2.4.2的步骤一需要新增一个条件:合同开始时间为2019-01-01后的合同,即新规则为:把符合合同范围为部门是经销商-营销管理部 AND 合同为正式合同AND 合同订单类型是i车商 AND 合同开始时间>= 2019-01-01 的合同数据结果数据插入业绩基础表(A1),按照常规开发我们需要找到代码,修改代码,线上部署;但是使用可视化规则管理后根据下图1架构,只需要通过可视化规则管理找到 "车商汇合同范围" 规则,在线调整增加合同开始时间条件大于2019-01-01即可,可以进行在线规则验证正确性、动态更新线上规则、做到无需代码开发即可完成规则变更及最新业绩核算,同时可以查看规则修改记录,版本记录。

EZNfEb7.png!web

三、实践与应用 

准备环境IDEA+ JDK1.8 + SpringBoot 2.0 + Drools 7.0.0.Final + Mybatis + Ant Design Pro +Maven 3; 

1、在pom.xml 文件添加如下包依赖:

<!-- drools -->

<dependency>
    <groupId>org.kie</groupId>
    <artifactId>kie-spring</artifactId>
    <version>7.0.0.Final</version>
</dependency>
<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-compiler</artifactId>
    <version>7.0.0.Final</version>
</dependency>

2、集成SpringBoot的Drools配置类(DroolsAutoConfiguration.class),该类可以获取到KieServices对象,并且通过该对象访问KIE关于构建和运行的相关对象,比如说可以获取到KieContainer、利用KieContainer来访问KBase和KSession等信息; 核心内容如下:

@Configuration

public class DroolsAutoConfiguration {

......

@Bean

@ConditionalOnMissingBean (KieContainer. class )

public KieContainer kieContainer() throws IOException {

KieUtils. setKieServices (getKieServices());

KieUtils. setKieRepository (getKieServices().getRepository());

new ReloadRules(). reloadAll (); //初始化所有规则

return KieUtils. getKieContainer ();

}

......

}

通过KieHelper可动态装载规则并且检查编译规则是否正确、通过此功能可以实现规则变更无需发布重启应用,做到热部署。

规则初始化及更新规则类内容如下:

public class ReloadRules {

/**

* 加载所有规则

* @author gaonq

*/

public static void reloadAll() {

KieServices kieServices = KieUtils. getKieServices ();

final KieRepository kieRepository = kieServices.getRepository();

kieRepository.addKieModule( new KieModule() {

@Override

public ReleaseId getReleaseId() {

return kieRepository .getDefaultReleaseId();

}

});

KieHelper kieHelper = KieUtils. getKieHelper ();

for (Map.Entry<String, String> entry : getRules ().entrySet()) {

kieHelper.addContent(entry.getValue(), "rules/" + entry.getKey() + ".drl" );

}

Results results = kieHelper.verify();

if (results.hasMessages(Message.Level. ERROR )) {

System. out .println( "更新规则错误:" + results.getMessages());

throw new IllegalStateException( "更新规则错误" );

}

KieSession kSession = kieHelper.build().newKieSession();

KieUtils. setKieSession (kSession);

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

KieUtils. setKieContainer (kieContainer);

}

......

/**

* 获取数据库所有规则初始化

* @return 规则list

*/

public static HashMap<String, String> getRules() {

HashMap<String, String> rules = new HashMap<>();

rules.put( "rule1" , "package rules.zhwx; \n " +

"rule \" rule1 \"\n " +

"    when \n " +

"        eval(true) \n " +

"    then \n " +

"        System.out.println( \" rule1 \" ); \n " +

"end" );

return rules;

}

}

/**

* 常用的方法

* @author gaonq

*/

public class KieUtils {  

......

/**

* 加载了某个特定规则组

* @param agendaGroupName 规则组名称

* @return 返回 KieSession

* @author gaonq

*/

public static KieSession getKieSession(String agendaGroupName) {

if (StringUtils. isNoneBlank (agendaGroupName)) {

kieSession .getAgenda().getAgendaGroup(agendaGroupName).setFocus();

}

return kieSession ;

}

}

执行规则方法,内容如下:

KieSession kieSession =  KieUtils. getKieSession ("规则组名称");

kieSession.fireAllRules();  

KieUtils. disposeKieSession (kieSession);

注:

• Duplicate rule name:"规则名" 不允许有重复,否则规则加载编译会报错。

• KieSession会在多次与规则引擎进行交互中,维护会话状态,必要时调用Dispose()方法清理KieSession维护的状态。

• 尽量使用aganda-group组属性,同时设置lock-on-active为true,是将若干规则分到一个组里,这个组里的规则只有一个会被执行,执行的先后顺序可以通过salience属性进行控制。

四、结语 

销售人员管理系统的搭建,规范了人力资源销售序列的管理。通过从0-1的系统建设,实现了绩效数据系统贯通、多维度多岗位评级考核、提成自动化核算、审批流程线上透明化管理,以此积累了丰富的业务背景及技术实战经验。同时,紧随业务发展,我们深入业务领域,敢于技术创新,不断完善和建设更贴合业务管理的产品,为之家的信息化系统建设提供强有力的支撑和保障。

五、参考文献

[1]  Drools规则引擎技术指南 作者: 来志辉 出版社: 北京大学出版社

[2]  官方最新文档: https://docs.jboss.org/drools/release/7.0.0.Final/drools-docs/html_single/index.html

[3]  Drools7.0.0.Final规则引擎教程: https://blog.csdn.net/wo541075754/article/category/9269332/2

fqmiAbF.jpg!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK