Drools中eval的正确打开姿势

个人博客地址:http://www.ltang.me/2020/04/23/using-eval-in-drools/

前面在做drools规则设计和测试时,发现一个很坑爹的现象,当LHS的某一行存在eval短句时,or短路就不生效了。具体情况如下例子。

我写了一个简单的例子:

import java.util.*;

global me.tangliu.drools.Test test;

rule "rule01"
when
    Map(this["A"] == 1000) || eval(test.testBoolean())
then
    System.out.println("reaching then");
end

我期望的时,当A == 1000时,直接跳转到RHS语句(then部分),而不需要执行test.testBoolean()(or短路),可是运行结果如下所示:

9:51:10.801 [main] DEBUG org.drools.compiler.kie.builder.impl.KieRepositoryImpl - Cannot load a KieRepositoryScanner, using the DummyKieScanner
19:51:11.096 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES
going into test boolean
reaching then
19:51:11.112 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING
19:51:11.112 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE
19:51:11.112 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED

going into test boolean 是在testBoolean方法中打印的日志,说明当前面this["A"] == 1000满足时,及时你写的是or,后面的判断依然会执行,or短路并未生效

这跟我预期的不一样啊!既然or短路不生效,那么and短路呢?我修改语句如下:

import java.util.*;

global me.tangliu.drools.Test test;

rule "rule01"
when
    Map(this["A"] == 1000) && eval(test.testBoolean())
then
    System.out.println("reaching then");
end

将A的值修改为99再去跑规则,发现test.testBoolean()不会执行了,说明and短路生效了

反复的做实验,发现,当同一行存在一个或多个eval()判断的时候,如果是or的关系,那么所有eval中的判断都会执行,并且,每次执行完一次判断,若满足条件,RHS都会执行。如下:

rule "rule01"
when
    Map(this["A"] == 1000) || eval(test.testBoolean()) || eval(test.testBoolean2())
then
    System.out.println("reaching then");
end

跑规则的结果是:

going into test boolean
reaching then
reaching then
going into test boolean 2
reaching then

但是,假如使用的不是or链接,而是and链接,那么短路是能生效的,这究竟是为什么呢?google了各种问答,能搜到不多的一些说明,如下:

The CE eval is essentially a catch-all which allows any semantic code (that returns a primitive boolean) to be executed. This code can refer to variables that were bound in the LHS of the rule, and functions in the rule package. Overuse of eval reduces the declarativeness of your rules and can result in a poorly performing engine. While eval can be used anywhere in the patterns, the best practice is to add it as the last conditional element in the LHS of a rule.
Evals cannot be indexed and thus are not as efficient as Field Constraints. However this makes them ideal for being used when functions return values that change over time, which is not allowed within Field Constraints.

val is very convenient as it allows us to include pretty much any condition in a rule. However, it’s considerably slower. With other conditions, Drools can cache (remember) the results because it can figure out when these results need to change. With eval, Drools doesn’t have this visibility. Therefore, all eval expressions need to be rechecked every time the rule is true. If you have to use eval, it’s best to add it as the last condition in a rule—meaning, it will be called less often. If any of the previous conditions return ‘false’, then Drools shortcuts, because there is no need to check any of the remaining conditions.

看起来都只是说了两点:

  1. eval很灵活,可以自定义方法调用来做条件判断
  2. eval效率低(因为无法缓存结果),因此尽量放在多个条件的最后

但是好像无法解答为啥短路语法不生效。再多看几篇关于drools语法规则的文档,我的理解如下:

我对drools的LHS的语义理解不对,它不像我们的java或者其他代码中的语法,它其实可以理解为:每一行是一个条件(条件间使用and链接),每一个条件是由多个约束组成的对一个对象的完整的约束,不应该在一行里面存在对多个对象的约束判断。换句话说,如果eval不是用在内联约束(inline expression),而是用在条件,那么,一行应该只有一个eval。具体来说,我们的语法应该是:

when
	eval( A() || B() )
then

而不应该是

when 
	eval( A()) || eval( B())
then

因此,最初的例子,我们可以改写为:

rule "rule01"
when
    $m: Map()
    eval( Integer.valueOf((String)$m.get("A")) == 1000  || test.testBoolean())
then
    System.out.println("reaching then");
end

这样就能达我们的期望,当A==1000时,testBoolean不需要再执行判断了。不过,这样就需要在代码里做好类型转换,很麻烦,因此改成下面这种写法,由drools自己去做转换,且可以走缓存,有可能提高效率:

import function testBoolean(){
		return me.ltang.drools.Test.testBoolean();
}
rule "rule01"
when
    Map(this["A"] == 1000 || eval(testBoolean()))
then
    System.out.println("reaching then");
end

最后达到的结果是一样的,但这种方式明显更好更合适。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Drools是一个开源的规则引擎,它提供了一种强大的方式来管理和执行业务规则。Drools文文档是一份关于Drools规则引擎文说明文档。 Drools文文档内容丰富全面,涵盖了Drools的基本概念、核心功能以及使用方法等方面的知识。文档开头介绍了Drools的发展背景和优势,让用户对规则引擎有一个整体的了解。 接下来,文档详细介绍了Drools的安装和配置方法,包括如何下载和安装Drools的各种版本,以及如何配置开发环境和运行时环境等。 文档还详细介绍了Drools的核心概念,如规则、事实、条件、动作等,以及它们在Drools的表示和使用方式。特别是对于Drools规则的编写和调试,文档提供了大量的示例代码和实践经验,帮助用户更好地理解和应用规则引擎。 此外,文档还介绍了Drools的高级功能,如规则的冲突解决、规则的动态修改和重载、规则的优化等。它还说明了如何在实际项目使用Drools来实现复杂的业务逻辑和规则。 总的来说,Drools文文档提供了完整而易懂的Drools规则引擎的相关知识,适合初学者和有一定经验的用户阅读和学习。无论是想了解规则引擎的基本概念,还是希望实际应用Drools构建规则引擎,该文档都是一个很好的参考资料。它的文说明和丰富的示例代码可以帮助用户更好地理解和应用Drools规则引擎,提高系统的可维护性和扩展性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值