14.8. DRL (WHEN)中的规则条件
DRL 规则的 when 部分(也称为规则的 Left Hand Side (LHS) )包含执行操作必须满足的条件。条件由一系列声明 模式和限制 组成,根据软件包中的可用数据对象,带有可选 绑定 和支持的规则条件元素(关键字)。例如,如果某个公司需要 loan applicants 的时间超过 21 年,那么 "Underage" 规则的 when 条件将是 Applicant (age < 21)。
DRL 使用 when 而不是 ,因为是其他执行流的一部分,该流通常会在特定时间点上检查条件。相反,if 当 表示条件评估不仅限于特定的评估序列或时间点,而是随时发生。每当满足条件时,都会执行操作。
如果 when 部分为空,则条件被视为 true,并且首先在决策引擎中执行 fireAllRules () 调用时,将执行 部分中的操作。如果要使用规则设置决策引擎状态,这非常有用。
以下示例规则使用空条件在每次执行规则时插入事实:
没有条件的规则示例
rule "Always insert applicant"
when
// Empty
then // Actions to be executed once
insert( new Applicant() );
end
// The rule is internally rewritten in the following way:
rule "Always insert applicant"
when
eval( true )
then
insert( new Applicant() );
end
如果规则条件使用多个模式,且没有定义的关键字(如 和、或 ),则默认组合是 和:
没有关键字组合的规则示例
rule "Underage"
when
application : LoanApplication()
Applicant( age < 21 )
then
// Actions
end
// The rule is internally rewritten in the following way:
rule "Underage"
when
application : LoanApplication()
and Applicant( age < 21 )
then
// Actions
end
14.8.1. 模式和约束
DRL 规则条件中的 模式是 决策引擎要匹配的分段。模式可能与插入到决策引擎工作内存的每个事实匹配。模式也可以包含 约束,以进一步定义要匹配的事实。
在最简单的形式中,没有限制,模式与给定类型的事实匹配。在以下示例中,type 是 Person,因此模式将与决策引擎工作内存中的所有 Person 对象匹配:
单个事实类型的模式示例
Person()
这个类型不需要是一些事实对象的实际类。模式可以引用超级类甚至接口,可能与许多不同类的事实匹配。例如,以下模式与决策引擎工作内存中的所有对象匹配:
所有对象的模式示例
Object() // Matches all objects in the working memory
组成约束的特征的括号,如个人年龄的以下约束:
带有约束的模式示例
Person( age == 50 )
约束 是返回 true 或 false 的表达式。DRL 中的模式限制基本上是带有一些改进的 Java 表达式,如属性访问,以及一些区别,如 == 和 != 的 equals () 和 !equals () 语义(而不是常见的语义)。
任何 192.168.1.0/24 属性都可以直接从模式限制访问。bean 属性在内部使用没有参数且返回一些标准站 getter 来公开。例如,age 属性写为 DRL 中的 年龄,而不是 getter getAge () :
带有 sVirt 属性的 DRL 约束语法
Person( age == 50 ) // This is the same as the following getter format: Person( getAge() == 50 )
Red Hat Process Automation Manager 使用标准 JDK Introspector 类来实现此映射,因此它遵循标准站规格。为获得最佳决策引擎性能,请使用属性访问格式,如 年龄,而不是明确使用 getters,如 getAge ()。
不要使用属性访问器来更改对象的状态,这可能会影响规则,因为决策引擎会缓存调用之间匹配的结果,以便提高效率。
例如,不要使用以下方法使用属性访问器:
public int getAge() {
age++; // Do not do this.
return age;
}public int getAge() {
Date now = DateUtil.now(); // Do not do this.
return DateUtil.differenceInYears(now, birthday);
}
遵循第二个示例,插入一个事实,它将当前日期嵌套在工作内存中,并根据需要更新 fireAllRules () 之间的事实。
但是,如果无法找到属性的 getter,编译器将使用属性名称作为回退方法名称,且没有参数:
如果没有找到对象,回退方法
Person( age == 50 ) // If `Person.getAge()` does not exist, the compiler uses the following syntax: Person( age() == 50 )
您还可以以模式嵌套访问属性,如下例所示。嵌套属性由决策引擎索引。
带有嵌套属性访问的模式示例
Person( address.houseNumber == 50 ) // This is the same as the following format: Person( getAddress().getHouseNumber() == 50 )
在有状态 KIE 会话中,请小心使用嵌套的访问器,因为决策引擎的工作内存不知道任何嵌套的值,且不会检测何时更改。考虑不可变的值,而其任何父引用都会插入到工作内存中,或者,如果要修改嵌套值,请将所有外部事实标记为更新。在上例中,当 houseNumber 属性有变化时,所有具有该地址的 Person 必须标记为更新。
您可以使用任何返回 布尔值 的 Java 表达式作为模式括号内的约束。Java 表达式可以与其他表达式增强混合,如属性访问:
带有使用属性访问和 Java 表达式的约束的模式示例
Person( age == 50 )
您可以使用括号更改评估优先级,如在任何逻辑或数学表达式中一样:
约束评估顺序示例
Person( age > 100 && ( age % 10 == 0 ) )
您还可以在约束中重复使用 Java 方法,如下例所示:
使用可重复使用的 Java 方法的限制示例
Person( Math.round( weight / ( height * height ) ) < 25.0 )
不要使用限制来更改对象的状态,这可能会影响规则,因为决策引擎会缓存调用之间匹配的结果,以提高效率。在规则条件中对事实执行的任何方法都必须是只读的方法。此外,事实的状态不应在规则调用之间更改,除非这些事实在每次更改时在工作内存中被标记为更新。
例如,不要使用以下方法使用模式约束:
Person( incrementAndGetAge() == 10 ) // Do not do this.
Person( System.currentTimeMillis() % 1000 == 0 ) // Do not do this.
标准 Java 操作器优先级适用于 DRL 中的约束运算符,DRL 运算符遵循标准的 Java 语义,但 == 和 != 运算符除外。
== 运算符使用 null-safe equals () 语义,而不是常见的语义。例如,模式 Person (firstName == "John") 与 java.util.Objects.equals (person.getFirstName (), "John"), 和 "John" 不为空,其模式也类似于 "John".equals (person.getFirstName ())。
!= 运算符使用 null-safe !equals () 语义,而不是常见的语义。例如,模式 Person (firstName != "John") 与 !java.util.Objects.equals (person.getFirstName (), "John") 类似。
如果约束的字段和约束值是不同的类型,则决策引擎将使用类型 coercion 来解决冲突并减少编译错误。例如,如果 "ten" 作为数字评估器中的字符串提供,则会出现编译错误,而 "10" 则合并到数字 10 中。在 coercion 中,字段类型总是优先于值类型:
带有 coerced 值的约束示例
Person( age == "10" ) // "10" is coerced to 10
对于限制组,您可以使用逗号限制 , 使用隐式 和连接 语义:
具有多个约束的模式示例
// Person is at least 50 years old and weighs at least 80 kilograms: Person( age > 50, weight > 80 ) // Person is at least 50 years old, weighs at least 80 kilograms, and is taller than 2 meters: Person( age > 50, weight > 80, height > 2 )
虽然 && 和,但运算符具有相同的语义,但它们可以通过不同的优先级来解决。 && 运算符在 || 操作器前,以及 && 和 || 运算符都放在 , 运算符 前。在顶级约束中使用逗号运算符来优化决策引擎性能和人类可读性。
您不能将逗号运算符嵌入到复合约束表达式中,如括号中:
复合约束表达式中错误使用的逗号示例
// Do not use the following format: Person( ( age > 50, weight > 80 ) || height > 2 ) // Use the following format instead: Person( ( age > 50 && weight > 80 ) || height > 2 )
14.8.2. 在模式和限制中绑定变量
您可以将变量绑定到模式和约束,以引用规则其他部分中的匹配对象。通过您在数据模型中注解事实的方式,绑定变量可帮助您更有效地定义规则或更加一致。要在规则中的变量和字段之间更容易区分,请为变量使用标准格式 $variable,特别是在复杂的规则中。此惯例很有用,但在 DRL 中不需要。
例如,以下 DRL 规则将变量 $p 用于带有 Person 事实的模式:
带有绑定变量的模式
rule "simple rule"
when
$p : Person()
then
System.out.println( "Person " + $p );
end
同样,您还可以将变量绑定到模式约束中的属性,如下例所示:
// Two persons of the same age: Person( $firstAge : age ) // Binding Person( age == $firstAge ) // Constraint expression
确保为更清晰、更有效的规则定义分隔约束绑定和约束表达式。虽然支持混合绑定和表达式,但它们可能会复杂模式并影响评估效率。
// Do not use the following format: Person( $age : age * 2 < 100 ) // Use the following format instead: Person( age * 2 < 100, $age : age )
决策引擎不支持绑定到同一声明,但支持多个属性的 取消 参数。虽然位置参数始终使用 unification 处理,但命名参数存在联合符号 :=。
以下示例模式在两个 Person 事实之间统一 age 属性:
带有未配置的模式示例
Person( $age := age ) Person( $age := age )
取消声明第一次发生的绑定,并限制为绑定字段的同一值,以进行序列发生。
14.8.3. 嵌套约束和内联多播
在某些情况下,您可能需要访问嵌套对象的多个属性,如下例所示:
访问多个属性的模式示例
Person( name == "mark", address.city == "london", address.country == "uk" )
您可以将这些属性访问器分组到使用语法 . (<constraints>) 嵌套的对象,以便更易读的规则,如下例所示:
带有分组限制的模式示例
Person( name == "mark", address.( city == "london", country == "uk") )
period 前缀 . 将嵌套对象约束与方法调用区分开。
当您以模式处理嵌套对象时,您可以使用语法 < type>114<subtype > 广播到子类型,并使父类型中的 getters 可供子类型使用。您可以使用对象名称或完全限定类名称,您可以转换为一个或多个子类型,如下例所示:
将内联转换为子类型的模式示例
// Inline casting with subtype name: Person( name == "mark", address#LongAddress.country == "uk" ) // Inline casting with fully qualified class name: Person( name == "mark", address#org.domain.LongAddress.country == "uk" ) // Multiple inline casts: Person( name == "mark", address#LongAddress.country#DetailedCountry.population > 10000000 )
这些示例模式 cast Address 到 LongAddress,以及上一次示例中的 Detailsed Country,在每个示例中,父 getters 可供子类型使用。
您可以使用 instanceof 运算符来推断在后续使用带有模式的指定类型的结果,如下例所示:
Person( name == "mark", address instanceof LongAddress, address.country == "uk" )
如果无法进行内联多播(例如,如果 instanceof 返回 false),则评估被视为 false。
14.8.4. 约束中的日期字面
默认情况下,决策引擎支持日期格式 dd-mmm-yyyy。您可以通过提供系统属性 drools.dateformat="dd-mmm-yyyy hh:mm" 的其它格式掩码来自定义日期格式,包括时间格式掩码。您还可以使用 drools.defaultlanguage 和 drools.defaultcountry 系统属性更改语言区域设置来自定义日期格式(例如,Thailand 的区域设置被设置为 drools.defaultlanguage=th 和 drools.defaultcountry=TH)。
带有日期字面限制的模式示例
Person( bornBefore < "27-Oct-2009" )
14.8.5. DRL 模式约束支持的 Operator
DRL 在模式约束中支持 Operator 的标准 Java 语义,但有一些例外和一些额外的运算符在 DRL 中是唯一的。以下列表总结了 DRL 约束中不同于标准 Java 语义或 DRL 约束中唯一的 Operator。
.(),#使用
. ()运算符将属性 accessors 分组到嵌套对象,并使用 guestfish 运算符,将子类型转换为嵌套对象中的子类型。遍历子类型使来自父类型的 getters 可供子类型使用。您可以使用对象名称或完全限定类名称,您可以转换为一个或多个子类型。带有嵌套对象的模式示例
// Ungrouped property accessors: Person( name == "mark", address.city == "london", address.country == "uk" ) // Grouped property accessors: Person( name == "mark", address.( city == "london", country == "uk") )
注意period 前缀
.将嵌套对象约束与方法调用区分开。将内联转换为子类型的模式示例
// Inline casting with subtype name: Person( name == "mark", address#LongAddress.country == "uk" ) // Inline casting with fully qualified class name: Person( name == "mark", address#org.domain.LongAddress.country == "uk" ) // Multiple inline casts: Person( name == "mark", address#LongAddress.country#DetailedCountry.population > 10000000 )
!.使用此操作器以 null-safe 的方式解引用属性。
! 左侧的值。运算符不能为空(解析为!= null),才能为模式匹配提供正结果。带有 null-safe 解引用的限制示例
Person( $streetName : address!.street ) // This is internally rewritten in the following way: Person( address != null, $streetName : address.street )
[]使用此操作器根据 index 或键的
Map值访问List值。带有
List和Map访问权限的约束示例// The following format is the same as `childList(0).getAge() == 18`: Person(childList[0].age == 18) // The following format is the same as `credentialMap.get("jdoe").isValid()`: Person(credentialMap["jdoe"].valid)<,<=,>,>=在具有自然排序的属性中使用这些运算符。例如,对于
Date字段,<运算符在 之前 表示,对于String字段,运算符在 之前按字母顺序 表示。这些属性仅适用于相似的属性。operator
之前的限制示例Person( birthDate < $otherBirthDate ) Person( firstName < $otherFirstName )
==,!=在约束中将这些运算符用作
equals ()和!equals ()方法,而不是常见的相同语义。带有 null-safe 相等的约束示例
Person( firstName == "John" ) // This is similar to the following formats: java.util.Objects.equals(person.getFirstName(), "John") "John".equals(person.getFirstName())
带有 null-safe 不匹配的限制示例
Person( firstName != "John" ) // This is similar to the following format: !java.util.Objects.equals(person.getFirstName(), "John")
&&,||使用这些运算符创建缩写组合关系条件,该条件对字段添加多个限制。您可以使用括号
()对限制进行分组,以创建递归语法模式。带有缩写组合关系的限制示例
// Simple abbreviated combined relation condition using a single `&&`: Person(age > 30 && < 40) // Complex abbreviated combined relation using groupings: Person(age ((> 30 && < 40) || (> 20 && < 25))) // Mixing abbreviated combined relation with constraint connectives: Person(age > 30 && < 40 || location == "london")
匹配,不匹配使用这些运算符来指示字段匹配或不匹配指定的 Java 正则表达式。通常,正则表达式是一个字符串字面,但解析为有效正则表达式的变量也支持。
这些操作器仅适用于String属性。如果您使用与null值匹配的,则生成的评估始终为false。如果您使用与null值不匹配,则生成的评估始终为true。与 Java 一样,您写为字符串字面的正则表达式必须使用双反斜杠\\来转义。要匹配或不匹配正则表达式的约束示例
Person( country matches "(USA)?\\S*UK" ) Person( country not matches "(USA)?\\S*UK" )
包含,不包含使用这些运算符来验证是
Array还是集合包含或不包含指定的值的字段。这些运算符适用于Array或Collection属性,但您也可以使用这些运算符代替String.contains ()和!String.contains ()约束检查。集合的限制示例包含且不包含// Collection with a specified field: FamilyTree( countries contains "UK" ) FamilyTree( countries not contains "UK" ) // Collection with a variable: FamilyTree( countries contains $var ) FamilyTree( countries not contains $var )
String 字面的限制示例包含且不包含// Sting literal with a specified field: Person( fullName contains "Jr" ) Person( fullName not contains "Jr" ) // String literal with a variable: Person( fullName contains $var ) Person( fullName not contains $var )
注意为向后兼容,
excludes运算符是不受支持的 synonym,不包含。memberOf,not memberOf使用这些运算符来验证字段是否为一个数组的成员,还是定义为变量的集合的成员。
Array或Collection必须是变量。带有
memberOf而不是 memberOf的限制示例FamilyTree( person memberOf $europeanDescendants ) FamilyTree( person not memberOf $europeanDescendants )
soundslike使用此运算符验证词语是否具有几乎相同的声音,使用英语探测与给定值(与 match 运算符类似)。
此 operator 使用 Soundex 算法。带有
类似声音的约束示例// Match firstName "Jon" or "John": Person( firstName soundslike "John" )
str使用此运算符验证
字符串是否以或以指定的值开头或结尾的字段。您还可以使用此操作器验证String的长度。带有
str的约束示例// Verify what the String starts with: Message( routingValue str[startsWith] "R1" ) // Verify what the String ends with: Message( routingValue str[endsWith] "R2" ) // Verify the length of the String: Message( routingValue str[length] 17 )
- 在 中,
notin 使用这些运算符指定多个可能的值来匹配约束(复合值限制)。只有
in和不支持在 operator 中支持复合值限制的功能。这些运算符的第二个操作对象必须是以逗号分隔的值列表,用括号括起。您可以将值作为变量、字面、返回值或合格的标识符提供。这些运算符内部使用操作符==或!=作为多个限制的列表。带有
in和notin的限制示例Person( $color : favoriteColor ) Color( type in ( "red", "blue", $color ) ) Person( $color : favoriteColor ) Color( type notin ( "red", "blue", $color ) )
14.8.6. DRL 模式约束中的 Operator 优先级
DRL 支持适用约束运算符的标准 Java 操作器优先级,但有一些例外和一些额外的运算符在 DRL 中是唯一的。下表在适用的情况下列出了 DRL operator 优先级,从最高到最低的优先级:
表 14.2. DRL 模式约束中的 Operator 优先级
| Operator 类型 | Operator | 备注 |
|---|---|---|
| 嵌套或空安全属性访问 |
| 不支持标准 Java 语义 |
|
|
| 不支持标准 Java 语义 |
| 约束绑定 |
| 不支持标准 Java 语义 |
| multiplicative |
| |
| additive |
| |
| 移动 |
| |
| 关系 |
| |
| ç›¸ç‰ |
|
使用 |
|
非短路 |
| |
|
非短路 exclusive |
| |
|
非短路包含 |
| |
|
logical |
| |
|
logical |
| |
| ternary |
| |
|
以逗号分隔的 |
| 不支持标准 Java 语义 |
14.8.7. DRL 中支持的规则条件元素(关键字)
DRL 支持以下规则条件元素(关键字),您可以与您在 DRL 规则条件中定义的模式一起使用:
å’Œ使用它来将条件组件分组到逻辑组合中。在fix
和prefix 中被支持,并被支持。您可以使用括号()显式分组模式。默认情况下,所有列出的模式都会与 合并,如果没有指定。带有
and的模式示例//Infix `and`: Color( colorType : type ) and Person( favoriteColor == colorType ) //Infix `and` with grouping: (Color( colorType : type ) and (Person( favoriteColor == colorType ) or Person( favoriteColor == colorType )) // Prefix `and`: (and Color( colorType : type ) Person( favoriteColor == colorType )) // Default implicit `and`: Color( colorType : type ) Person( favoriteColor == colorType )
注意不要使用带有 and 关键字的前导
声明绑定(例如,您可以使用或)。声明一次只能引用单个事实,如果您使用声明绑定和,那么当和满足时,它将同时匹配事实,并导致错误。滥用
和的示例// Causes compile error: $person : (Person( name == "Romeo" ) and Person( name == "Juliet"))
或者使用此选项将条件组件分组到逻辑取消中。在fix 和
prefix中不被支持。您可以使用括号()显式分组模式。您还可以使用模式绑定或,但每个模式都必须单独绑定。带有
or的模式示例//Infix `or`: Color( colorType : type ) or Person( favoriteColor == colorType ) //Infix `or` with grouping: (Color( colorType : type ) or (Person( favoriteColor == colorType ) and Person( favoriteColor == colorType )) // Prefix `or`: (or Color( colorType : type ) Person( favoriteColor == colorType ))
带有
或模式绑定的模式示例pensioner : (Person( sex == "f", age > 60 ) or Person( sex == "m", age > 65 )) (or pensioner : Person( sex == "f", age > 60 ) pensioner : Person( sex == "m", age > 65 ))orcondition 元素的行为与 connective||运算符不同,用于字段限制和限制。决策引擎不会直接解释元素,而是使用逻辑转换来使用或作为多个子规则重写规则。此过程最终会生成具有单个or或根节点的规则,以及每个 condition 元素的一个子规则。每个子规则都像任何常规规则一样激活并执行,子规则之间没有特殊行为或交互。因此,当两个或者多个 disjunction 术语满足时,请考虑
orcondition 元素生成两个或多个类似规则的快捷方式。exists使用它来指定必须存在的事实和约束。这个选项仅针对第一个匹配项触发,而不在以后的匹配项上触发。如果您将此元素与多种模式一起使用,请将模式与括号
()括起来。存在模式示例exists Person( firstName == "John") exists (Person( firstName == "John", age == 42 )) exists (Person( firstName == "John" ) and Person( lastName == "Doe" ))not使用它来指定不能存在的事实和约束。如果您将此元素与多种模式一起使用,请将模式与括号
()括起来。没有的模式示例not Person( firstName == "John") not (Person( firstName == "John", age == 42 )) not (Person( firstName == "John" ) and Person( lastName == "Doe" ))forall使用此选项来验证与第一个模式匹配的所有事实是否与所有剩余的模式匹配。当满足
forall结构时,该规则将评估为true。此元素是一个范围分隔符,因此它可以使用任何之前绑定的变量,但其中没有变量绑定可在它之外使用。带有
forall的规则示例rule "All full-time employees have red ID badges" when forall( $emp : Employee( type == "fulltime" ) Employee( this == $emp, badgeColor = "red" ) ) then // True, all full-time employees have red ID badges. end在本例中,规则选择类型为
"fulltime"的所有Employee对象。对于与此模式匹配的每个事实,该规则会评估遵循的模式(从属颜色),如果匹配,该规则将评估为true。要说明决策引擎工作内存中给定类型的所有事实必须与一组限制匹配,您可以使用单一模式来方便使用。
带有
forall和单一模式的规则示例rule "All full-time employees have red ID badges" when forall( Employee( badgeColor = "red" ) ) then // True, all full-time employees have red ID badges. end您可以将
forall构造使用多个模式,或者嵌套它们与其他 condition 元素一起,例如在not元素构造中。带有
forall和多个模式的规则示例rule "All employees have health and dental care programs" when forall( $emp : Employee() HealthCare( employee == $emp ) DentalCare( employee == $emp ) ) then // True, all employees have health and dental care. end带有
forall而不是t 的规则示例rule "Not all employees have health and dental care" when not ( forall( $emp : Employee() HealthCare( employee == $emp ) DentalCare( employee == $emp ) ) ) then // True, not all employees have health and dental care. end注意all (p1 p2 p2 p3 …)的格式等同于not (p1 而不是(和 p2 p3 …)。from使用它来为模式指定数据源。这可让决策引擎超过工作内存中的数据。数据源可以是绑定变量上的子字段,也可以是方法调用的结果。用于定义对象源的表达式是遵循常规 MVEL 语法的任何表达式。因此,ca 元素可让您轻松使用对象属性导航、执行方法调用和访问映射和集合元素。
使用
from和 pattern 绑定的规则示例rule "Validate zipcode" when Person( $personAddress : address ) Address( zipcode == "23920W" ) from $personAddress then // Zip code is okay. end带有
from和图形表示法的规则示例rule "Validate zipcode" when $p : Person() $a : Address( zipcode == "23920W" ) from $p.address then // Zip code is okay. end迭代所有对象的规则示例
rule "Apply 10% discount to all items over US$ 100 in an order" when $order : Order() $item : OrderItem( value > 100 ) from $order.items then // Apply discount to `$item`. end注意对于大量对象集合,而不是添加带有决定引擎经常迭代的大型图形的对象,直接将集合添加到 KIE 会话中,然后在条件中加入集合,如下例所示:
when $order : Order() OrderItem( value > 100, order == $order )
带有
from和lock-on-active规则属性的规则示例rule "Assign people in North Carolina (NC) to sales region 1" ruleflow-group "test" lock-on-active true when $p : Person() $a : Address( state == "NC" ) from $p.address then modify ($p) {} // Assign the person to sales region 1. end rule "Apply a discount to people in the city of Raleigh" ruleflow-group "test" lock-on-active true when $p : Person() $a : Address( city == "Raleigh" ) from $p.address then modify ($p) {} // Apply discount to the person. end重要使用带有
lock-on-active规则属性的from可能会导致规则没有被执行。您可以使用以下方法之一解决这个问题:-
当您可以将所有事实插入到决策引擎的工作内存中时,避免使用
from元素,或者在约束表达式中使用嵌套对象引用。 -
将
modify ()块中使用的变量设置为规则条件中最后一个句子。 -
当您可以明确管理同一 ruleflow 组中的规则时,避免使用
lock-on-active规则属性。
包含
from子句的模式不能后跟以括号开头的另一个模式。这个限制的原因是 DRL 解析器从表达式读取",且无法将这个表达式与函数调用区分开。最简单的解决方法是将from$l (String ()或 Number ())"from子句嵌套在括号中,如下例所示:来自使用不正确且正确使用的规则示例// Do not use `from` in this way: rule R when $l : List() String() from $l (String() or Number()) then // Actions end // Use `from` in this way instead: rule R when $l : List() (String() from $l) (String() or Number()) then // Actions end-
当您可以将所有事实插入到决策引擎的工作内存中时,避免使用
entry-point使用它来定义入口点或 事件流,对应于模式的数据源。这个元素通常与
fromcondition 元素一起使用。您可以为事件声明入口点,以便决策引擎仅使用该入口点中的数据来评估规则。您可以通过在 DRL 规则中或明确在 Java 应用程序中引用入口点来隐式声明入口点。来自 entry-point的规则示例rule "Authorize withdrawal" when WithdrawRequest( $ai : accountId, $am : amount ) from entry-point "ATM Stream" CheckingAccount( accountId == $ai, balance > $am ) then // Authorize withdrawal. end带有 EntryPoint 对象的 Java 应用程序代码示例和插入的事实
import org.kie.api.runtime.KieSession; import org.kie.api.runtime.rule.EntryPoint; // Create your KIE base and KIE session as usual: KieSession session = ... // Create a reference to the entry point: EntryPoint atmStream = session.getEntryPoint("ATM Stream"); // Start inserting your facts into the entry point: atmStream.insert(aWithdrawRequest);collect使用它来定义规则可作为条件的一部分使用的对象集合。规则从指定源或决策引擎的工作内存获取集合。
collect元素的结果模式可以是实现java.util.Collection接口的任何聚合类,并提供默认的 no-arg 公共构造器。您可以使用 Java 集合,如List、LinkedList和HashSet,或者您自己的类。如果在条件中的collect元素之前绑定变量,您可以使用变量限制源和结果模式。但是,collect元素内所做的任何绑定都不可用,可在它之外使用。带有
collect的规则示例import java.util.List rule "Raise priority when system has more than three pending alarms" when $system : System() $alarms : List( size >= 3 ) from collect( Alarm( system == $system, status == 'pending' ) ) then // Raise priority because `$system` has three or more `$alarms` pending. end在本例中,该规则评估每个给定系统决策引擎工作内存中的所有待处理警报,并将它们分组到列表中。
如果为给定系统找到三个或更多警告,则执行该规则。您还可以使用与元素嵌套的
collect元素,如下例所示:从
中收集和嵌套的规则示例import java.util.LinkedList; rule "Send a message to all parents" when $town : Town( name == 'Paris' ) $mothers : LinkedList() from collect( Person( children > 0 ) from $town.getPeople() ) then // Send a message to all parents. end累积使用它来迭代对象集合,对每个元素执行自定义操作,并返回一个或多个结果对象(如果约束评估为
true)。这个元素是collectcondition 元素的更灵活且强大的形式。您可以在累积条件中使用预定义的功能,或根据需要实施自定义功能。您还可以在规则条件中使用缩写缩写cc 来累积。使用以下格式在规则中定义
累积条件:累积格式的首选格式accumulate( <source pattern>; <functions> [;<constraints>] )
注意虽然决策引擎支持
累积元素的替代格式来实现向后兼容,但对于规则和应用程序中获得最佳性能,这种格式是首选的。决策引擎支持以下预定义的
累积功能。这些功能接受任何表达式作为输入。-
平均 -
分钟 -
max -
数� -
sum -
collectList -
collectSet
在以下示例规则中,
min、max和average是在计算每个传感器的所有读取值的最小、最大值和平均温度值的功能:计算温度值的累积规则示例
rule "Raise alarm" when $s : Sensor() accumulate( Reading( sensor == $s, $temp : temperature ); $min : min( $temp ), $max : max( $temp ), $avg : average( $temp ); $min < 20, $avg > 70 ) then // Raise the alarm. end以下示例规则使用测量
的平均函数来按照顺序计算所有项目的平均原率:计算平均 profit 的规则示例
rule "Average profit" when $order : Order() accumulate( OrderItem( order == $order, $cost : cost, $price : price ); $avgProfit : average( 1 - $cost / $price ) ) then // Average profit for `$order` is `$avgProfit`. end要在
累积条件中使用自定义特定于域的功能,请创建一个 Java 类来实现org.kie.api.runtime.rule.AccumulateFunction接口。例如,以下 Java 类定义了AverageData函数的自定义实现:带有
平均功能的自定义实现的 Java 类示例// An implementation of an accumulator capable of calculating average values public class AverageAccumulateFunction implements org.kie.api.runtime.rule.AccumulateFunction<AverageAccumulateFunction.AverageData> { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { } public void writeExternal(ObjectOutput out) throws IOException { } public static class AverageData implements Externalizable { public int count = 0; public double total = 0; public AverageData() {} public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { count = in.readInt(); total = in.readDouble(); } public void writeExternal(ObjectOutput out) throws IOException { out.writeInt(count); out.writeDouble(total); } } /* (non-Javadoc) * @see org.kie.api.runtime.rule.AccumulateFunction#createContext() */ public AverageData createContext() { return new AverageData(); } /* (non-Javadoc) * @see org.kie.api.runtime.rule.AccumulateFunction#init(java.io.Serializable) */ public void init(AverageData context) { context.count = 0; context.total = 0; } /* (non-Javadoc) * @see org.kie.api.runtime.rule.AccumulateFunction#accumulate(java.io.Serializable, java.lang.Object) */ public void accumulate(AverageData context, Object value) { context.count++; context.total += ((Number) value).doubleValue(); } /* (non-Javadoc) * @see org.kie.api.runtime.rule.AccumulateFunction#reverse(java.io.Serializable, java.lang.Object) */ public void reverse(AverageData context, Object value) { context.count--; context.total -= ((Number) value).doubleValue(); } /* (non-Javadoc) * @see org.kie.api.runtime.rule.AccumulateFunction#getResult(java.io.Serializable) */ public Object getResult(AverageData context) { return new Double( context.count == 0 ? 0 : context.total / context.count ); } /* (non-Javadoc) * @see org.kie.api.runtime.rule.AccumulateFunction#supportsReverse() */ public boolean supportsReverse() { return true; } /* (non-Javadoc) * @see org.kie.api.runtime.rule.AccumulateFunction#getResultType() */ public Class< ? > getResultType() { return Number.class; } }要在 DRL 规则中使用自定义功能,请使用 import
累积语句导入函数:导入自定义功能的格式
import accumulate <class_name> <function_name>
带有导入
平均功能的规则示例import accumulate AverageAccumulateFunction.AverageData average rule "Average profit" when $order : Order() accumulate( OrderItem( order == $order, $cost : cost, $price : price ); $avgProfit : average( 1 - $cost / $price ) ) then // Average profit for `$order` is `$avgProfit`. end-
14.8.8. OOPath 语法以及 DRL 规则条件中的对象图形
OOPath 是 XPath 的面向对象的语法扩展,旨在浏览 DRL 规则条件限制中的对象图形。OOPath 使用 XPath 中的紧凑表示法来导航相关元素,同时处理集合和过滤约束,对对象图形特别有用。
当事实的字段是一个集合时,您可以使用 from condition 元素(关键字)与集合中的所有项目绑定和原因。如果您需要在规则条件约束中浏览对象图表,则对 from condition 元素的广泛使用会导致详细和重复的语法,如下例所示:
从中浏览对象图形的规则示例
rule "Find all grades for Big Data exam"
when
$student: Student( $plan: plan )
$exam: Exam( course == "Big Data" ) from $plan.exams
$grade: Grade() from $exam.grades
then
// Actions
end
在本例中,域模型包含一个带有正在研究的 Plan 的 Tailoring 对象。此计划 可以有零个或多个研究 实例,并会包括零个或多个 Grade 实例。在这种情况下,只有图形的根对象需要处于决策引擎的工作内存中,才能使此规则设置正常工作。
作为使用声明中广泛使用的更多替代方案,您可以使用缩写 OOPath 语法,如下例所示:
使用 OOPath 语法浏览对象图形的规则示例
rule "Find all grades for Big Data exam"
when
Student( $grade: /plan/exams[course == "Big Data"]/grades )
then
// Actions
end
通常,OOPath 表达式的核心 grammar 以扩展 Backus-Naur 格式(EBNF)标记定义:
OOPath 表达式的 EBNF 表示法
OOPExpr = [ID ( ":" | ":=" )] ( "/" | "?/" ) OOPSegment { ( "/" | "?/" | "." ) OOPSegment } ;
OOPSegment = ID ["#" ID] ["[" ( Number | Constraints ) "]"]
实际上,OOPath 表达式具有以下功能和功能:
-
以正斜杠
/或问问题标记开始,如果它是一个非主动 OOPath 表达式(本节后面介绍),则以正斜杠 / 或正斜杠?/开头。 -
可以使用句点
.操作符解引用对象的单个属性。 -
可以使用正斜杠
/运算符解引用对象的多个属性。如果返回集合,表达式会迭代集合中的值。 可以过滤掉不满足一个或多个限制的对象。约束在方括号之间写成 predicate 表达式,如下例所示:
将约束作为 predicate 表达式
Student( $grade: /plan/exams[ course == "Big Data" ]/grades )
可将遍历的对象缩减到通用集合中声明的类的子类。后续限制也可以安全地访问该子类中声明的属性,如下例所示。不是此内联 cast 中指定的类实例的对象会自动过滤掉。
带有下游对象的约束
Student( $grade: /plan/exams#AdvancedExam[ course == "Big Data", level > 3 ]/grades )
可以引用当前迭代图形前遍历的图形的对象。例如,以下 OOPath 表达式仅匹配通过测试的平均等级:
带有后引用对象的约束
Student( $grade: /plan/exams/grades[ result > ../averageResult ] )
可以是另一个 OOPath 表达式,如下例所示:
递归约束表达式
Student( $exam: /plan/exams[ /grades[ result > 20 ] ] )
可以通过其方括号
[]间的索引访问对象,如下例所示。要遵循 Java 规范,OOPath 索引基于 0,而 XPath 索引则基于 1。按索引访问对象的限制
Student( $grade: /plan/exams[0]/grades )
OOPath 表达式可以是 reactive 或 non-reactive。决策引擎不会响应涉及在评估 OOPath 表达式期间遍历的深度嵌套对象的更新。
要使这些对象重新主动更改,请修改对象来扩展类 org.drools.core.phreak.ReactiveObject。修改对象以扩展 ReactiveObject 类后,domain 对象调用继承的方法 notifyModification,以在更新其中一个字段时通知决策引擎,如下例所示:
通知决策引擎迁移到其他课程的对象方法示例
public void setCourse(String course) {
this.course = course;
notifyModification(this);
}
使用以下对应的 OOPath 表达式,当评估移到其他课程时,会重新执行该规则,并重新计算与该规则匹配的等级列表:
"Big Data" 规则中的 OOPath 表达式示例
Student( $grade: /plan/exams[ course == "Big Data" ]/grades )
您还可以使用 ?/ 分隔符而不是 / 分隔符来只对 OOPath 表达式的一个子端口禁用重新活动,如下例所示:
部分非主动的 OOPath 表达式示例
Student( $grade: /plan/exams[ course == "Big Data" ]?/grades )
通过本例,决策引擎会对评估所做的更改做出反应,或者如果为计划添加新的等级,则不会对计划进行了评估。
如果 OOPath 部分不是主动的,则 OOPath 表达式的所有剩余部分也会变为非活跃状态。例如,以下 OOPath 表达式完全非活跃:
完全非主动的 OOPath 表达式示例
Student( $grade: ?/plan/exams[ course == "Big Data" ]/grades )
因此,您不能在同一 OOPath 表达式中使用 ?/ 分隔符一次。例如,以下表达式会导致编译错误:
带有重复非活动标记的 OOPath 表达式示例
Student( $grade: /plan?/exams[ course == "Big Data" ]?/grades )
启用 OOPath 表达式的另一种方法是为 Red Hat Process Automation Manager 中的 List 和 Set 接口使用专用实现。这些实现是 ReactiveList 和 ReactiveSet 类。一个 ReactiveCollection 类也可用。该实施还支持通过 Iterator 和 ListIterator 类执行可变操作。
以下示例类使用这些类来配置 OOPath 表达式重新活动:
配置 OOPath 表达式的 Java 类示例
public class School extends AbstractReactiveObject {
private String name;
private final List<Child> children = new ReactiveList<Child>(); 1
public void setName(String name) {
this.name = name;
notifyModification(); 2
}
public void addChild(Child child) {
children.add(child); 3
// No need to call `notifyModification()` here
}
}