IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 3 Drools语法介绍 -> 正文阅读

[Java知识库]3 Drools语法介绍

1 规则文件的组成

在Drools的初体验里面,我们编写了一个droolsFirst.drl的规则文件,并运行达到了预期的结果。从规则的命名可以看出,Drools的规则文件一般是以.drl(Drools Rule Language)结尾的文件。

一个完整的规则文件一般会由下面内容构成:

注意:上面说的Drools规则文件一般是以.drl结尾的,其实在实际的使用中还可以使用到决策表(.xls,.xlsx)结尾的文件,当然也可以把规则预先存到mysql等数据库中,使用的时候加载出来。

2 规则体语法结构

规则体是规则文件内容中的重要组成部分,是进行业务规则判断、处理业务结果的重要组成部分。

构成规则的规则体语法结构如下:

rule "ruleName"
    attributes
    when
        LHS
    then
        RHS
end

rule:规则名称,表示规则开始,规则名称需要保证唯一性;

attributes:规则属性,是rule与when之间的参数,为可选项;

when:关键字,后面跟规则的条件部分;

LHS(Left Hand Side):是规则的条件部分的通用名称,它由零个或多个条件元素组成;如果LHS为空,则它将被视为始终为true的条件元素。

then:关键字,后面跟规则的结果部分;

RHS(Right Hand Side):是规则的后果或行动部分的通用名称。

end:关键字,表示一个规则结束。

3 Pattern模式匹配

在介绍Pattern模式匹配之前,我们先弄清楚一个原理。Drools规则引擎的运行原理是将Working Memory中的Fact对象匹配编写的规则,如果匹配成功就会触发相应的逻辑。在编写规则的LHS部分就是由多个条件构成的,整个过程的执行就是条件的判断和匹配。

我们通过上面编写的例子来看看这种方式:

/**
* 规则名称
**/
rule "rule_monthIn_2"
    when
       /**
       * $s 绑定变量,如果后面条件匹配成功,用来接收Fact中的对象
       * PersonBasicInfo 类型匹配,工作内存中要有一个PersonBasicInfo类型的对象
       * monthIn 属性匹配,如java中的属性值,这里我们可以看到用的是收入大小的比较
       **/
       $s:PersonBasicInfo(monthIn.compareTo(BigDecimal.valueOf(10000))<0 && monthIn.compareTo(BigDecimal.valueOf(5000))>=0)
    then
       Integer score=Objects.isNull($s.getScore())?0+5:$s.getScore()+5;
       $s.setScore(score);
end

通过上面的例子,可以看出只有同时满足工作内存中有一个PersonBasicInfo的对象,并且这个对象中的月收入的范围在5000之10000之间才会满足条件出发then后面的逻辑。

绑定变量除了用来绑定对象以外,也可以用来在绑定属性,如下:

/**
* 规则名称
**/
rule "rule_monthIn_3"
    when
       /**
       * $s 绑定变量,如果后面条件匹配成功,用来接收Fact中的对象
       * PersonBasicInfo 类型匹配,工作内存中要有一个PersonBasicInfo类型的对象
       * monthIn 属性匹配,如java中的属性值,这里我们可以看到用的是收入大小的比较
       * $m,$m1用来绑定属性匹配的值(注意是指结果值,如果传入的monthIn是6000那么$m是-1,$m1是1)
       **/
       $s:PersonBasicInfo($m:monthIn.compareTo(BigDecimal.valueOf(10000))<0 && $m1:monthIn.compareTo(BigDecimal.valueOf(5000))>=0)
    then
      System.out.println($m);
      System.out.println($m1);
end

LHS部分也可以写多个条件,多个条件可以用and连接在一起,不写默认是and。

4 比较运算符

Drools规则引擎提供的运算符除了有大小比较外还提供了正则匹配及集合的包含操作等,具体的运算符内容如下:

前面的比较运算符和Java中的比较运算符使用方式一致,下面我们重点了解一下集合匹配的一些相关操作。在介绍下面的案例之前,我们先描述一下这样一个例子,学生可以选择多种课程,现在要知道一个学生是否报了语文课或者要知道这个学生的名字是否姓张,其实这些操作就可以通过下面讲解的部分解决,我们先定义一个学生的类。

package com.dream21th.first;

import java.util.List;

/*
 * @Author dream21th
 **/
public class Student {

    /**
     *  学生姓名
     */
    private String name;

    /**
     * 学生年龄
     */
    private String age;

    /**
     * 课程
     */
    private List<String> subjects;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public List<String> getSubjects() {
        return subjects;
    }

    public void setSubjects(List<String> subjects) {
        this.subjects = subjects;
    }
}

4.1 contains和not contains

接下来编写一个Drools规则文件,文件的详细内容如下:

package ruls;
import  com.dream21th.first.Student

/**
*    这个规则是判断包含的逻辑,如果选择的课程里面有语文课就会触发
**/
rule "rule_contains"
    when
       $s:Student(subjects contains "语文")
    then
       System.out.println("学生:"+$s.getName()+"选择的课程包含语文");
end


/**
*    这个规则是判断不包含的逻辑,如果选择的课程里面没有英语课就会触发
**/
rule "rule_not_contains"
    when
       $s:Student(subjects not contains "英语")
    then
       System.out.println("学生:"+$s.getName()+"选择的课程不包含英语");
end

编写一个测试用例,测试用例的代码如下:

@Test
    public void test2(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieClasspathContainer =kieServices.getKieClasspathContainer();
        //会话对象,用于和规则引擎交互
        KieSession kieSession = kieClasspathContainer.newKieSession();

        Student student=new Student();
        student.setName("马芸");
        student.setAge(19);
        student.setSubjects(Arrays.asList("语文","数学","英语"));
        kieSession.insert(student);
        //激活规则引擎,如果规则匹配成功则执行规则
        kieSession.fireAllRules();

        //关闭会话
        kieSession.dispose();

    }

这个例子的学生选择了"语文","数学","英语"三门课程,按照上面写的规则,只会触发第一条,运行代码得出结果和预期一致。

4.2 memberOf和not memberOf

接下来编写一个Drools规则文件,文件的详细内容如下:

package ruls;
import  com.dream21th.first.Student

/**
*    这个规则判断是否是集合中的成员逻辑,如果选择的课程里面有语文课就会触发
**/
rule "rule_memberOf"
    when
       $s:Student("语文" memberOf subjects)
    then
       System.out.println("学生:"+$s.getName()+"语文在选择的课程中");
end


/**
*    这个规则判断不是集合中的成员的逻辑,如果选择的课程里面没有地理课就会触发
**/
rule "rule_not_memberOf"
    when
       $s:Student("地理" not memberOf subjects)
    then
       System.out.println("学生:"+$s.getName()+"地理不在选择的课程中");
end

编写一个测试用例,测试用例的代码如下:

 @Test
    public void test3(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieClasspathContainer =kieServices.getKieClasspathContainer();
        //会话对象,用于和规则引擎交互
        KieSession kieSession = kieClasspathContainer.newKieSession();

        Student student=new Student();
        student.setName("徐佳莹");
        student.setAge(21);
        student.setSubjects(Arrays.asList("语文","数学","英语"));
        kieSession.insert(student);
        //激活规则引擎,如果规则匹配成功则执行规则
        kieSession.fireAllRules();

        //关闭会话
        kieSession.dispose();

    }

这个例子的学生选择了"语文","数学","英语"三门课程,按照上面写的规则,两条规则都会触发,运行代码得出结果和预期一致。

4.3 matches和not matches

matches和not matches是用来正则匹配逻辑的,接下来我们通过编写如下规则代码:

package ruls;
import  com.dream21th.first.Student

/**
*    这个规则是匹配逻辑,如果学生姓名以赵开头就会触发规则
**/
rule "rule_matches"
    when
       $s:Student(name matches "赵.*")
    then
       System.out.println("学生:"+$s.getName()+"触发matches规则");
end


/**
*    如果学生姓名不是以云结尾就触发
**/
rule "rule_not_matches"
    when
       $s:Student(name not matches ".*云")
    then
       System.out.println("学生:"+$s.getName()+"触发not matches规则");
end

编写一个测试用例,测试用例的代码如下:

@Test
    public void test4(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieClasspathContainer =kieServices.getKieClasspathContainer();
        //会话对象,用于和规则引擎交互
        KieSession kieSession = kieClasspathContainer.newKieSession();

        Student student=new Student();
        student.setName("赵鹏程");
        student.setAge(21);
        kieSession.insert(student);
        //激活规则引擎,如果规则匹配成功则执行规则
        kieSession.fireAllRules();

        //关闭会话
        kieSession.dispose();

    }

这个学生的姓名叫赵鹏程,满足上面的两个规则,就会触发编写的逻辑。

5 执行指定规则

通过上面运行的案例可以看到,我们在调用规则代码时,满足条件的规则都会被执行。那么如果我们只想执行其中的某个规则如何实现呢?Drools给我们提供的方式是通过规则过滤器来实现执行指定规则。对于规则文件不用做任何修改,只需要修改Java代码即可,如下:

//通过规则过滤器实现只执行指定规则
kieSession.fireAllRules(new RuleNameEqualsAgendaFilter("规则名称"));

6 关键字

Drools的关键字分为:硬关键字(Hard keywords)和软关键字(Soft keywords)。

硬关键字是我们在规则文件中定义包名或者规则名时明确不能使用的,否则程序会报错。软关键字虽然可以使用,但是不建议使用。

硬关键字包括:true false null

软关键字包括:lock-on-active date-effective date-expires no-loop auto-focus activation-group agenda-group ruleflow-group entry-point duration package import dialect salience enabled attributes rule extend when then template query declare function global eval not in or and exists forall accumulate collect from action reverse result end over init

7 Drools内置方法

规则文件的RHS部分的主要作用是通过一些内置方法来插入,删除或修改工作内存中的Fact数据,来达到控制规则引擎执行的目的。Drools提供了一些方法可以用来操作工作内存中的数据,操作完成后规则引擎会重新进行相关规则的匹配,原来没有匹配成功的规则在我们修改数据完成后有可能就会匹配成功了。

7.1 update方法使用

update方法的主要作用是将工作内存中的对象更新,进而可以匹配新的规则属性。我们编写新的规则文件,规则文件的路径是 \resources\first\updateTests.drl,规则文件的内容如下:

package rules;
import com.dream21th.first.LoanInfo;

rule "update_rank_A"
    when
        $s:LoanInfo(rank=="A")
    then
        System.out.println("用户名:"+$s.getName()+",评级:"+$s.getRank());
        $s.setRank("B");
        update($s);//更新工作内存中的对象
end

rule "update_rank_B"
    when
        $s:LoanInfo(rank=="B")
    then
        System.out.println("用户名:"+$s.getName()+",评级:"+$s.getRank());
end

规则文件中使用到的LoanInfo类的信息如下:

package com.dream21th.first;

/*
 * @Author dream21th
 **/
public class LoanInfo {

    private String name;

    private String rank;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getRank() {
        return rank;
    }

    public void setRank(String rank) {
        this.rank = rank;
    }
}

接着我们编写测试案例,测试案例的具体内容如下:

  @Test
    public void testUpdate(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieClasspathContainer =kieServices.getKieClasspathContainer();
        //会话对象,用于和规则引擎交互
        KieSession kieSession = kieClasspathContainer.newKieSession();
        LoanInfo loanInfo=new LoanInfo();
        loanInfo.setName("李云飞");
        loanInfo.setRank("A");
        kieSession.insert(loanInfo);
        //激活规则引擎,如果规则匹配成功则执行规则
        kieSession.fireAllRules();

        //关闭会话
        kieSession.dispose();

    }

案例解释:

1,首先我们在工作内存中添加一个LoanInfo的对象,对象的Rank值为A;

2,update_rank_A这条规则匹配成功,接在在then里面修改了工作内存中的Rank值,并使用update方法更新工作内存中的值;

3,由于工作内存中的Rank值被修改为B,接着update_rank_B规则触发。

注意:工作内存中的值修改后,要通过update方法更新才会使下面的匹配规则生效;同时要注意规则的编写,避免由于更新工作内存中的值导致规则重新匹配产生死循环。

7.2 insert方法使用

insert方法主要是向工作内存中插入对象,并让相关规则触发和匹配。编写新的规则,规则文件的路径为\resources\first\insertTests.drl。规则文件的具体内容如下:

package rules;
import com.dream21th.first.LoanInfo;

rule "insert_rank_C"
    when
       $s:LoanInfo(rank=="C")
    then
       System.out.println("用户名:"+$s.getName()+",评级:"+$s.getRank());
       LoanInfo loanInfo=new LoanInfo();
       loanInfo.setName("赵云龙");
       loanInfo.setRank("D");
       insert(loanInfo);//向工作内存中插入新的对象
end

rule "insert_rank_D"
    when
       $s:LoanInfo(rank=="D")
    then
       System.out.println("用户名:"+$s.getName()+",评级:"+$s.getRank());
end

rule "insert_name_1"
    when
       $s:LoanInfo(name=="赵云龙")
    then
       System.out.println("规则insert_name_1:用户名:"+$s.getName()+",评级:"+$s.getRank());
end


rule "insert_name_2"
    when
       $s:LoanInfo(name=="李云飞")
    then
       System.out.println("规则insert_name_2:用户名:"+$s.getName()+",评级:"+$s.getRank());
end

接着我们编写测试案例,测试案例的具体内容如下:

    @Test
    public void testInsert(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieClasspathContainer =kieServices.getKieClasspathContainer();
        //会话对象,用于和规则引擎交互
        KieSession kieSession = kieClasspathContainer.newKieSession();
        LoanInfo loanInfo=new LoanInfo();
        loanInfo.setName("李云飞");
        loanInfo.setRank("C");
        kieSession.insert(loanInfo);
        //激活规则引擎,如果规则匹配成功则执行规则
        kieSession.fireAllRules();

        //关闭会话
        kieSession.dispose();

    }

案例解释:

1,测试案例中先向工作内存中插入一个LoanInfo对象,对象的name属性为李云飞,rank为C;

2,insert_rank_C规则满足条件触发,触发后再then逻辑里面新插入对象LoanInfo,对象的name属性为赵云龙,rank为D;

3,此时工作内存中有两个LoanInfo对象,新加的对象满足insert_rank_D和insert_name_1规则,原始对象满足insert_name_2规则,故可以在控制台中输出四条规则的触发结果;

7.3 retract方法

retract方法主要是删除工作内存中的对象,并让相关规则触发和匹配。编写新的规则,规则文件的路径为\resources\first\retractTests.drl。规则文件的具体内容如下:

package rules;
import com.dream21th.first.LoanInfo;

rule "retract_rank_E_1"
    when
       $s:LoanInfo(rank=="E")
    then
       System.out.println("规则:retract_rank_E_1:用户名:"+$s.getName()+",评级:"+$s.getRank());
       retract($s);//删除工作内存中的对象
end

rule "retract_rank_E_2"
    when
       $s:LoanInfo(rank=="E")
    then
       System.out.println("规则:retract_rank_E_2:用户名:"+$s.getName()+",评级:"+$s.getRank());
end

接着我们编写测试案例,测试案例的具体内容如下:

    @Test
    public void testRetract(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieClasspathContainer =kieServices.getKieClasspathContainer();
        //会话对象,用于和规则引擎交互
        KieSession kieSession = kieClasspathContainer.newKieSession();
        LoanInfo loanInfo=new LoanInfo();
        loanInfo.setName("张红");
        loanInfo.setRank("E");
        kieSession.insert(loanInfo);
        //激活规则引擎,如果规则匹配成功则执行规则
        kieSession.fireAllRules();

        //关闭会话
        kieSession.dispose();

    }

案例解释:

1,我们在LoanInfo中插入一个LoanInfo对象,对象的name属性是张红,rank为E;

2,接着触发retract_rank_E_1规则,规则触发后通过retract删除工作内存中的LoanInfo对象,发现retract_rank_E_2没有触发。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-08 22:14:58  更:2022-03-08 22:17:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:11:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码