1 Introduction
drools
中的模式( patterns
)和约束( constraints
)以及when
。
2. Grammatical structure
3. Pattern example
3.1 Single Object Matching
rule "工作内存中只要有Person对象就执行,存在多个执行多次"
when Person()
then
System.out.println("工作内存中存在Person对象");
end
3.2 Match any object
rule "只要工作内存中有对象,都会匹配到"
when Object()
then
System.out.println("只要工作内存中有对象,都会匹配到");
end
3.3 Conditional Matching
rule "匹配年龄小于20岁的"
when
Person(age < 20) // 等驾与getAge() < 20,推荐使用属性的写法
then
System.out.println("匹配年龄小于20岁的");
end
3.3.1 Notes
1. The matching condition result needs to be true
or false
.
2. Person(age < 20)
and Person(getAge() < 20)
are equivalent, but 推荐第一种写法
.
3. Person(age < 20)
will call the getAge()
method by default. If the method does not exist, it will call the age()
method. If it does not exist, an exception will be thrown.
4. Drools engine
will cache the matching results during the call to improve efficiency, so our getter
method should not be stateful.
3.4 Matching of Nested Properties
3.4.1 Accessing a single nested property
rule "嵌套属性的访问"
when
Person(car.name == "宝马")
then
System.out.println("嵌套属性的访问");
end
3.4.2 Accessing Multiple Nested Properties
rule "嵌套属性的访问-02"
when
Person( age < 20 && car.name == "宝马" && car.color == null)
then
System.out.println("嵌套属性的访问-02");
end
3.4.3 Attribute grouping
.( <constraints> )
Group these property accessors into nested objects for more readable rules
rule "嵌套属性的访问-03"
when
Person(age < 20 , car.(name == "宝马" || color != null)) // 属性分组访问
then
System.out.println("嵌套属性的访问-03");
end
3.4.4 Coercion
In nested mode, we can use the <type>#<subtype>
syntax to cast to the subtype and make the supertype's getter for the subtype.
rule "嵌套属性的访问-强制类型转换"
when
Person(age < 20 , car#BMWCar.name == "宝马") // 强制类型转换
then
System.out.println("嵌套属性的访问-强制类型转换");
end
Pay attention to the above car#BMWCar
, this is to convert car
into BMWCar
type to use.
3.4.5 Notes
In stateful kie session
, use 嵌套属性
with caution. Because the working memory of Drools engine
doesn't know about any nested values and doesn't detect when they change.
3.5 Calling java method constraints
rule "调用java方法约束"
when
Person(!isChild())
then
System.out.println("调用java方法约束");
end
3.5.1 Note the implementation
isChild()
The method should not modify the status of ---ec84dc4152e989333ed968f7a742f0cb fact
, because drools引擎
In order to improve work efficiency, the result during the call will be cached. It will lead to inaccurate matching results.
3.6 Multiple Field Constraints
rule "多个字段约束"
when
Person((name != null && age < 20) && car != null) // isChild 方法中需要有状态的更改
then
System.out.println("多个字段约束");
end
3.7 Top-level field constraints
Person(name != null , age < 20 , car != null)
Person((name != null && age < 20) && car != null)
上面2种写法是一样的。
3.7.1 Notes
1. In the top-level field constraint ,
the performance is higher than that of &&
.
2、 &&
优先||
, &&
和---fa2c61c8ef05caf2c6a7d7347fd487f9 ||
都优先,
。
3. It is not possible to embed ,
in compound expressions, for example: Person((name != null , age < 20) , car != null)
This is a wrong way of writing, you need to replace ,
&&
symbol.
3.8 Use of Date Types
In drools
the default date format is dd-mmm-yyyy
, here we set the system variable drools.dateformat
to yyyy-MM-dd HH:mm:ss
format.
rule "日期类型的使用"
when
$p: Person(registerDate < '2022-05-24 12:12:12' ) // 日期格式比较,System.setProperty("drools.dateformat","yyyy-MM-dd HH:mm:ss");
then
System.err.println("日期类型的使用 注册时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format($p.getRegisterDate()) );
end
4. Use bind variables in patterns and constraints
rule "使用绑定变量"
when
$p: Person($age: age)
then
System.err.println("使用绑定变量 " + $p.getName() + ": " + $age);
end
Later, we can use $p
and $age
, $p
to indicate that when the current rule is running, the matching $age
Person
object in the working memory $age
Indicates that match the age
attribute of this object, the general binding variable starts with $
, and starts with the attribute of fact
.
4.1 Bad writing of bound variables in field constraints
rule "使用绑定变量-不好的写法"
when
Person($age: age * 2 < 100)
then
System.err.println("使用绑定变量-不好的写法 " + ": " + $age);
end
This is not clearly written, and the execution efficiency is not high.
4.2 A good way to write bound variables in field constraints
rule "使用绑定变量-推荐的写法"
when
Person( age * 2 < 100, $age: age) // 这样写更清晰,运行效率更高
then
System.err.println("使用绑定变量-推荐的写法 " + ": " + $age);
end
4.3 Constraint binding only considers the first atomic expression that follows
Person( $age1: (age * 2))
and
Person( $age2: age * 2)
The result is not the same, the result of ---427f7dc1ffea2460de86c902b3c0854e $age1
is twice the result of $age2
.
5. Supported operators
5.1 .() Grouping properties
Use the .()
operator to group property accessors into nested objects
Person(age < 20 , car.(name == "宝马" , color == null ))
Person(age < 20 , car.name == "宝马" , car.color == null )
The above two spellings mean the same thing
5.2 # Type conversion
In nested mode, we can use the <type>#<subtype>
syntax to cast to the subtype and make the supertype's getter for the subtype.
Person(car#BMWCar.brand == "BMW")
car#BMWCar
means to convert car
to BMWCar
type.
5.3 !. Nested properties are null safe
Person(car!.name == "宝马") // 如果此时 car 为null,则使用 car!.name 是不会报错的
Use !.
avoid null pointer exceptions when our properties are nested.
5.4 [] Operation List or Map
1. List operation - access by index
Person(hobbyList[0] == "打篮球")
2, map operation - operate according to the key
Person(map["key1"] == "value1")
This map
Person(map["key1"] == "value1")
Person
is a field of map
is ---86f170a77ed019c8b4f1c1f8f9
5.5 <, <=, >, >=, ==, !=, &&, ||
These operators are used in the same way as in Java.
<, <=, >, >=
These operators, if used in fields of type Date
, then <
represents before, for fields of type ---0f39973d11679fe6d4f1cfca33f90---, ---96d1f8ab91817557389d7cedc6eb1a3b---represents before, for fields of type String
Sort and compare in natural order
Person(age ((> 30 && < 40) || (>= 18 && <= 25))
&& car != null && registerDate < '2022-12-12 12:12:12')
Person(age >= 18 && age <= 25)
and Person(age (>= 18 && <= 25))
are equivalent.
5.6 matches, not matches Regular matching
- Used to determine whether
给定的字段
matches the regular expression executed. -
正则表达式
can be a given string or dynamically obtained from a variable. - Escaping requires the use of
\\
.
Person(name matches hobbyList[2] && car.name not matches "^奥迪") // 正则表达式可以是动态来的
5.7 contains, not contains Does a collection or string contain anything?
contains
: included; not contains
: not included.
1. Verify that a Array
or Collection
contains the value of a specified field (can be 常量
or 变量
).
2. It can also be String
type field contains a certain value (it can be 常量
or 变量
).
Person(
hobbyList contains "打篮球" && hobbyList not contains "打橄榄球"
&&。hobbyList not contains name &&
name contains "张" && name not contains car.name
)
hobbyList
: Field of type List.
name
or car.name
: Field of type String.
As you can see from the example above:
hobbyList contains "打篮球"
: "playing basketball" is a constant string.
hobbyList not contains nam
: "name" is a dynamic variable, obtained from Person.
For backward compatibility, the excludes operator works the same as not contains.
5.8 memberOf, not memberOf field is a member of a set
Verify that a field is a member of Array
or Collection
. Array
or Collection
must be variable.
Person("打篮球" memberOf hobbyList && "篮球" not memberOf hobbyList
&& name not memberOf hobbyList)
5.9 str verifies whether a field begins or ends with what
- Verify that the specified string starts with
str[startsWith]
. - Verify what the specified string ends with
str[endsWith]
. - Verify the length of the specified string
str[length]
. - Check out this class
org.drools.core.base.evaluators.StrEvaluatorDefinition
Person(
name str[startsWith] "张" && name str[endsWith] "三" &&
name str[length] 2 && "张三" str[startsWith] "张"
)
5.10 in not in
Determine if a value is in a set of values
Person(
$name: name &&
name in ($name, "李四") &&
"打篮球" in ("打篮球", "踢足球") &&
car.name not in ("打篮球", $name)
)
6. Operator precedence
The following table lists the precedence of DRL operators from 高到低
.
Operator type | Operators | Notes | |
---|---|---|---|
Nested or null-safe property access | . , .() , !. | Not standard Java semantics | |
List or Map access | [] | Not standard Java semantics | |
Constraint binding | : | Not standard Java semantics | |
Multiplicative | * , /% | ||
Additive | + , - | ||
Shift | >> , >>> , << | ||
Relational | < , <= , > , >= , instanceof | ||
Equality | == != | Uses equals() and !equals() semantics, not standard Java same and not same semantics | |
Non-short-circuiting AND | & | ||
Non-short-circuiting exclusive OR | ^ | ||
Non-short-circuiting inclusive OR | `\ | ` | |
Logical AND | && | ||
Logical OR | `\ | ` | |
Ternary | ? : | ||
Comma-separated AND | , | Not standard Java semantics |
7. Rule condition elements (keywords) supported by DRL
There are many rule condition elements supported in drl
b1c3ec274659b6423e9ceb79b0ef34bc---, here 讲解部分
the usage of keyword words.
7.1 and
- Use
and
to group conditions into logical combinations. -
and
Support infix and prefix mode. - Grouping can be done explicitly using
()
. - By default it is
and
// 规则 and-01 and-02 and-03 是同一个意思,工作内存中需要同时存在Person和Order对象
rule "and-01"
when
Person() and Order()
then
System.out.println("and-01");
end
rule "and-02"
when
(and Person() Order())
then
System.out.println("and-02");
end
rule "and-03"
when
Person()
Order()
then
System.out.println("and-03");
end
7.2 or
or
also supports several ways of writing, here is one way of writing. Consistent with the usage of --- java
in or
rule "or-01"
when
$p: Person() or Order() // 规则内存中只要存在Pereson或Order对象就会执行,如果都存在,那么可能会执行多次。如果只想执行一次,可以看下exists的用法
then
System.out.println("or-01");
end
7.3 exists
Matching with Fact
in working memory will only be triggered at the first match, not multiple times. If used with multiple patterns, you need to use ()
.
简单理解:
Suppose I insert 5 Person
objects into working memory at a time, if exists
matches, it will only be executed once, not 5 times.
rule "exists"
when
exists (Person() or Order()) // 单个: exists Person() 多个:需要()分割
then
System.out.println("exists 工作内存中同时存在多个Person()对象和Order()对象,该规则也只执行一次");
end
7.4 not
When this object does not exist in the rule memory, the rule is triggered.
For example: not Person()
indicates that there is no Person
this Fact
object in the rule memory.
rule "not-02"
when
not (Person(name == "李四") or Order(orderId == 1000))
then
System.out.println("not-02,规则内存中不存在Person#name==李四或Order#orderId=1000 时触发");
end
7.5 from
使用它来指定模式的数据源。 这使 Drools 引擎能够对不在工作内存中的数据进行推理。
data source can be a subfield of a bind variable or the result of a method call. An expression used to define an object source is any expression that follows normal MVEL syntax. Therefore, the from element enables you to easily navigate using object properties, perform method calls, and access map and collection elements.
Basic usage:
rule "from"
when
$p: Person($hobbyList: hobbyList)
$hobby: String() from $hobbyList
then
System.out.println("如果$hobby有多个,那么此处可能执行多次");
System.out.println("from: person: " + $p.getName() + " 的 hobby is: " +$hobby);
end
Person
的hobbyList
,那么推荐hobbyList
这个插入到kie session
中,来提高性能。
Workaround for use with lock-on-active
Using from with lock-on-active
rule attribute can result in rules not being executed
. You can address this issue in one of the following ways:
- Avoid using the
from
element when you can insert all facts into the working memory of the Drools engine or use nested object references in your constraint expressions. - Place the variable used in the
modify()
block as the last sentence in your rule condition. - Avoid using the
lock-on-active
rule attribute when you can explicitly manage how rules within the same ruleflow group place activations on one another.
The solution to the form clause followed by a pattern
After the pattern containing the from
clause 不能跟以括号开头的另一个模式
. The reason for this restriction is that the DRL parser reads the from expression as "from $l (String() or Number())" and it cannot distinguish this expression from a function call. 最简单的解决方法是将 from 子句括在括号中
, as shown in the following example:
// 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
7.6 entry-point
使用它来定义与模式的数据源相对应的入口点或事件流
. This element is usually used with the from
condition element. You can declare an entry point for an event so that the Drools engine uses only data from that entry point to evaluate rules. You can implicitly declare an entry point by referencing it in DRL rules, or explicitly declare it in your Java application.
drl file
rule "entry-point"
when
$o: Order() from entry-point "order-entry-point" // 这个地方的数据是从 order-entry-point 中来的,kieSession.getEntryPoint("order-entry-point");
$p: Person() // 这个地方的数据是通过kieSession.insert 来的
then
System.err.println("entry-point" + $p.getName() + ": " + $o.getOrderId());
end
Order()
From the above rule file, this Order()
object is from order-entry-point
. rather than from anywhere else.
Java file
// order-entry-point 这个是 drl 文件中定义的
EntryPoint entryPoint = kieSession.getEntryPoint("order-entry-point");
entryPoint.insert(new Order(2001L, 10000L));
8. Complete project
https://gitee.com/huan1993/spring-cloud-parent/tree/master/drools/drools-drl-when
9. Reference address
1. https://docs.drools.org/7.69.0.Final/drools-docs/html_single/index.html#drl-rules-WHEN-con_drl-rules
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。