DRL(Drools规则语言)规则
DRL文件结构:
package
import
function // Optional
query // Optional
declare // Optional
global // Optional
rule "rule name"
// Attributes
when
// Conditions
then
// Actions
end
rule "rule2 name"
...
package
和java的package概念类似,唯一的命名空间。一个规则库可以包含很多的package,但通常将一个package下的所有规则放在一个文件中。
drools提倡package和文件的路径相同。
package必须在rule文件的第一行,但是其他的内容的顺序可以变化。
import
引入其他package的对象。
格式:packageName.objectName
function
可以在rule文件中定义函数。
在规则下的then之中调用function。
也可以import其他package的function。
实例:
function String hello(String applicantName) {
return "Hello " + applicantName + "!";
}
rule "Using a function"
when
// Empty
then
System.out.println( hello( "James" ) );
end
import function my.package.applicant.hello;
rule "Using a function"
when
// Empty
then
System.out.println( hello( "James" ) );
end
query
DRL文件中的Query在Drools引擎的工作内存中搜索与DRL文件中的规则相关的event。在DRL中定义Query,在java中调用query获得数据。
Query是全系统唯一的,必须保证在整个KIE中名称唯一。
实例:
DRL文件中的示例查询定义
query "people under the age of 21"
$person : Person( age < 21 )
end
获取查询结果的示例应用程序代码
QueryResults results = ksession.getQueryResults( "people under the age of 21" );
System.out.println( "we have " + results.size() + " people under the age of 21" );
查询结果的遍历方式:
QueryResults results = ksession.getQueryResults( "people under the age of 21" );
System.out.println( "we have " + results.size() + " people under the age of 21" );
System.out.println( "These people are under the age of 21:" );
for ( QueryResultsRow row : results ) {
Person person = ( Person ) row.get( "person" );
System.out.println( person.getName() + "\n" );
}
位置参数
类型声明中声明的类型顺序与参数位置匹配。
如下实例,Location(x, y;)代替Location( thing == x, location == y):
declare Location
thing : String
location : String
end
query isContainedIn( String x, String y )
Location(x, y;)
or
( Location(z, y;) and ?isContainedIn(x, z;) )
end
主意:这里的“ z”将始终是“输出”变量。’?’ 符号表示查询仅是拉式查询。
可以使用@position重新定义顺序。
declare Cheese
name : String @position(1)
shop : String @position(2)
price : int @position(0)
end
org.drools.definition.type包中的@Position 可用于java的原始pojo。
DRL中的类型声明和元数据
DRL文件中的规则使用的event类型是新定义的类型或元数据:
- 新的event model。默认为java.lang.Object.可以在drl中定义新的模型,不必在java中定义模型。
- 元数据。
没有元数据的类型声明
declare Person
name : String
dateOfBirth : java.util.Date
address : Address
end
rule "Using a declared type"
when
$p : Person( name == "James" )
then // Insert Mark, who is a customer of James.
Person mark = new Person();
mark.setName( "Mark" );
insert( mark );
end
每个属性的类型都可以是任何有效的Java类型,包括您创建的另一个类或先前声明的事实类型。为了避免在每次声明类时都写出全限定名,可以将全称定义为import子句的一部分:
import java.util.Date
declare Person
name : String
dateOfBirth : Date
address : Address
end
Drools引擎会在编译时生成declare的类型的Java类。上面的Person对应的java类为:
public class Person implements Serializable {
private String name;
private java.util.Date dateOfBirth;
private Address address;
// Empty constructor
public Person() {...}
// Constructor with all fields
public Person( String name, Date dateOfBirth, Address address ) {...}
// If keys are defined, constructor with keys
public Person( ...keys... ) {...}
// Getters and setters
// `equals` and `hashCode`
// `toString`
}
在规则文件中就可以直接使用Person类型了,如下:
rule "Using a declared type"
when
$p : Person( name == "James" )
then // Insert Mark, who is a customer of James.
Person mark = new Person();
mark.setName( "Mark" );
insert( mark );
end
DRL中的枚举类型声明
定义方式:
declare enum <factType>
declare enum DaysOfWeek
SUN("Sunday"),MON("Monday"),TUE("Tuesday"),WED("Wednesday"),THU("Thursday"),FRI("Friday"),SAT("Saturday");
fullName : String
end
rule "Using a declared Enum"
when
$emp : Employee( dayOff == DaysOfWeek.MONDAY )
then
...
end
DRL中的扩展类型声明
也就是java中的继承。
import org.people.Person
declare Person end
declare Student extends Person
school : String
end
declare LongTermStudent extends Student
years : int
course : String
end
DRL中带有元数据的类型声明
元数据可用于类型以及类型的属性。
import java.util.Date
declare Person
@author( Bob )
@dateOfCreation( 01-Feb-2009 )
name : String @key @maxLength( 30 )
dateOfBirth : Date
address : Address
end
可以用于import的数据类型或者declare的数据类型:
import org.drools.examples.Person
declare Person
@author( Bob )
@dateOfCreation( 01-Feb-2009 )
end
declare org.drools.examples.Person
@author( Bob )
@dateOfCreation( 01-Feb-2009 )
end
元数据标签列表:
- @role
CEP中,给定的事实类型是作为常规事实还是在Drools引擎中的事件处理。
默认参数: fact
支持的参数:fact,event
@role( fact | event )
declare VoiceCall
@role( event )
end
- @timestamp
每个event的时间戳
默认参数:Drools引擎会话时钟增加的时间
支持的参数:会话时钟时间或自定义时间戳属性
declare VoiceCall
@role( event )
@timestamp( callDateTime )
end
- @duration
事件可以是基于时间间隔的事件或时间点事件。基于时间间隔的事件具有持续时间,并持续存在于Drools引擎的工作存储器中,直到其持续时间过去。时间点事件没有持续时间,本质上是持续时间为零的基于间隔的事件。
declare VoiceCall
@role( event )
@timestamp( callDateTime )
@duration( callDuration )
end
- @expires
该标签确定事件在Drools引擎的工作内存中到期之前的持续时间。默认情况下,当事件不再匹配并激活任何当前规则时,事件就会过期。该标签定义还覆盖了根据KIE基础中的时间约束和滑动窗口计算出的隐式过期偏移。
declare VoiceCall
@role( event )
@timestamp( callDateTime )
@duration( callDuration )
@expires( 1h35m )
end
- @typesafe
- @serialVersionUID
- @key
此标记使事实类型属性可用作事实类型的键标识符。
生成的类可以实现equals()和hashCode()方法,以确定该类型的两个实例是否彼此相等。Drools引擎还可以使用所有关键属性作为参数来生成构造函数。
declare Person
firstName : String @key
lastName : String @key
age : int
end
对于此示例,Drools引擎检查firstName和lastName属性以确定两个的实例是否Person彼此相等,但不检查该age属性。Drools引擎还隐式生成了三个构造函数:一个没有参数,一个带有@key字段,一个带有所有字段的构造器:
Person() // Empty constructor
Person( String firstName, String lastName )
Person( String firstName, String lastName, int age )
- @position
此标记确定声明的事实类型属性或字段在位置参数中的位置,从而覆盖属性的默认声明顺序。您可以使用此标记来修改模式中的位置约束,同时在类型声明和位置参数中保持一致的格式。
declare Person
firstName : String @position( 1 )
lastName : String @position( 0 )
age : int @position( 2 )
occupation: String
end
在此示例中,按以下顺序在位置参数中对属性进行优先级排序:
1 lastName
2 firstName
3 age
4 occupation
在位置参数中,无需指定字段名称,因为位置映射到已知的命名字段。例如,参数Person( lastName == “Doe” )与相同Person( “Doe”😉,其中该lastName字段在DRL声明中具有最高位置注释。
在扩展类型声明中,定义@position注释时请格外小心,因为属性位置是在子类型中继承的。这种继承可能导致混合的属性顺序,在某些情况下可能会造成混淆。两个字段可以具有相同的@position值,并且不需要声明连续的值。如果重复某个位置,则使用继承(父类型中的位置值具有优先级),然后使用从第一个声明到最后一个声明的声明顺序来解决冲突。
declare Person
firstName : String @position( 1 )
lastName : String @position( 0 )
age : int @position( 2 )
occupation: String
end
declare Student extends Person
degree : String @position( 1 )
school : String @position( 0 )
graduationDate : Date
end
在此示例中,按以下顺序在位置参数中对属性进行优先级排序:
1 lastName (父类型中的位置0)
2 school (子类型中的位置0)
3 firstName (父类型中的位置1)
4 degree (子类型中的位置1)
5 age (父类型中的位置2)
6 occupation
7 graduationDate
DRL中的全局变量
全局变量的典型应用是为rule提供数据或服务。例如,rule中使用应用服务,rule返回数据等场景。可以在java应用中设置全局变量,在rule的then模块中使用。
在java中设置全局变量:
List<String> list = new ArrayList<>();
KieSession kieSession = kiebase.newKieSession();
kieSession.setGlobal( "myGlobalList", list );
在rule中使用:
global java.util.List myGlobalList;
rule "Using a global"
when
// Empty
then
myGlobalList.add( "My global list" );
end
注意:
- 不要在条件判断中使用全局变量,除非全局变量是不可变的。全局变量并没有插入工作内存,所以drools引擎不能跟踪变量的变化。
- 不要将全局变量用于规则之间的共享数据。规则只见共享数据需要将数据放到工作内存空间。
DRL中的rule属性
语法格式:
rule "rule_name"
// Attribute
// Attribute
when
// Conditions
then
// Actions
end
设置属性列表:
属性 | 描述 |
---|---|
salience | 定义规则优先级的整数。在激活队列中排序时,具有较高显着性值的规则将具有较高的优先级。例: salience 10 |
enabled | 布尔值。选择该选项后,将启用规则。如果未选择该选项,则该规则将被禁用。例: enabled true |
date-effective | 包含日期和时间定义的字符串。仅当当前日期和时间在date-effective属性之后时,才能激活该规则。例: date-effective “4-Sep-2018” |
date-expires | 包含日期和时间定义的字符串。如果当前日期和时间在date-expires属性之后,则无法激活该规则。例: date-expires “4-Oct-2018” |
no-loop | 布尔值。选择该选项后,如果规则的结果重新触发了先前满足的条件,则无法重新激活(循环)规则。如果未选择条件,则在这些情况下可以循环规则。例: no-loop true |
agenda-group | 一个字符串,用于标识您要向其分配规则的议程组。通过议程组,您可以对议程进行分区,以提供对规则组的更多执行控制。只有已获得焦点的议程组中的规则才能被激活。例: agenda-group “GroupName” |
activation-group | 一个字符串,用于标识您要向其分配规则的激活(或XOR)组。在激活组中,只能激活一个规则。触发的第一个规则将取消激活组中所有规则的所有未决激活。例: activation-group “GroupName” |
duration | 一个长整数值,定义了如果仍满足规则条件,则可以激活规则的持续时间(以毫秒为单位)。例: duration 10000 |
timer | 一个字符串,用于标识int(间隔)或cron计时器定义以调度规则。示例:(timer ( cron:* 0/15 * * * ? ) 每15分钟一次) |
calendar | 一个石英调度规则日历定义。示例:(calendars “* * 0-7,18-23 ? * *” 不包括非营业时间) |
auto-focus | 一个布尔值,仅适用于议程组中的规则。选择该选项后,下次激活该规则时,将自动为分配了该规则的议程组指定焦点。例: auto-focus true |
lock-on-active | 一个布尔值,仅适用于规则流组或议程组中的规则。选择该选项后,下一次该规则的规则流组变为活动状态或该规则的议程组获得焦点时,将无法再次激活该规则,直到规则流组不再处于活动状态或议程组失去焦点为止。这是该no-loop属性的更强版本,因为匹配匹配规则的激活将被忽略,而与更新的来源无关(不仅是规则本身)。此属性是计算规则的理想选择,在计算规则中,您有许多修改事实的规则,并且您不希望任何规则重新匹配并再次触发。例: lock-on-active true |
ruleflow-group | 标识规则流组的字符串。在规则流组中,只有在相关规则流激活了该组时,规则才能触发。例: ruleflow-group “GroupName” |
dialect | 字符串,用于标识规则中的代码表达式JAVA或MVEL将其用作语言。默认情况下,该规则使用在程序包级别指定的方言。此处指定的任何方言都会覆盖规则的打包方言设置。例: dialect “JAVA” |