1

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

  1. Used to determine whether 给定的字段 matches the regular expression executed.
  2. 正则表达式 can be a given string or dynamically obtained from a variable.
  3. 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

  1. Verify that the specified string starts with str[startsWith] .
  2. Verify what the specified string ends with str[endsWith] .
  3. Verify the length of the specified string str[length] .
  4. 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

  1. Use and to group conditions into logical combinations.
  2. and Support infix and prefix mode.
  3. Grouping can be done explicitly using () .
  4. 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

PersonhobbyList ,那么推荐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:

  1. 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.
  2. Place the variable used in the modify() block as the last sentence in your rule condition.
  3. 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


huan1993
218 声望34 粉丝

java工程师