• Drools规则引擎入门指南(一)


    最近项目需要增加风控系统,在经过一番调研以后决定使用Drools规则引擎。因为项目是基于SpringCloud的架构,所以此次学习使用了SpringBoot2.0版本结合Drools7.14.0.Final版本。

    引入依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-core</artifactId>
    <version>7.14.0.Final</version>
    </dependency>
    <dependency>
    <groupId>org.kie</groupId>
    <artifactId>kie-spring</artifactId>
    <version>7.14.0.Final</version>
    </dependency>

    创建配置类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    @Configuration
    public class DroolsAutoConfiguration {
    private static final String RULES_PATH = "rules/";

    @Bean
    @ConditionalOnMissingBean(KieFileSystem.class)
    public KieFileSystem kieFileSystem() throws IOException {
    KieFileSystem kieFileSystem = getKieServices().newKieFileSystem();
    for (Resource file : getRuleFiles()) {
    kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_PATH + file.getFilename(), "UTF-8"));
    }
    return kieFileSystem;
    }

    private Resource[] getRuleFiles() throws IOException {
    ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
    return resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "**/*.*");
    }

    @Bean
    @ConditionalOnMissingBean(KieContainer.class)
    public KieContainer kieContainer() throws IOException {
    final KieRepository kieRepository = getKieServices().getRepository();
    kieRepository.addKieModule(new KieModule() {
    public ReleaseId getReleaseId() {
    return kieRepository.getDefaultReleaseId();
    }
    });
    KieBuilder kieBuilder = getKieServices().newKieBuilder(kieFileSystem());
    kieBuilder.buildAll();
    return getKieServices().newKieContainer(kieRepository.getDefaultReleaseId());
    }


    @Bean
    @ConditionalOnMissingBean(KieBase.class)
    public KieBase kieBase() throws IOException {
    return kieContainer().getKieBase();
    }

    @Bean
    @ConditionalOnMissingBean(KieSession.class)
    public KieSession kieSession() throws IOException {
    KieSession kieSession = kieContainer().newKieSession();
    return kieSession;
    }

    @Bean
    @ConditionalOnMissingBean(KModuleBeanFactoryPostProcessor.class)
    public KModuleBeanFactoryPostProcessor kiePostProcessor() {
    return new KModuleBeanFactoryPostProcessor();
    }
    public KieServices getKieServices() {
    System.setProperty("drools.dateformat","yyyy-MM-dd");
    return KieServices.Factory.get();
    }
    }

    在这个时候我们的基本环境已经搭建好了,接下来我们一起来学习Drools吧

    HelloWord

    程序员的世界里,我们学习任何一门语言都是以HelloWord开启的,本次学习也不例外。

    1.创建规则文件

    Drools的规则文件是以*.drl结尾的文件,我们来看一个最简单的规则文件中都是包含什么。

    通常来说,我们会把规则文件放在resources资源文件夹下,这里呢我们在resources文件夹下新建一个rules文件夹,然后再新建一个HelloWord.drl文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package rules;
    import cn.org.zhixiang.entity.User;
    import java.lang.String;
    import java.util.List;

    rule "hello,word"
    when
    eval(true)
    then
    System.err.println("hello,word!");
    end
    1. 规则文件,就是我们新建的这个HelloWord.drl可以理解为一个Java类
    2. package,这个跟Java中的包名是差不多的
    3. import,此文件中需要的类。
    4. rule,可以理解为给这个规则起的一个名字,一个规则文件中可以包含多个rule。
    5. when,when下面可以放置一些条件判断的表达式以及定义一些变量什么的。如果里面内容为空的话则会默认添加一个eval(true)代表一个为true的表达式
    6. then,当when下面的表达式为true是then下方的代码才会执行,在这里可以直接编写Java代码(代码所需要的类通过import引入),当然也可以使用when模块定义的一些变量
    7. end 代表规则hello,word的结束。

    2.Java调用

    现在我们的规则文件写好以后就可以在Java中来进行调用了。

    1. 新建一个测试类DroolsApplicationHelloWordTests

    1
    2
    3
    4
    5
    6
    7
    8
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class DroolsApplicationHelloWordTests {

    @Autowired
    KieSession kieSession;

    }

    上方注入的kieSession对象就是以后与Drools打交道最常用的一个对象了,通过它可以直接操作在配置类kieFileSystem方法中加载的所有的规则文件

    2. 编写测试代码

    1
    2
    3
    4
    @Test
    public void testHelloWord() {
    kieSession.fireAllRules();
    }

    kieSession.fireAllRules方法是执行所有的规则,在运行了这个测试方法之后我们应该就可以看到控制台打印的一句hello,word!了

    基础学习

    1. 向规则文件传参

    1. 在entity包下新增一个User的实体类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class User {
    private String name;
    private int age;

    public User(String name, int age) {
    this.name = name;
    this.age = age;
    }
    //省略getter,setter
    }

    2. 在hello,word规则下方再次新建一个规则user

    1
    2
    3
    4
    5
    6
    7
    rule "user"
    when
    $u:User(name=="张三",age==18)
    then
    $u.setName("李四");
    System.err.println("hello,word:"+$u.getName());
    end

    $u:User(name==“张三”,age==18)的意思就是当存在一个user对象,并且它的name属性等于张三age等于18时就把这个对象赋值给$u。

    在下方的then模块,如果上方的条件成立时就把$u的name属性更新一下,然后打印。

    3. 编写测试代码

    1
    2
    3
    4
    5
    6
    7
    @Test
    public void testUser() {
    User user=new User("张三",18);
    kieSession.insert(user);
    kieSession.fireAllRules();
    System.err.println("规则执行完毕后张三变为了:"+user.getName());
    }

    我们可以使用kieSession.insert方法向规则文件中传参,然后在调用方法后你会发现在规则文件中更改的值在Java代码中也被更改了。

    4. 存在的小问题

    可能你会发现上方代码执行的时候连那句helloword也打印了,为什么呢,这是因为HelloWord那条规则没有验证条件再加上kieSession.fireAllRules()本来就是执行所有被加载的规则的。那么避免这种情况的办法就是执定本次执行的规则

    1
    2
    3
    4
    5
    6
    @Test
    public void testOneRule() {
    User user=new User("张三",18);
    kieSession.insert(user);
    kieSession.fireAllRules(new RuleNameEndsWithAgendaFilter("user"));
    }

    上方的user就是指定的本次执行的规则名称了。

    5.扩展操作

    上方我们通过RuleNameEndsWithAgendaFilter对象成功指定了需要执行的规则文件,其实通过查看此对象的源码我们发现这个对象是AgendaFilter的一个实现类,决定执不执行一个规则的条件是accept方法返回的boolean值决定的。
    所以说如果我们希望可以一次批量匹配多个规则的话可以通过继承AgendaFilter重写accept方法哦

    2. 常用运算符

    1. 连接符

    Drools中存在的三种连接符,上方的代码中我们已经使用过一个了,那就$u:User(name==“张三”,age==18)中的逗号,这里的逗号其实就是and的意思。另外的两个运算符就是&&和||,相信它们两个的意思不用我来介绍了吧。

    不过有一点需要注意的是&&和|| 和逗号,不能同时出现。要不你选择用&&和||要不就只用逗号, 。

    2. 类型比较操作符

    1.首先就是<,>,==,!=,>=,<=这六个

    它们是配合eval使用的,比如上方我们使用的eval(true)就是直接返回的true。当我们比较常量时可以使用eval(u.age>b.age)

    2. contains not contains

    contains用于判断对象的某个字段是否包含另外一个对象

    1
    2
    3
    4
    5
    6
    7
    rule "contains"
    when
    $s:String()
    $u:User(name contains $s)
    then
    System.err.println("用户张三存在");
    end
    1
    2
    3
    4
    5
    6
    7
    8
    @Test
    public void testContains() {
    String name="张三";
    User user=new User("张三",18);
    kieSession.insert(name);
    kieSession.insert(user);
    kieSession.fireAllRules(new RuleNameEndsWithAgendaFilter("contains"));
    }

    not contains顾明思议就是不包含

    3. memberOf not memberOf

    memberOf用于判断对象的某个字段是否存在一个集合中

    1
    2
    3
    4
    5
    6
    7
    rule "memberOf"
    when
    $list:List()
    $u:User(name memberOf $list)
    then
    System.err.println("用户李四存在");
    end
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Test
    public void testMemberOf() {
    List list=new ArrayList();
    list.add("张三");
    list.add("李四");
    User user=new User("李四",18);
    kieSession.insert(list);
    kieSession.insert(user);
    kieSession.fireAllRules(new RuleNameEndsWithAgendaFilter("memberOf"));
    }

    not memberOf顾明思议就是不存在

    3. matches not matches

    matches就是用于匹配正则表达式的了

    1
    2
    3
    4
    5
    6
    rule "matches"
    when
    $u:User(name matches "张.*")
    then
    System.err.println("用户张xx存在");
    end
    1
    2
    3
    4
    5
    6
    @Test
    public void testMatches() {
    User user=new User("张三",18);
    kieSession.insert(user);
    kieSession.fireAllRules(new RuleNameEndsWithAgendaFilter("matches"));
    }

    not matches不用我说了吧

    本文所有源码:https://github.com/shiyujun/drools

    本文出自http://zhixiang.org.cn/,转载请保留

  • 相关阅读:
    指针数组/数组指针
    hdu 5053 the Sum of Cube(上海网络赛)
    Archlinux YouCompleteMe+syntastic vim自己主动补全插件,显示缩进和状态栏美化,爽心悦目的vim
    sgu139Help Needed!推断15数码是否有解,以及推断N数码是否有解的推论
    hdu 4932 Miaomiao&#39;s Geometry(暴力)
    Theano学习笔记(一)——代数
    Tomcat全攻略
    send,recv,sendto,recvfrom
    git合并远端分支到本地分支的两种方式
    php实现记忆化递归--以斐波那契数列为例(还是以边学边做为主,注重练习)
  • 原文地址:https://www.cnblogs.com/zhixiang-org-cn/p/10106551.html
Copyright © 2020-2023  润新知