RuleEngine -- an easy-to-use, easy-to-use database rule engine

The rule engine is a component embedded in the application, which realizes the separation of decision logic and business system. In real business scenarios, the complexity and variability of decision logic make decision engines more and more used, and it is more and more important to separate decision logic.
At present, the commonly used rule engines in the market include Ilog JRules, Drools, Jess, Visual Rules, etc. Ilog JRules is the most famous commercial BRMS; Drools is the most active open source rules engine; Jess is the java implementation of Clips, just like JRuby is to Ruby, it is the representative of the AI ​​department; Visual Rules (flag is the rule engine) domestic business rules engine brand. However, these rule engines need to generate a large number of bean classes and Judgment classes. When implementing rule judgment, you need to write a lot of java code, or use rete specifications, and write scripts. Then in our actual programming, most of the data of these beans are stored in the database, and the judgment of the rule engine is actually a part of the SQL script running.
Therefore, here is a middleware that can use SQL scripts to define rules - RuleEngine. RuleEngine has been registered in the central library in Maven, we can directly include it in the POM.xml file.

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

   Before use, you need to configure the RuleEngine configuration file ruleEngine.properties. RuleEngine supports 3 rule definition methods, namely 1, database table configuration; 2, xml file configuration; 3, Drools drl file method.
You can set the rule.reader field in ruleEngine.properties, which is explained below:

1. The database table configuration method. In ruleEngine.properties, set rule.reader = database.
At this time, you need to configure the following information
a) db.rule.table field, set db.rule.table=tl_rule_define (table name). The definition of this table structure is defined in https://github.com/Hale-Lee/RuleEngine/tree/dev/referenc (there are 2 ways of oralce and mysql).
b) db.accesser data connection method, RuleEngine provides three methods: direct jdbc connection, Druid connection pool, and Spring framework connection. If you use jdbc link or Druid link, you need to set db.accesser=tech.kiwa.engine.utility.DirectDBAccesser (setting UseDruid of DirectDBAccesser can distinguish whether to use Druid connection pool, the default is true use). If you use the connection of the Spring framework directly, you need to set db.accesser= tech.kiwa.engine.utility.SpringDBAccesser.
RuleEngine also provides the interface of DBAccesser, we can obtain our own connection by implementing the method of the interface of DBAccessor.
c) If you use jdbc link or Druid link, you need to configure jdbc properties or Druid connection pool parameters. RuleEngine can configure connection pool parameters independently, or you can directly use the existing connection parameters in the project.
A typical configuration file is as follows (using Druid configuration): #Data

driver
jdbc.driver=com.mysql.cj.jdbc.Driver
#jdbc.driver=oracle.jdbc.driver.OracleDriver #Database
connection
jdbc.url=jdbc: mysql://127.0.0.1:3306/hosp?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=true #Database
username

jdbc.username=oracle
jdbc.password=user #Table
defined by rules
db.rule.table=TL_RULE_DEFINE
db .accesser=tech.kiwa.engine.utility.DirectDBAccesser
rule.reader=database

The database table structure is defined as follows:

-- 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 ,
COMMENT ON COLUMN "TL_RULE_DEFINE"."PARAM_NAME" IS 'The parameters of the SQL statement, multiple parameters are used, divided, and the DefaultCustomerCheck class needs to be completed and inherited when reading the value. ';
















COMMENT ON COLUMN "TL_RULE_DEFINE"."PARAM_TYPE" IS 'exe_sql or exe_class parameter type, multiple types are separated by commas (,), and param_name needs to be in one-to-one correspondence. ';
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, etc. ';
COMMENT ON COLUMN "TL_RULE_DEFINE"."BASELINE" IS 'parameter value, compare the target value';
COMMENT ON COLUMN "TL_RULE_DEFINE"."RESULT" IS '1 - pass 2 - concern 3 - reject when the logical operation meets the target value Read the changes. ';

COMMENT ON COLUMN "TL_RULE_DEFINE"."CONTINUE_FLAG" IS 'Whether to continue to execute the next one, if a rule meets the interruption, then set to 2. 1 -- continue 2 -- interruption';
COMMENT ON COLUMN "TL_RULE_DEFINE"." PARENT_ITEM_NO" IS 'If it is a sub-rule, then you need to fill in the item_no' of the parent rule;
COMMENT ON COLUMN "TL_RULE_DEFINE"."PARENT_EXPRESS" IS 'The operation expression of each ITEM of the same PARENT_ITEM. ( A AND B OR C)';
COMMENT ON COLUMN "TL_RULE_DEFINE"."EXECUTOR" IS 'The executed body after the result is executed, inherited from AbstractCommand. ';
COMMENT ON COLUMN "TL_RULE_DEFINE"."ENABLE_FLAG" IS 'Whether to use 1 - valid 2 - invalid';

-- ------------------------ ----
-- Checks structure for table TL_RULE_DEFINE
-- ----------------------------
ALTER TABLE "TL_RULE_DEFINE"

ADD CHECK ("ITEM_NO" IS NOT NULL); 2, xml file configuration, the way of xml file configuration also needs to configure the read and write mode of the engine in ruleEngine.properties. Just configure two things.

rule.reader=xml #Specify
the file name of the rule file, and RuleEngine will search for the file from the classpath.
xml.rule.filename=ruleconfig.xml The

XML file is written in a similar way to table. The typical xml file format is:

<?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="Customer ID number rules"/>
        <property name="

        <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=">"/>         <property name="baseline_desc" value="Customer's ID number is in the number of blacklists greater than 0"/>
        <property name="baseline" 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=">"/>
        <property name="baseline" value="0"/> </rules>     </rule>
        <property name="baseline_desc" value="Customer's ID number is greater than 0 in the number of blacklists"/>




3. In the Drools file method, RuleEngine also supports reading the rules in the Drools drl file, and can directly execute its rule body. At this point, you need to configure the read and write mode of the engine in ruleEngine.properties. Just configure two things.

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

For the file style of Drools, please refer to the specific Drools documentation. The typical style is:

#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

starts RuleEngine, which is detected for a specific target object (Bean), the target The object (Bean) must be readable, the corresponding get method must be provided, or its member variables must be public. For example, a student object, we need to check whether the student object conforms to the rules we defined. Therefore, the object must exist before calling the rule engine, and if there are multiple objects, execute the condition in the loop body.

The sample code is as follows:
EngineService service = new EngineService();

try {

Student st = new Student(); //Create a student object
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();
}


In the above code, the Sutdent object has a getAge method, so it can be accessed, and its rules can be executed, otherwise a RuleEngineException will be thrown. In the corresponding rule, the ageUp() is executed. Command operation.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326129384&siteId=291194637