Drools性能实践总结
本文总结一下Drools的性能提升要点。
要点
选择
7.5
以后的版本。老版本存在一个性能BUG。KnowledgeBuilder很耗时,编译结果要缓存起来。这样
builder
就不会成为瓶颈。kbase过大,会导致内存消耗过多,gc也可能成为瓶颈。建议按规则相关性拆分为多个Kbase。但需要注意,如果一个kbase里的规则数太少,那么无法发挥drools的优势,跟你自己写
if-else
没啥差别。所以拆分的重点是规则相关性,而不是数量。drools的体系注定其更适应增加rule数,而不是增加fact数。在使用时牢记此点。另外,最极端的情况,使用一个通用类去表达所有的
fact
,会增加beta节点向左侧匹配值的次数,也会导致性能下降,并降低规则可读性。尽量减少
data
或fact
的碎片化,尽量在同一个session
中仅包含相关fact
和相关rule
。在创建session
时,将所有fact
批量insert
到session
中,然后fire
比为每个fact
单独触发规则更为可取。在调用insert()之前准备好数据远远胜过在LHS里去访问数据库获取数据,这种做法可以显著提高性能。
规则之间,不要耦合。
多
insert
,少from
。避免在
then
段落中对fact做约束,约束要提前到when
中
// 错误示范 |
- 建议使用属性访问而不是显式使用
getter
,因为前者可以通过字段索引提高性能。
// 错误示范 |
- 尽量使用
,
,而不是&&
。drools对前者有更好的性能优化。但,
不能用于带括号的组合条件中。
// 错误示范 |
- 使用fact属性传递约束优于使用变量传递约束,因为
==
赋值非常高效。(可以用到哈希索引)
Person( age == $firstAge ) |
- 如果一个POJO的属性可能在drools里被修改(
modify
方法),但你不期待这个属性修改触发规则的重新匹配。那么加上@ClassReactive
注解,这将有助于提高性能和递归。
// Java里 |
- 避免在drools里使用方言去
accumulate
。原因有几个,包括在维护和测试使用它们的规则时遇到困难,以及无法重用该代码。实现自己的累积函数非常简单,它们易于单元测试和使用。这种形式的累积只支持向后兼容。
// 这是一个使用java方言实现累计的例子。(不建议) |
- 善用窗口,实现基于流的小批处理。
declare window Ticks |
- 谨慎使用嵌套访问,很可能就是性能陷阱。
# 嵌套访问示例 |
- 不要过度使用eval,因为它会降低规则的声明性,从而导致引擎性能不佳。eval不能被索引,因此不如字段约束有效。
p1 : Parameter() |
- 在编写规则时,遵循将区隔度最大的节点放在最前面,以降低计算量。
END
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 LeFer!
评论