85.4. Fibonacci 示例决策(递归和冲突解析)
Fibonacci 示例决策集演示了决策引擎如何使用递归来解析序列中规则的执行冲突。该示例重点通过您可以在规则中定义的 salience 值解决冲突。
以下是 Fibonacci 示例的概述:
-
名称 :fibon
acci -
主类 :
org.drools.examples.fibonacci.FibonacciExample(src/main/java) -
模块 :
drools-examples - 类型 :Java 应用程序
-
规则文件:
org.drools.examples.fibonacci.Fibonacci.drl(在src/main/resources中) - 目标 :通过规则 salience 来演示递归和冲突解析
Fibonacci Numbers 形成以 0 和 1 开头的序列。下一个 Fibonacci 号通过添加前面的两个 Fibonacci 号: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946 等。
Fibonacci 示例使用带有以下两个字段的单事实类 Fibonacci :
-
sequence -
value
sequence 字段表示对象在 Fibonacci 数字序列中的位置。value 字段显示该序列位置的 Fibonacci 对象的值,其中 -1 表示仍需要计算的值。
Fibonacci 类
public static class Fibonacci {
private int sequence;
private long value;
public Fibonacci( final int sequence ) {
this.sequence = sequence;
this.value = -1;
}
... setters and getters go here...
}
要执行示例,请在 IDE 中作为 Java 应用程序运行 org.drools.examples.fibonacci.FibonacciExample 类。
执行后,以下输出会出现在 IDE 控制台窗口中:
IDE 控制台中的 Fibonacci 示例输出
recurse for 50
recurse for 49
recurse for 48
recurse for 47
...
recurse for 5
recurse for 4
recurse for 3
recurse for 2
1 == 1
2 == 1
3 == 2
4 == 3
5 == 5
6 == 8
...
47 == 2971215073
48 == 4807526976
49 == 7778742049
50 == 12586269025
为了在 Java 中实现此行为,示例将插入单个 Fibonacci 对象,序列字段为 50。然后,示例使用递归规则插入其他 49 Fibonacci 对象。
这个示例使用 MVEL dialect modify 关键字启用块 setter 操作并通知决策引擎更改,而不是实施 PropertyChangeSupport 接口来使用动态事实。
Fibonacci 示例执行
ksession.insert( new Fibonacci( 50 ) );
ksession.fireAllRules();
这个示例使用以下三个规则:
-
"Recurse" -
"Bootstrap" -
"calculate"
规则 "Recurse" 匹配每个断言的 Fibonacci 对象,值为 -1,创建并模拟一个新的 Fibonacci 对象,序列小于当前匹配的对象。每次添加 Fibonacci 对象时,如果一个序列字段等于 1,则该规则会重新匹配并再次触发。当您在内存中所有 50 个 Fibonacci 对象后,in 条件元素用于停止规则匹配。规则也具有 salience 值,因为您需要在执行 "Bootstrap" 规则前,所有 50 个 Fibonacci 对象都变为serted。
规则"递归"
rule "Recurse"
salience 10
when
f : Fibonacci ( value == -1 )
not ( Fibonacci ( sequence == 1 ) )
then
insert( new Fibonacci( f.sequence - 1 ) );
System.out.println( "recurse for " + f.sequence );
end
为更好地了解本例的执行流程,您可以将审计日志文件从 target/fibonacci.log 加载到 IDE debug 视图或 审计 视图(例如,在 Window
在本例中,审计视图显示 Fibonacci 对象的原始断言,序列 字段为 50,从 Java 代码完成。从那里,审计视图显示 规则的持续递归,其中每个断言 Fibonacci 对象会导致 "递归" 规则激活并再次触发。
图 85.7. 审计视图中的规则"递归"
当 Fibonacci 对象带有 2 序列 字段被断言时,"Bootstrap" 规则会与 "递归"规则匹配 并激活。请注意,对于字段 序列 的限制,测试使用 1 或 2 的相等性:
规则"Bootstrap"
rule "Bootstrap"
when
f : Fibonacci( sequence == 1 || == 2, value == -1 ) // multi-restriction
then
modify ( f ){ value = 1 };
System.out.println( f.sequence + " == " + f.value );
end
您还可以使用 IDE 中的 Agenda View 来调查决策引擎模拟的状态。"Bootstrap" 规则尚未触发,因为 "递归" 规则具有更高的 salience 值。
图 85.8. Agenda View 1 中的规则"递归"和"Bootstrap"
当带有 1 序列 的 Fibonacci 对象被断言时,"Bootstrap" 规则会再次匹配,从而导致该规则的两个激活。"递归" 规则不匹配并激活,因为当存在带有 1 序列 的 Fibonacci 对象后,t 条件元素会立即停止匹配。
图 85.9. Agenda View 2 中的规则"递归"和"Bootstrap"
"Bootstrap" 规则将 序列 为 1 和 2 的对象设置为值 1。现在,您有两个 Fibonacci 对象的值不等于 -1, "Calculate" 规则可以匹配。
此时,工作内存中几乎有 50 个 Fibonacci 对象。您需要选择合适的 triple 来依次计算每个值。如果您在没有字段限制的规则中使用三种 Fibonacci 模式来限制可能的跨产品,则结果将是 50x49x48 可能的组合,从而导致大约 125,000 个可能的规则触发,大多数规则都不正确。
"Calculate" 规则使用字段限制来以正确顺序评估三种 Fibonacci 模式。此技术称为 跨产品匹配。
第一个模式找到任何值为 != -1 的 Fibonacci 对象,并绑定模式和字段。第二个 Fibonacci 对象执行同样的操作,但添加额外的字段约束,以确保其序列大于绑定到 f1 的 Fibonacci 对象。当此规则第一次触发时,您知道只有序列 1 和 2 具有 1 值,并且两个限制可确保 f1 引用序列 1,以及 f2 引用序列 2。
最终模式找到 Fibonacci 对象,值设为 -1, 以及一个大于 f2 的序列。
此时,可从可用的跨产品正确选择三个 Fibonacci 对象,您可以计算绑定到 f3 的第三个 Fibonacci 对象的值。
规则"Calculate"
rule "Calculate"
when
// Bind f1 and s1.
f1 : Fibonacci( s1 : sequence, value != -1 )
// Bind f2 and v2, refer to bound variable s1.
f2 : Fibonacci( sequence == (s1 + 1), v2 : value != -1 )
// Bind f3 and s3, alternative reference of f2.sequence.
f3 : Fibonacci( s3 : sequence == (f2.sequence + 1 ), value == -1 )
then
// Note the various referencing techniques.
modify ( f3 ) { value = f1.value + v2 };
System.out.println( s3 + " == " + f3.value );
end
modify 语句更新绑定到 f3 的 Fibonacci 对象的值。这意味着您现在有一个没有等于 -1 的新 Fibonacci 对象,这允许 "Calculate" 规则重新匹配并计算下一个 Fibonacci 号。
IDE 的 debug 视图或 审计 视图显示触发最后一个 "Bootstrap" 规则如何修改 Fibonacci 对象,启用 "Calculate" 规则匹配,然后修改另一个 Fibonacci 对象,以便 "Calculate" 规则再次匹配。这个过程会继续,直到为所有 Fibonacci 对象设置值。
图 85.10. 审计视图中的规则