Drools Rule Language
1 Packages in DRL
- 可以有多个packages
- 但推荐只用一个package
- example: package org.mortgages;
2 Import statements in DRL
2.1 You specify the package and data object in the format packageName.objectName, with multiple imports on separate lines.
2.2 example: import org.mortgages.LoanApplication;
3 Functions in DRL
3.1 在drl里面定义函数
function String hello(String applicantName) {
return "Hello " + applicantName + "!";
}
3.2 实际也可以直接import java 的static function: import static org.example.applicant.MyFunctions.hello;
4 Queries in DRL
查询fact,其实可以用java访问替代
4.1 Queries in DRL files search the working memory of the Drools engine for facts related to the rules in the DRL file
4.2 not yet supported
- Expression unification - pred( X, X + 1, X * Y / 7 )
- List and Map unification
4.3 支持对入参的赋值
query contains(String $s, String $c)
$s := String( this.contains( $c ) )
end
rule PersonNamesWithA when
$p : Person()
contains( $p.name, "a"; )
then
end
5 Type declarations and metadata in DRL
5.1 在DSL里面定义数据类型
5.1.1 支持extend,java访问
5.2 是否有实际应用场景?
Rule attributes in DRL
6.1 Rule attributes
6.1.1 salience 优先级
6.1.2 enabled
6.1.3 date-effective
- 注意没有时间
- Example: date-effective “4-Sep-2018”
6.1.4 date-expires
6.1.5 no-loop
- 不重复执行 the rule cannot be reactivated (looped) if a consequence of the rule re-triggers a previously met condition.
6.1.6 agenda-group
就是分组,通过setFocus指定优先执行,具体看drools engine里面的说明
6.1.7 activation-group :only one rule can be activated
6.1.8 duration 执行时长:A long integer value defining the duration of time in milliseconds after which the rule can be activated, if the rule conditions are still met.
6.1.9 timer
- 定时执行定义
- Example: timer ( cron:* 0/15 * * * ? ) (every 15 minutes)
6.1.10 calendar
A Quartz calendar definition for scheduling the rule.
6.1.11 auto-focus
a focus is automatically given to the agenda group to which the rule is assigned
6.1.12 lock-on-active
- 只用于agenda group 或者rule flow
- the rule cannot be activated again until the ruleflow group is no longer active or the agenda group loses the focus
6.1.13 ruleflow-group
rules can fire only when the group is activated by the associated rule flow(纯规则不用,和jbpm有关)
6.1.14 dialect
A string identifying either JAVA or MVEL as the language to be used the dialect “JAVA” rule consequences support only Java 5 syntax
6.2 定时控制
6.2.1 Generally, a rule that is controlled by a timer becomes active when the rule is triggered and the rule consequence is executed repeatedly
6.2.2 When the Drools engine is in passive mode, rule consequences of timed rules are evaluated only when fireAllRules() is invoked again
6.2.3 可以通过ksconf.setOption( TimedRuleExecutionOption.YES );触发定时执行
// You can additionally set a FILTERED specification on the TimedRuleExecutionOption option
KieSessionConfiguration ksconf = KieServices.Factory.get().newKieSessionConfiguration();
conf.setOption( new TimedRuleExecutionOption.FILTERED(new TimedRuleExecutionFilter() {
public boolean accept(Rule[] rules) {
return rules[0].getName().equals("MyRule");
}
}) );
7 Rule conditions in DRL (WHEN)
7.1 also known as the Left Hand Side (LHS) of the rule
7.2 每一行代表一个判断,默认连接词为and
7.3 defined keyword conjunctions (such as and, or, or not)
7.4 支持nest access properties in patterns
- Person( address.houseNumber == 50 )
- Person( getAddress().getHouseNumber() == 50 )
7.5 example - Person( age > 100 && ( age % 10 == 0 ) )
- Person( Math.round( weight / ( height * height ) ) < 25.0 )
- Person( ( age > 50 && weight > 80 ) || height > 2 )
7.6 注意点
7.6.1 避免修改fact
7.6.2 避免随机fact
7.7 Bound variables in patterns and constraints
7.7.1 Bound variables can help you define rules more efficiently or more consistently with how you annotate facts in your data model.
7.7.2 绑定pattern
rule "simple rule"
when
$p : Person()
then
System.out.println( "Person " + $p );
end
A pattern in a DRL rule condition is the segment to be matched by the Drools engine.
7.7.3 bind variables to properties in pattern constraints
// Two persons of the same age:
Person( $firstAge : age ) // Binding
Person( age == $firstAge ) // Constraint expression
7.8 Nested constraints and inline casts
- Person( name == “mark”, address.( city == “london”, country == “uk”) )
- Person( name == “mark”, address.city == “london”, address.country == “uk” )
- inner class,使用#,例子
Person( name == “mark”, address#LongAddress.country == “uk” )
7.9 Date literal in constraints
7.9.1 By default, the Drools engine supports the date format dd-mmm-yyyy
7.9.2 修改:drools.dateformat=“dd-mmm-yyyy hh:mm”
7.9.3 Person( bornBefore < “27-Oct-2009” )
7.10 Supported operators in DRL pattern constraints
7.10.1 .(), #
7.10.2 !. (interpreted as != null)
- Person( $streetName : address!.street )
- Person( address != null, $streetName : address.street )
7.10.3 []
operator to access a List value by index or a Map value by key.
7.10.4 <, <=, >, >=
7.10.5 ==, !=
7.10.6 &&, ||
7.10.7 matches, not matches
- matches or does not match a specified Java regular expression
7.10.8 contains, not contains
7.10.9 memberOf, not memberOf
- a field is a member of or is not a member of an Array or a Collection
7.10.10 soundslike
- verify whether a word has almost the same sound, using English pronunciation,
7.10.11 str
- starts with or ends with a specified value.
- You can also use this operator to verify the length of the 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 )
7.10.12 in, notin
- Color( type in ( “red”, “blue”, $color ) )
7.10.13 列表
7.11 supports the following rule condition elements (keywords)
7.11.1 and
- Color( colorType : type ) and Person( favoriteColor == colorType )
7.11.2 or
注意可以不同对象之间or
pensioner : (Person( sex == "f", age > 60 ) or Person( sex == "m", age > 65 ))
//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 ))
7.11.3 exists
- exists (Person( firstName == “John” ) and Person( lastName == “Doe” ))
7.11.4 not
7.11.5 not/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
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
7.11.6 from
Use this to specify a data source for a pattern
rule "Validate zipcode"
when
Person( $personAddress : address )
Address( zipcode == "23920W" ) from $personAddress
then
// Zip code is okay.
end
Using from with lock-on-active rule attribute can result in rules not being executed
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
The pattern that contains a from clause cannot be followed by another pattern starting with a parenthesis
7.11.7 entry-point
Use this to define an entry point, or event stream
rule "Authorize withdrawal"
when
WithdrawRequest( $ai : accountId, $am : amount ) from entry-point "ATM Stream"
CheckingAccount( accountId == $ai, balance > $am )
then
// Authorize withdrawal.
end
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);
7.11.8 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
7.11.9 accumulate
- accumulate :These functions accept any expression as input.
- average
- min
- max
- count
- sum
- collectList
- collectSet
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
- 可以自定义,增加accumulate函数:create a Java class that implements the org.kie.api.runtime.rule.AccumulateFunction interface. alternate syntax for a single function with return type
rule "Apply 10% discount to orders over US$ 100,00"
when
$order : Order()
$total : Number( doubleValue > 100 )
from accumulate( OrderItem( order == $order, $value : value ),
sum( $value ) )
then
// apply discount to $order
end
- accumulate with inline custom code
<result pattern> from accumulate( <source pattern>,
init( <init code> ),
action( <action code> ),
reverse( <reverse code> ),
result( <result expression> ) )
rule R
example
dialect "mvel"
when
String( $l : length )
$sum : Integer() from accumulate (
Person( age > 18, $age : age ),
init( int sum = 0 * $l; ),
action( sum += $age; ),
reverse( sum -= $age; ),
result( sum )
)
eval
7.12 OOPath syntax with graphs of objects in DRL rule conditions
7.12.1 OOPath是XPath的面向对象语法扩展,用于浏览DRL规则条件约束下的对象。
7.12.2 对比
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
Example rule that browses a graph of objects with OOPath syntax
rule "Find all grades for Big Data exam"
when
Student( $grade: /plan/exams[course == "Big Data"]/grades )
then
// Actions
end
7.12.3 语法
- OOPExpr = [ID ( “:” | “:=” )] ( “/” | “?/” ) OOPSegment { ( “/” | “?/” | “.” ) OOPSegment } ;
- OOPSegment = ID [“#” ID] [“[” ( Number | Constraints ) “]”]
examples
Student( $grade: /plan/exams#AdvancedExam[ course == "Big Data", level > 3 ]/grades )
Student( $grade: /plan/exams/grades[ result > ../averageResult ] )
/和?/区别
- Slash (“/”): Used as a separator in the path expression.
- Question Mark (“?”): Used as a wildcard to match any object in a collection.
- Forward Slash with Question Mark (“?/”): Used for nested wildcard matching in collections.
7.12.4 参考URL
https://blog.csdn.net/u010952582/article/details/109669747
8 Rule actions in DRL (THEN)
8.1 The then part of the rule (also known as the Right Hand Side (RHS) of the rule) contains the actions to be performed when the conditional part of the rule has been met.
8.2 Supported rule action methods in DRL
8.2.1 java set
- set ( )
- $application.setApproved ( false );
8.2.2 modify
可以看着批量set,会触发rule
modify( LoanApplication ) {
setAmount( 100 ),
setApproved ( true )
}
8.2.3 update
- 通知drools fact 有变化
- update ( <object, ) // Informs the Drools engine that an object has changed
LoanApplication.setAmount( 100 );
update( LoanApplication );
8.2.4 insert-参考engine
- insert
- insertLogical
8.2.5 delete
8.3 Other rule action methods from drools variable
使用drools获取当前runtime 信息
8.3.1 drools.getRule().getName(): Returns the name of the currently firing rule.
8.3.2 drools.getMatch(): Returns the Match that activated the currently firing rule.
8.3.3 drools.getKieRuntime().halt(): Terminates rule execution if a user or application previously called fireUntilHalt()
8.3.4 drools.getKieRuntime().getAgenda(): Returns a reference to the KIE session Agenda
8.3.5 具体参考java doc getRuleMatch/KieRuntime
8.4 Advanced rule actions with conditional and named consequences
8.4.1 使用DO 分支
8.4.2 使用break 分支
break blocks any further condition evaluation
rule "Give free parking and 10% discount to over 60 Golden customer and 5% to Silver ones"
when
$customer : Customer( age > 60 )
if ( type == "Golden" ) do[giveDiscount10]
else if ( type == "Silver" ) break[giveDiscount5]
$car : Car( owner == $customer )
then
modify($car) { setFreeParking( true ) };
then[giveDiscount10]
modify($customer) { setDiscount( 0.1 ) };
then[giveDiscount5]
modify($customer) { setDiscount( 0.05 ) };
end
9 Comments in DRL files
9.1 DRL supports single-line comments prefixed with a double forward slash // and multi-line comments enclosed with a forward slash and asterisk /* … */
10 Error messages for DRL troubleshooting
10.1 图例
10.2 1st Block: Error code
10.3 2nd Block: Line and column in the DRL source where the error occurred
10.4 3rd Block: Description of the problem
10.5 4th Block: Component in the DRL source (rule, function, query) where the error occurred
10.6 5th Block: Pattern in the DRL source where the error occurred (if applicable)
10.7 error code
- 10.7.1 101: no viable alternative
- 10.7.2 102: mismatched input
- 10.7.3 103: failed predicate
- 10.7.4 104: trailing semi-colon not allowed: Indicates that an eval() clause in a rule condition uses a semicolon ; but must not use one.
eval( abc(); ) // Must not use semicolon;
- 10.7.5 105: did not match anything
11 Rule units in DRL rule sets (实验性功能)
11.1 Rule units are groups of data sources, global variables, and DRL rules that function together for a specific purpose
11.2 Rule units are experimental in Drools 7. Only supported in Red Hat build of Kogito.
11.3 需要创建对应java class
11.3.1
11.3.2 package org.mypackage.myunit
unit AdultUnit
rule Adult
when
$p : Person(age >= adultAge) from persons
then
System.out.println($p.getName() + " is adult and greater than " + adultAge);
end
12 Performance tuning considerations with DRL
12.1 Define the property and value of pattern constraints from left to right
12.1.1 ensure that the fact property name is on the left side of the operator and that the value (constant or a variable) is on the right side
12.2 Use equality operators more than other operator types in pattern constraints when possible
12.3 List the most restrictive rule conditions first
12.4 Avoid iterating over large collections of objects with excessive from clauses
12.5 Use Drools engine event listeners instead of System.out.println statements in rules for debug logging
12.6 Use the drools-metric module to identify the obstruction in your rules
- first add drools-metric to your project dependencies:
- If you want to use drools-metric to enable trace logging, configure a logger for org.drools.metric.util.MetricLogUtils
<logger name="org.drools.metric.util.MetricLogUtils" level="trace"/>
- Alternatively, you can use drools-metric to expose the data using Micrometer.
Example project dependency for Micrometer
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-jmx</artifactId> <!-- Discover more registries at micrometer.io. -->
</dependency>
Example Java code for Micrometer
Metrics.addRegitry(new JmxMeterRegistry(s -> null, Clock.SYSTEM));