搜索

16.8. DRL 中的规则条件(WHEN)

download PDF

DRL 规则的一部分(也称为 Left Hand Side(LHS) )包含要执行操作的条件。条件由一系列指定 模式和 约束 组成,具有可选的绑定和支持的规则条件元素(关键字),具体取决于软件包中的可用数据对象。例如,如果银行需要 loan applicants 已有 21 余年,那么 "Underage" 规则的 when 条件将是适用的 (年龄 < 21 )

注意

如果 DRL 通常是特定时间点的确定性执行流的一部分,则 DRL 而不是使用。 相反,如果 指示条件评估不受特定评估序列的限制,而是随时持续发生。每当满足条件时,都会执行相关的操作。

如果 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

16.8.1. 模式和限制

DRL 规则状况中的 模式是 与决策引擎匹配的片段。模式可能会与插入到决策引擎工作内存的每个事实匹配。模式也可以包含 约束,以进一步定义要匹配的事实。

在最简单的形式中,没有限制,模式匹配给定类型的事实。在以下示例中,type 是 Person,因此模式将与决策引擎的工作内存中的所有 Person 对象匹配:

单一事实类型的模式示例

Person()

类型不需要是某些事实对象的实际类。模式可以参考超类甚至接口,可能会与许多不同类匹配的事实。例如,以下模式匹配决策引擎工作内存中的所有对象:

所有对象的模式示例

Object() // Matches all objects in the working memory

括起约束的特征的括号,如人员年龄上的以下约束:

带有约束的模式示例

Person( age == 50 )

约束( constraint )是一个返回 truefalse 的表达式。DRL 中的模式限制基本上是带有一些增强功能的 Java 表达式,如属性访问,以及一些差别,如 equivalent ()!equals() 语义 ==!=而不是相同 语义)。

任何 JavaBeans 属性都可以直接从模式约束进行访问。bean 属性通过标准 JavaBeans getter 在内部公开,该参数不使用任何参数,并返回一些参数。例如,age 属性在 DRL 中以 年龄 形式编写,而不是 getter getAge()

使用 JavaBeans 属性的 DRL 约束语法

Person( age == 50 )

// This is the same as the following getter format:

Person( getAge() == 50 )

Red Hat Process Automation Manager 使用标准的 JDK Introspector 类来实现这个映射,因此它遵循标准 JavaBeans 规格。要获得最佳决策引擎性能,请使用属性访问格式,如 age,而不是显式使用 getters,如 getAge()

警告

不要使用属性访问器以可能影响规则的方式更改对象状态,因为决策引擎会缓存调用之间的匹配结果,以获得更高的效率。

例如,不要使用以下方法使用属性 accessors:

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 会话中,请谨慎使用嵌套访问器,因为决策引擎的工作内存不知道任何嵌套值,且不会检测到它们何时更改。当其任何父引用都插入到工作内存中时,或者要修改嵌套值,请将所有 outer 事实标记为更新。在上例中,当 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 中的 operator,DRL 运算符则遵循标准的 Java 语义,但 ==!= 运算符除外。

== 运算符使用 null-safe equals() 语义,而不是常见的 相同的 语义。例如,pattern Person(firstName == "John")java.util.Objects.equals(person.getFirstName(), "John") )类似,因为 "John" 不是 null,模式也类似于 "John".equals(person.getFirstName())

!= 运算符使用 null-safe !equals() 语义,而不是通常相同的 语义。例如,Person( firstName != "John") 类似于 !java.util.Objects.equals(person.getFirstName(), "John")

如果项和约束的值不同类型,则决策引擎使用类型协调来解决冲突并减少编译错误。例如,如果 "ten" 在数字 evaluator 中作为字符串提供,则会发生编译错误,而 "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 )

注意

虽然 && 但 operator 具有相同的语义,但可使用不同的优先级解决它们。&& operator 前面是 || 运算符,并且 &&|| 运算符都位于 , operator 前。使用顶级约束中的逗号操作人员获得最佳决策引擎性能和人类可读性。

您不能将逗号运算符嵌入到复合约束表达式中,例如在括号中:

复合约束表达式中滥用的逗号示例

// 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 )

16.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
注意

约束绑定仅考虑遵循它的第一个原子表达式。在以下示例中,模式仅将人的年龄绑定到变量 $a

Person( $a : age * 2 < 100 )

对于更清晰且效率的规则定义,请分隔约束绑定和约束表达式。虽然支持混合绑定和表达式,但这可能会复杂模式并影响评估效率。

// Do not use the following format:
Person( $a : age * 2 < 100 )

// Use the following format instead:
Person( age * 2 < 100, $a : age )

在上例中,如果要绑定到人员年龄的 $a 变量,则必须将其嵌套到括号中,如下例所示:

Person( $a : (age * 2) )

决策引擎不支持绑定到同一声明,但不支持在多个属性间对参数进行解释。虽然位置参数始终以未验证处理,但存在命名参数的符号 :=

以下示例模式在两个 Person 事实中统一 age 属性:

带有未验证的模式示例

Person( $age := age )
Person( $age := age )

未验证为第一个发生次数声明绑定,限制在出现的顺序时与 bound 字段的值相同。

16.8.3. 嵌套限制和内联广播

在某些情况下,您可能需要访问嵌套对象的多个属性,如下例所示:

访问多个属性的模式示例

Person( name == "mark", address.city == "london", address.country == "uk" )

您可以将这些属性访问器分组为使用语法 .(<constraints>) 的嵌套对象,以获得更易读的规则,如下例所示:

带有分组限制的模式示例

Person( name == "mark", address.( city == "london", country == "uk") )

注意

period 前缀 将嵌套的对象约束与方法调用区分。

当您以模式中使用嵌套对象时,您可以使用语法 < type>#<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 )

这些示例模式 将地址 转换为 LongAddress,以及上一次示例中的 DetailedCountry,使父地址可供子类型使用。

您可以使用 instanceof operator 在随后使用那个字段的模式来推断指定类型的结果,如下例所示:

Person( name == "mark", address instanceof LongAddress, address.country == "uk" )

如果无法进行内联广播(例如,如果 instanceof 返回假),则评估将被视为 false

16.8.4. 限制中的日期

默认情况下,决策引擎支持日期格式 dd-mmm-yyyyyyyyyyy。您可以通过为系统属性 drools.dateformat="dd-mmm-yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyymm".您还可以通过使用 drools.defaultlanguagedrools.defaultcountry 系统属性更改语言区域来自定义日期格式(例如,手册的区域设置为 drools.defaultlanguage=thdrools.defaultry=TH)。

带有日期字面限制的模式示例

Person( bornBefore < "27-Oct-2009" )

16.8.5. DRL 模式限制中支持的 operator

DRL 为模式限制中的 Operator 支持标准 Java 语义,但有一些例外,也有一些在 DRL 中唯一的额外运算符。以下列表总结了 DRL 约束中与标准 Java 语义或在 DRL 限制中唯一处理的情况。

.(), #

使用 .() operator 将属性访问器分组为嵌套对象,并使用 # operator 广播到嵌套对象中的子类型。广播到子类型,从父类型提供给子类型。您可以使用对象名称或完全限定的类名称,您可以转换到一个或多个子类型。

带有嵌套对象的模式示例

// 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 dereferencing 的约束示例

Person( $streetName : address!.street )

// This is internally rewritten in the following way:

Person( address != null, $streetName : address.street )

[]

使用此运算符按键通过索引或 映射 值访问 List 值。

带有 ListMap 访问的限制示例

// 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 字段,& lt; 运算符表示 在 之前,对于 String 字段,运算符表示 先按字母顺序排列。这些属性仅适用于可比较的属性。

使用 before operator 的约束示例

Person( birthDate < $otherBirthDate )

Person( firstName < $otherFirstName )

==, !=

将这些运算符使用 等于()!equals() 方法。

null-safe equality 的约束示例

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 或 a Collection 包含或不包含指定的值的字段。这些运算符适用于 ArrayCollection 属性,但也可以使用这些运算符来取代 String.contains()!String.tains() 约束检查。

带有 的限制示例 但不包含集合 ( Collection)

// 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 操作器支持了一个 不包含 的同义词。

memberOf不是 memberOf

使用这些运算符验证某个字段是否是数组的成员,还是定义为变量的 CollectionArrayCollection 必须是一个变量。

带有 memberOf 且不是 memberOf 的限制示例

FamilyTree( person memberOf $europeanDescendants )

FamilyTree( person not memberOf $europeanDescendants )

听起来

使用此运算符验证某个词语是否几乎是相同的声音,使用英语探测器作为给定值(与 匹配 Operator 相似)。此 Operator 使用 Soundex 算法。

具有声音 一样的约束示例

// Match firstName "Jon" or "John":
Person( firstName soundslike "John" )

str

使用此运算符验证某个字段是否以 String 开头或以指定的值结束。您还可以使用此运算符验证 String 的长度。

使用预先限制示例

// 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 )

在 中而不是在 中

使用这些运算符在约束(复合值限制)中指定多个可能的值。复合值限制的功能只在 innot Operator 中被支持。这些运算符的第二运算对象必须是以括号括起的逗号分隔的值列表。您可以将值作为变量、文字、返回值或合格标识符提供。这些运算符在内部使用 operators ==!= 重写为多个限制的列表。

使用 中的 和 not in 的限制示例

Person( $color : favoriteColor )
Color( type in ( "red", "blue", $color ) )

Person( $color : favoriteColor )
Color( type notin ( "red", "blue", $color ) )

16.8.6. DRL 模式限制中的 Operator 优先级

DRL 支持适用于适用约束运算符的标准 Java 操作优先级,但有一些例外,也有一些在 DRL 中唯一的额外运算符。下表列出了适用的 DRL 运算符优先级,从高到低优先级:

表 16.2. DRL 模式限制中的 Operator 优先级
Operator 类型Operator备注

嵌套或 null-safe 属性访问

., .(), !.

不是标准 Java 语义

列出映射 访问

[]

不是标准 Java 语义

约束绑定

:

不是标准 Java 语义

Multiplicative

*, /%

 

additive

+, -

 

改变

>>, >>>, <<

 

关系

&lt;, <=, &gt; , & gt;= , instanceof

 

等于

== !=

使用等 ()!equals() 语义,它 并不相同而不是相同的 语义

Non-short-circuiting and

&

 

非短路

^

 

Non-short-circuiting includes OR

|

 

逻辑 AND

&&

 

逻辑 OR

||

 

Ternary

? :

 

逗号分隔 AND

,

不是标准 Java 语义

16.8.7. DRL(关键字)中支持的规则条件元素

DRL 支持以下规则条件元素(关键字),供您用于 DRL 规则条件中定义的模式:

使用此选项将条件组件分组到逻辑中。支持在fix 前缀中。您可以使用括号 () 显式分组模式。默认情况下,所有列出的模式都与 和 结合使用,并且 未指定任何组合。

带有 的模式示例

//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"))

使用此选项将条件组件分组到逻辑不符中。支持在修复和 前缀或 支持中。您可以使用括号 () 显式分组模式。您也可以通过 使用模式绑定,但每个模式必须单独绑定。

带有 的模式示例

//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 ))

带有 and pattern binding 的特征示例

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 ))

决策引擎不会直接解释 or 元素,而是使用逻辑转换来使用或作为多个子规则重写规则。此过程最终会生成具有单个 根节点的规则,以及每个 condition 元素的一个子规则。每个子规则都已激活并执行(如任何普通规则),在子规则之间没有特殊行为或交互。

因此,可以考虑 condition 元素生成两个或更多类似规则的快捷方式,当两个或更多人对不浏览的术语为 true 时,可以创建多个激活。

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" ))

全部

使用此选项验证匹配第一个模式的所有事实都与所有剩余的模式匹配。当 满足总 结构时,该规则将评估为 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 和 single 模式的规则示例

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 结构与多个模式搭配使用,或者将其嵌套到其他状况元素中,如 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 而不是的规则示例

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

注意

forall(p1 p2 p3 …​) 等同于 not(p1, not(和 p3 …​))

from

使用它来指定模式的数据源。这可让决策引擎与不在工作内存中的数据进行原因。数据源可以是绑定的变量或方法调用的结果上的子字段。用于定义对象源的表达式是符合常规 MVEL 语法的任何表达式。因此,通过 from 元素,您可以轻松地使用对象属性导航、执行方法调用和访问映射和集合元素。

带有 from 和 pattern binding 的规则示例

rule "Validate zipcode"
  when
    Person( $personAddress : address )
    Address( zipcode == "23920W" ) from $personAddress
  then
    // Zip code is okay.
end

带有 的规则示例以及图形表示法

rule "Validate zipcode"
  when
    $p : Person()
    $a : Address( zipcode == "23920W" ) from $p.address
  then
    // Zip code is okay.
end

带有 from 的规则示例来迭代所有对象

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 )

来自 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 元素。
  • modify() 块中使用的变量设置为您的规则条件中的最后一个句子。
  • 当您可以明确管理同一 ruleflow 组中的规则放入激活时,避免使用 lock-on-active 规则属性。

包含 from 子句的模式不能跟以括号开头的其他模式。这个限制的原因是 DRL 解析器 表达式中读取为 "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

使用它来定义与模式的数据源对应的入口点或 事件源。此元素通常用于 from condition 元素。您可以为事件声明一个入口点,以便决策引擎仅从该入口点使用数据来评估规则。您可以在 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 接口的任何 concrete 类,并提供默认的 no-arg 公共构造器。您可以使用 ListLinkedListHashSet 等 Java 集合,或者您自己的类。如果变量在条件中的 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

在本例中,该规则评估每个给定系统决策引擎工作内存中的所有待处理警报,并在列表中对它们进行分组。如果为给定系统找到三个或更多警报,则会执行该规则。

您还可以使用带有与元素嵌套的 收集 元素,如下例所示:

带有 收集和 嵌套的规则示例

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)。此元素是收集条件元素的一种更加灵活、强大的形式。您可以使用 累积 条件或根据需要实施自定义功能中的预定义功能。您还可以在规则条件中使用 缩写 cc

使用以下命令在规则中定义 累积 条件:

累积的首选格式

accumulate( <source pattern>; <functions> [;<constraints>] )

注意

虽然决策引擎支持替代格式用于向后兼容元素,但这种格式是规则和应用程序中优化性能的首选。

决策引擎支持以下预定义的 累积 功能:这些功能接受任何表达式作为输入。

  • average
  • 分钟
  • max
  • 数量
  • sum
  • collectList
  • collectSet

在以下示例中,minmaxaverage 是计算每个传感器所有读取的最小、最大值和平均温度值的累积函数:

带有 累积 值的规则示例

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

以下示例规则使用 平均 功能来 连续计算所有项目的平均利润:

以累计方式计算平均利润的规则示例

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

要在 累积 条件中使用自定义特定域的功能,请创建一个实施 org.kie.api.runtime.rule.AccumulateFunction 接口的 Java 类。例如,以下 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 规则中使用自定义功能,请使用导入 accumulate 语句 导入 函数:

导入自定义功能的格式

import accumulate <class_name> <function_name>

带有导入的 average 功能的规则示例

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

16.8.8. OOPath 语法,在 DRL 规则条件中对象图形

OOPath 是 XPath 的一个面向对象的语法扩展,专为浏览 DRL 规则条件限制中的对象图形。OOPath 使用 XPath 的紧凑标记来导航相关的元素,同时处理集合和过滤限制,对于对象图形来说,OOPath 特别有用。

当事实字段是一个集合时,您可以使用 from condition 元素(关键字)来绑定和原因,而不是该集合中的所有项目。如果您需要浏览规则条件约束中的对象图, condition 元素广泛使用会导致详细和重复的语法,如下例所示:

使用 from浏览对象图的规则示例

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

在本例中,域模型包含带有 计划 研究的 Student 对象。计划 可以有零个或多个 考试 实例,一个 考试 可以有零个或多个预期实例。只有图形的 root 对象,本例中的 学员 需要位于决策引擎的工作内存中以便此规则设置才能正常工作。

作为使用语句中广泛使用的效率,您可以使用缩写的 OOPath 语法,如下例所示:

使用 OOPath 语法浏览对象图形的规则示例

rule "Find all grades for Big Data exam"
  when
    Student( $grade: /plan/exams[course == "Big Data"]/grades )
  then
    // Actions
end

正式,OOPath 表达式的核心抓取以扩展 Backus-Naur 表单(EBNF)表示法定义:

OOPath 表达式的 EBNF 表示法

OOPExpr = [ID ( ":" | ":=" )] ( "/" | "?/" ) OOPSegment { ( "/" | "?/" | "." ) OOPSegment } ;
OOPSegment = ID ["#" ID] ["[" ( Number | Constraints ) "]"]

在实践中,OOPath 表达式具有以下特性:

  • 以正斜杠 / 开头,或以问号和正斜杠 ?/ 开头(如果它是非主动 OOPath 表达式(在本节稍后进行评分)。
  • 可以使用 period . operator 解引用对象的单一属性。
  • 可以使用正斜杠 / 运算符解引用对象的多个属性。如果返回集合,则表达式会迭代集合中的值。
  • 可以过滤掉不满足一个或多个限制的对象。约束被编写为方括号之间的 predicate 表达式,如下例所示:

    作为 predicate 表达式的限制

    Student( $grade: /plan/exams[ course == "Big Data" ]/grades )

  • 可以分解一个遍历对象到通用集合中声明的类子类。后续限制也可以安全地访问该子类中声明的属性,如下例所示。不是此内联广播中指定的类实例的对象会自动过滤。

    使用 downcast 对象的限制

    Student( $grade: /plan/exams#AdvancedExam[ course == "Big Data", level > 3 ]/grades )

  • 可以重新引用在当前迭代图前遍历图形的对象。例如,以下 OOPath 表达式仅匹配所传递考试的平均等级:

    使用 backreferenced 对象的限制

    Student( $grade: /plan/exams/grades[ result > ../averageResult ] )

  • 也可以是另一个 OOPath 表达式,如下例所示:

    递归约束表达式

    Student( $exam: /plan/exams[ /grades[ result > 20 ] ] )

  • 可以通过方括号 [] 间的索引访问对象,如下例所示。要遵循 Java 惯例,OOPath 索引基于 0,而 XPath 索引es 则基于 1。

    通过索引对对象的访问限制

    Student( $grade: /plan/exams[0]/grades )

OOPath 表达式可以是 reactive 或 non-reactive。在评估 OOPath 表达式的过程中,决策引擎不会响应涉及深度嵌套对象的更新。

要使这些对象被动更改,修改对象以扩展类 org.drools.core.phreak.ReactiveObject。在修改对象以扩展 ReactiveObject 类后,域对象调用继承的方法 通知修改,以在更新其中一个字段时通知决策引擎,如下例所示:

通知决策引擎(即考试已移至其他课程)的对象方法示例

public void setCourse(String course) {
        this.course = course;
        notifyModification(this);
        }

使用下列对应的 OOPath 表达式时,当考试移动到不同的课程时,重新执行该规则以及与该规则匹配的等级列表:

来自 "Big Data" 规则的 OOPath 表达式示例

Student( $grade: /plan/exams[ course == "Big Data" ]/grades )

您还可以使用 ?/ 分隔符而不是 / 分隔符仅在 OOPath 表达式的一个子端口中禁用 reinteractive,如下例所示:

部分非活跃的 OOPath 表达式示例

Student( $grade: /plan/exams[ course == "Big Data" ]?/grades )

在此例中,决策引擎对考试所做的更改做出反应,或者如果计划中添加了考试,但不将新评测添加到现有考试中。

如果 OOPath 部分不是活跃的,OOPath 表达式的所有剩余部分也将变为 non-reactive。例如,以下 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 中的 ListSet 接口的专用实现。这些实现是 ReactiveListReactiveSet 类。另外还可使用 ReactiveCollection 类。该实施还通过 IteratorListIterator 类提供对执行可变操作的被动支持。

以下示例类使用这些类来配置 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
    }
  }

1
对标准 Java List 实例使用 ReactiveList 实例来被动支持。
2
在 reactive 支持中更改了字段时,使用所需的 notifyModification() 方法。
3
children 字段是一个 ReactiveList 实例,因此不需要 notifyModification() 方法调用。通知会自动处理,与通过 children 字段执行的所有其他变异操作一样。
Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.