MyException - 我的异常网
当前位置:我的异常网» 数据库 » RuleEngine - 一款使用简略,入门方便的数据库规则

RuleEngine - 一款使用简略,入门方便的数据库规则引擎

www.MyException.Cn  网友分享于:2018-03-30  浏览:0次
RuleEngine -- 一款使用简单,入门方便的数据库规则引擎
规则引擎是嵌入在应用程序中的组件,实现了决策逻辑和业务系统的分离功能。在现实业务场景中,决策逻辑的复杂性和可变性,使得决策引擎的应用越来越多,把决策逻辑单独分离出来也显得越来越重要了。
目前市场上常用的规则引擎有Ilog JRules,Drools,Jess,Visual Rules等。Ilog JRules 是最有名的商用BRMS;Drools 是最活跃的开源规则引擎;Jess 是Clips的java实现,就如JRuby之于Ruby,是AI系的代表; Visual Rules(旗正规则引擎)国内商业规则引擎品牌。但是这些规则引擎都需要生成大量的bean类和Judgment类,在实现规则判断的时候,需要编写大量的java代码,或者使用rete规范,另外编写脚本。然后我们实际编程中,这些bean的数据大多数存于数据库中,规则引擎的判断实际上是SQL脚本运行的一部分。
因此在这里介绍一款可以使用SQL脚本来定义规则的中间件 -- RuleEngine。RuleEngine已经登记在Maven中的中央库中了,我们可以直接在POM.xml文件中包含就可以了。

<dependency>
        <groupId>com.github.hale-lee</groupId>
        <artifactId>RuleEngine</artifactId>
        <version>0.1.0</version>
    </dependency>

   使用前,需要先配RuleEngine的配置文件ruleEngine.properties,RuleEngine支持3种规则定义方式,分别是1,数据库table配置;2,xml文件配置;3,Drools的drl文件方式。
在ruleEngine.properties中设置rule.reader字段即可,下面分别说明:

1, 数据库table配置方式,在ruleEngine.properties中,设置rule.reader = database
此时需要配置下面的信息
a) db.rule.table字段,设置db.rule.table=tl_rule_define(表名)。此表结构的定义在https://github.com/Hale-Lee/RuleEngine/tree/dev/referenc中有定义(有oralce和mysql的2种方式)。
b) db.accesser数据连接方式,RuleEngine提供了直接的jdbc连接,Druid连接池,Spring框架连接3种方式。 如果使用jdbc链接或者是Druid链接,那么需要设置db.accesser=tech.kiwa.engine.utility.DirectDBAccesser(设置DirectDBAccesser的UseDruid可以区别是否使用Druid连接池,默认是true使用)。如果直接使用Spring框架的连接,那么需要设置db.accesser= tech.kiwa.engine.utility. SpringDBAccesser。
RuleEngine也提供DBAccesser的接口,我们可以通过实现DBAccessor的接口的方法来自己获得自己的连接。
c) 如果使用jdbc链接或者是Druid链接,那么需要配置jdbc属性,或者是Druid的连接池参数,RuleEngine可以独立配置连接池参数,也可以直接使用项目中现有的连接参数。
典型的配置文件的方式如下(使用Druid配置):

#数据驱动
jdbc.driver=com.mysql.cj.jdbc.Driver
#jdbc.driver=oracle.jdbc.driver.OracleDriver
#数据库连接
jdbc.url=jdbc:mysql://127.0.0.1:3306/hosp?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=true
#数据库用户名

jdbc.username=oracle
jdbc.password=user
#规则定义的表
db.rule.table=TL_RULE_DEFINE
db.accesser=tech.kiwa.engine.utility.DirectDBAccesser
rule.reader=database

数据库表结构的定义如下:

-- Table structure for TL_RULE_DEFINE
-- ----------------------------
DROP TABLE "TL_RULE_DEFINE";
CREATE TABLE "TL_RULE_DEFINE" (
"ITEM_NO" NVARCHAR2(32) NOT NULL ,
"CONTENT" NVARCHAR2(256) NULL ,
"EXE_SQL" NVARCHAR2(512) NULL ,
"EXE_CLASS" NVARCHAR2(128) NULL ,
"PARAM_NAME" NVARCHAR2(128) NULL ,
"PARAM_TYPE" NVARCHAR2(128) NULL ,
"COMPARISON_CODE" NVARCHAR2(32) NULL ,
"COMPARISON_VALUE" NVARCHAR2(64) NULL ,
"BASELINE" NVARCHAR2(64) NULL ,
"RESULT" NVARCHAR2(6) NULL ,
"PRIORITY" NVARCHAR2(32) NULL ,
"CONTINUE_FLAG" NVARCHAR2(2) NULL ,
"PARENT_ITEM_NO" NVARCHAR2(2) NULL ,
"PARENT_EXPRESS" NVARCHAR2(256) NULL ,
"EXECUTOR" NVARCHAR2(64) NULL ,
"REMARK" NVARCHAR2(64) NULL ,
"COMMENTS" NVARCHAR2(64) NULL ,
"ENABLE_FLAG" NVARCHAR2(2) NULL ,
"CREATE_TIME" TIMESTAMP(6)  NULL ,
"UPDATE_TIME" TIMESTAMP(6)  NULL
)
LOGGING
NOCOMPRESS
NOCACHE;


COMMENT ON TABLE "TL_RULE_DEFINE" IS '规则引擎定义表';
COMMENT ON COLUMN "TL_RULE_DEFINE"."ITEM_NO" IS '主key';
COMMENT ON COLUMN "TL_RULE_DEFINE"."CONTENT" IS '中文的内容说明';
COMMENT ON COLUMN "TL_RULE_DEFINE"."EXE_SQL" IS '执行的SQL语句';
COMMENT ON COLUMN "TL_RULE_DEFINE"."EXE_CLASS" IS '执行检查的java类名, 与exe_sql二者只填写一项';
COMMENT ON COLUMN "TL_RULE_DEFINE"."PARAM_NAME" IS 'SQL语句的参数,多个参数用,分割,读值时需要完成和继承DefaultCustomerCheck类。';
COMMENT ON COLUMN "TL_RULE_DEFINE"."PARAM_TYPE" IS 'exe_sql或者exe_class的参数类型,多个类型用逗号(,)分割,与param_name需一一对应。';
COMMENT ON COLUMN "TL_RULE_DEFINE"."COMPARISON_CODE" IS '01: = ,  02: > , 03 : < , 04 != , 05 >= , 06: <= , 07 include , 08 exclude , 09: included by 10: excluded by  11: equal , 12 : not equal 13: euqalIngoreCase 15: matches 16: NOT MATCHES';
COMMENT ON COLUMN "TL_RULE_DEFINE"."COMPARISON_VALUE" IS '=,>,<,>=,<=, !=, include, exclude等内容。';
COMMENT ON COLUMN "TL_RULE_DEFINE"."BASELINE" IS '参数值,比较目标值';
COMMENT ON COLUMN "TL_RULE_DEFINE"."RESULT" IS '1 - 通过  2 - 关注 3 -拒绝  逻辑运算满足目标值的时候读取改内容。';
COMMENT ON COLUMN "TL_RULE_DEFINE"."PRIORITY" IS '执行的优先顺序,值大的优先执行.';
COMMENT ON COLUMN "TL_RULE_DEFINE"."CONTINUE_FLAG" IS '是否继续执行下一条,如果某条规则满足中断的话,那么就设置为 2. 1 -- 继续  2 -- 中断';
COMMENT ON COLUMN "TL_RULE_DEFINE"."PARENT_ITEM_NO" IS '如果是子规则,那么需要填写父规则的item_no';
COMMENT ON COLUMN "TL_RULE_DEFINE"."PARENT_EXPRESS" IS '同一PARENT_ITEM的各个ITEM的运算表达式。 ( A AND B OR C)';
COMMENT ON COLUMN "TL_RULE_DEFINE"."EXECUTOR" IS '结果执行后的被执行体,从AbstractCommand中继承下来。';
COMMENT ON COLUMN "TL_RULE_DEFINE"."ENABLE_FLAG" IS '是否使用 1 - 有效  2 - 失效';

-- ----------------------------
-- Checks structure for table TL_RULE_DEFINE
-- ----------------------------
ALTER TABLE "TL_RULE_DEFINE" ADD CHECK ("ITEM_NO" IS NOT NULL);

2, xml文件配置,xml文件配置的方式也需要在ruleEngine.properties中配置引擎的读写方式。仅仅配置两项内容即可。

rule.reader=xml
#指定规则文件的文件名,RuleEngine会从classpath中搜索该文件。
xml.rule.filename=ruleconfig.xml

XML文件的写法与table类似,典型的xml文件格式为:

<?xml version="1.0" encoding="UTF-8"?>
<rules >
<organization>
<url>www.kiwa.tech</url>
</organization>

    <description>
        Configuration for the rule list which stores the rule information in-memory and executed by rule engine service.
    </description>

    <rule id="totallist" exe_class="" method="" parent="">
        <property name="content" value="客户身份证号码规则"/>
        <property name="result" value="RESULT.REJECTED" desc="拒绝"/>
        <property name="continue_flag" value="1"/>
        <property name="group_express" value="(blacklist || graylist)"/>
<property name="priority" value="10"/>
    </rule>

    <rule id="blacklist" parent="totallist">
        <property name="content" value="客户身份证号码命中内部黑名单"/>
        <property name="exe_sql" value="select count(1) from customer_black_list where certificate_type >=1 and customer_no = ? and is_black = 1"/>
        <property name="param" value="CUSTOMER_NO" type="java.lang.String" desc="客户编号"/>
        <property name="comparison_code" value="02"/>
        <property name="comparison_value" value="&gt;"/>
        <property name="baseline" value="0"/>
        <property name="baseline_desc" value="客户的身份证号码在黑名单表个数中大于0"/>
    </rule>


    <rule id="graylist" exe_class="" method="" parent="totallist">
        <property name="content" value="客户身份证号码命中内部灰名单"/>
        <property name="exe_sql" value="select count(1) from customer_black_list where certificate_type =1 and customer_no = ? and is_gray = 1"/>
        <property name="param" value="CUSTOMER_NO" type="java.lang.String" desc="客户编号"/>
        <property name="comparison_code" value="02"/>
        <property name="comparison_value" value="&gt;"/>
        <property name="baseline" value="0"/>
        <property name="baseline_desc" value="客户的身份证号码在黑名单表个数中大于0"/>
    </rule>

</rules>

3, Drools文件方式,RuleEngine同样支持读取Drools的drl文件中的规则,并且可以直接执行其规则体。此时需要在ruleEngine.properties中配置引擎的读写方式。仅仅配置两项内容即可。

rule.reader=drools
drools.rule.filename=sample.drl

Drools的文件样式请参考具体Drools的文档,典型的样式为:

#this is a test
package tech.kiwa.engine.entity;
globals java.util.List myGlobalList

import tech.kiwa.engine.sample.Student;

function void callOver(Student $student){

  if($student != null){
  System.out.println("student [" +  $student.name + "] is called.");
  }

}
function void ageUp(Student $student, int age ){

  if($student != null){
  $student.setAge( $student.getAge() + age);
  }

}

declare teacher
   age : int
   name : String
   sex : int
end

query "juniorBoy"
$student: Student( age <=14 && (age >10 || age !=12 , sex  ==1 || sex == 2 ), name =="tony")
end

query "querymale"(int $gender)
$student: Student(sex == $gender)
end

rule "ageUp12"
salience 400
when
$student: Student(age <
/* antoher rule */
then
System.out.println("I was called, my name is : " + $student.name);
ageUp($student,12);
//callOver($student);
end

rule "isTom"
salience 30
date-expires "2018-12-01"
dialet "java"
when
$student: Student(name == tom)
then
$student.sex = 4;
    callOver($student);
end

启动RuleEngine,RuleEngine是针对一个具体的目标对象(Bean)进行检测的,该目标对象(Bean)必须是可读的,必须提供对应的get方法,或者其成员变量是public的。比如学生对象,我们需要检测该学生对象是否符合我们定义的规则。因此,在调用规则引擎前,必须存在该对象,如果有多个对象,那请在循环体中执行该条件。

示例代码如下:
EngineService service = new EngineService();

try {

Student st = new Student();  //建立学生对象
st.setAge(5);
st.name = "tom";
st.sex = 1;

EngineRunResult result = service.start(st);
System.out.println(result.getResult().getName());

System.out.println(st.getAge());
} catch (RuleEngineException e) {

e.printStackTrace();
}


上述代码中,Sutdent对象存在getAge方法,因此是可以被访问的,其规则也是可以执行的,否则会抛出RuleEngineException异常,在对应的规则中,执行了ageUp()的Command操作。

文章评论

漫画:程序员的工作
漫画:程序员的工作
我是如何打败拖延症的
我是如何打败拖延症的
编程语言是女人
编程语言是女人
Java程序员必看电影
Java程序员必看电影
程序员必看的十大电影
程序员必看的十大电影
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
中美印日四国程序员比较
中美印日四国程序员比较
旅行,写作,编程
旅行,写作,编程
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
老程序员的下场
老程序员的下场
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
程序员都该阅读的书
程序员都该阅读的书
Google伦敦新总部 犹如星级庄园
Google伦敦新总部 犹如星级庄园
程序员的鄙视链
程序员的鄙视链
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
我的丈夫是个程序员
我的丈夫是个程序员
代码女神横空出世
代码女神横空出世
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
程序员应该关注的一些事儿
程序员应该关注的一些事儿
为什么程序员都是夜猫子
为什么程序员都是夜猫子
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
10个调试和排错的小建议
10个调试和排错的小建议
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
程序员和编码员之间的区别
程序员和编码员之间的区别
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
总结2014中国互联网十大段子
总结2014中国互联网十大段子
鲜为人知的编程真相
鲜为人知的编程真相
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
如何成为一名黑客
如何成为一名黑客
 程序员的样子
程序员的样子
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
那些争议最大的编程观点
那些争议最大的编程观点
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有