Drools语法详解

本文仅包含Drools的语法介绍, 不涉及如何使用,规则引擎介绍,算法介绍等方面.



语法全貌概览

规则文件一般都是.drl文件, 也可以是xml文件. 我们默认都是用.drl文件. 一个规则文件大致会有这样的结构:

package   /* 包名, 必须, 逻辑上的管理, 不对应物理位置 */
import    /* 导入类或方法, 与java中的import类似 */
global    /* 全局变量 */
function  /* 定义函数 */
query     /* 查询 */
rule      /* 规则, 可以由多个; 这是规则文件的主要部分 */

来个具体的规则文件的例子:

package com.test.drools;

function void showName(String name) {
    System.out.println("我是" + name);
}

rule "rule1"
    when
        eval(true)
    then
        System.out.println("hello drools");
        showName("test");
end

package

package有以下几点

  • package是必须的, 且必须放在规则文件第一行;
  • package的名字是随意的, 不必对应物理路径;
  • javapackage的概念不同,这里只是逻辑上的一种区分,同样的package下定义的functionquery等可以直接使用。

import

importjava中类似, 可以导入类, 也可以直接导入静态方法

global

定义全局变量,通常用于返回数据和提供服务; 全局变量与fact不通,引擎不能知道全局变量的改变,必须在插入fact之前,设置global变量

functon

定义函数, 为了提高代码复用, 使用java语法书写


rule

定义一个规则, 格式大致为:

rule "规则名"
    <属性><>
    when
        条件 (也叫 Left Hand Side, 简称 LHS)
    then
        结果 (也叫 Right Hand Side, 简称 RHS)
end

主要包含三部分:

  • 属性部分: 定义当前规则执行的一些属性等,比如是否可被重复执行、过期时间、生效时间等
  • 条件部分: 即LHS, 定义当前规则的条件; 如 when Message(); 判断当前workingMemory中是否存在Message对象
  • 结果部分: 即RHS, 即当前规则条件满足后执行的操作,可以直接调用Fact对象的方法来操作应用,可写java代码

规则属性

属性有这些内容: activation-group, agenda-group, auto-focus, date-effective, date-expires, dialect, duration, duration-value, enabled, lock-on-active, no-loop, ruleflow-group, salience

下面挨个解释:

  • salience: 优先级, 属性值是一个数字, 数值越大越先执行, 可以是负数, 默认为0. 这个可以控制规则的执行顺序
  • date-effective: 设置规则的生效时间, 当前系统时间>=date-effective时才会触发执行, 值是一个日期格式的字符串, 推荐用法是手动在java代码中设置当前系统的时间格式, 然后按照格式指定时间. 比如: date-expires "2016-01-31 23:59:59"
  • date-expires: 设置规则的过期时间, 跟上面正好相反.
  • enabled: 表示该规则是否可用, 值为布尔类型, 默认是true, 设置成false则该规则就不会被执行了
  • dialect: 设置语言类型, 值为字符串, 一般有两种语言,mveljava, 默认为java
  • duration: 规则定时, 值为长整型, 单位为毫秒, 如 duration 3000, 表示规则在3秒后执行(另外的线程中执行)
  • no-loop: 是否允许规则多次执行, 值为布尔类型, 默认是false, 即当前的规则只要满足条件, 可以无限次执行; 对当前传入workingMemory中的Fact对象进行修改或者个数的增减时, 就会触发规则重新匹配执行; 设置属性no-loop true, 表示当前规则只执行一次, 即使RHS中更新了当前Fact对象也不会再次执行该规则了. 不过当其他规则里更新了Fact对象时, 即使有no-loop true也会触发, 即no-loop true仅表示本规的RHS中有更新时不重复执行.
  • lock-on-active: 是no-loop的增强版, 与其他属性配合使用;规则的重复执行不一定是本身触发的, 也可能是其他规则触发的, 当在规则上使用ruleflow-group属性或agenda-group属性时, 将lock-on-active属性值设置为true,可避免因某些Fact对象被修改而使已经执行过的规则再次被激活执行.
  • activation-group: 作用是将规则分组, 值为字符串表示组名,这样在执行的时候,具有相同activation-group属性的规则中只要有一个会被执行,其它的规则都将不再执行。即在具有相同activation-group属性的规则当中,只有一个规则会被执行,其它规则都将不会被执行.相同activation-group属性的规则中哪一个会先执行,则可以用salience之类的属性来实现
  • agenda-group: 将规则分成若干个Agenda Group, 默认情况下, 引擎在调用这些设置了agenda-group属性的规则时需要显示的指定某个Agenda Group得到Focus(焦点),这样位于该Agenda Group中的规则才会触发执行,否则将不执行

  • ruleflow-group: 使用规则流的时候会用到该属性, 作用是将规则分组,然后在规则流当中通过使用ruleflow-group属性的值,从而使用对应的规则

when

条件部分(Conditions/LHS)用于匹配条件, 也叫匹配模式(Pattern)

条件可以是单个, 也可以有多个, 下面是一些例子

when
    eval(true)            // 是一个默认的api, 类似于 while(true)
    Person()              // 当前的 workingMemory 中存在 Pserson 类型的 Fact 对象
    $person:Person()      // 同上, $person 是给对象起的名字
    $bob:Person(name == "bob")  // 字段绑定, 存在 Person 类型且属性 name 值为bob的对象
    Person($name:name == "bob") // 与上面类似, 只是把名字放到了 $name 变量里
    Person(name == $name) // 与上面类似, 只是把名字放到了 $name 变量里
    $tom:Person(name == "tom" || name == "Tom") // 条件组合
then
    ...  // 上面起的变量这里可以直接使用

注意:

  • 上例中的$person, $bob等代表着符合条件的变量的引用, 在后面的条件部分和RHS部分中可直接使用
  • 条件可以有组合, 如Person(age == 18 && (name == "tom" || name == "Tom")), 若条件全是&&关系, 可以使用,代替, 但两者不能混用.
  • Fact对象(即输入的数据,类似于java bean)的private属性, 在LHS中必须用.引用, 如($person.name == "tom"), 而RHS中必须使用 gettersetter 方法

另外drools提供了十二种比较操作符, 有:>, >=, <, <=, ==, !=, contains, not contains, memberOf, not memberOf, matches, not matches

  • contains: 是否包含, 被比较对象可以是一个复杂对象也可以是一个简单的值
  • memberOf: 是否在某个集合中, 与contains不同的是他被比较的对象是一个集合, 而contains被比较的对象是单个值或者对象
  • matches: 正则表达式匹配

then

RHS, 这部分是普通的java代码, 记得加;.
另外drools提供了几个方法:

  • insert: 往当前workingMemory中插入一个新的Fact对象, 会触发规则的再次执行,除非使用no-loop限定
  • update: 更新
  • modify: 修改, 与update语法不同, 效果一样, 结果都是更新操作
  • retract: 删除