如何解决寻找检查 Drools 与 Facts 交互的方法
我正在将类似 pojo 的对象/事实插入 KieSession 并具有与这些对象交互的规则。触发所有规则后,我希望能够检查规则访问了哪些对象及其方法。从概念上讲,这类似于模拟。
我尝试使用 Mockito 并将模拟对象插入 kieSession。我能够得到一个被调用的方法列表,但似乎并不是所有的交互都出现了。 不确定这是 Mockito 的限制,还是与 Drools 管理事实和生命周期的方式有关,从而打破了模拟。
也许有更好的方法来实现这一点?
更新: 推理 - 我们有一个应用程序执行各种规则集。应用程序提供所有数据,但每个规则集只需要数据的一些子集。在某些监控需求中,我们希望准确查看给定规则集访问了哪些数据(对事实对象调用 getter)。
解决方法
您问题的这一部分表明您(或更可能是您的管理层)从根本上不了解基本的 Drools 生命周期:
推理 - 我们有一个应用程序执行各种规则集。应用程序提供所有数据,但每个规则集只需要数据的一些子集。在某些监控需求中,我们希望准确查看给定规则集访问了哪些数据(对事实对象调用 getter)。
以下是对其工作原理的非常简化的解释。更详细的解释会超出 StackOverflow 上答案字段的字符限制。
当您在 Drools 中调用 fireAllRules
时,规则引擎进入一个称为“匹配”的阶段,即它决定实际运行哪些规则时。首先,规则引擎根据您的特定规则集(通过显着性、自然顺序等)对规则进行排序,然后遍历此规则列表并执行左侧(LHS;又名“when 子句”或“条件”)仅用于确定规则是否有效。在每条规则的 LHS 上,每条语句都按顺序执行,直到任何一条语句都不为真。
在 Drools 检查了所有规则的 LHS 后,它进入“执行”阶段。在这一点上,它决定要触发的所有规则都被执行。使用匹配阶段的相同顺序,它遍历每个规则,然后执行规则右侧的语句。
当您考虑到 Drools 支持继承时,事情变得更加复杂,因此规则 B 可以扩展规则 A,因此规则 A 的 LHS 中的语句将在匹配阶段执行两次——一次是在引擎评估是否可以触发规则 B,并且在引擎评估它是否可以触发规则 A 时也会触发一次。
这进一步复杂,因为您可以通过使用右侧的特定关键字(RHS;又名“then 子句”或“后果”)从执行重新进入匹配阶段") 规则 -- 特别是通过调用 update
、insert
、modify
、retract
/delete
等。其中一些关键字如 {{1 }} 将重新评估规则的一个子集,而 insert
等其他规则将在第二个匹配阶段重新评估所有单词。
我在本次讨论中将重点放在 LHS 上,因为您的声明是这样说的:
有一些监控需求,我们希望确切地查看访问了哪些数据(在事实对象上调用 getter)....
除非您有一些非常不标准的规则,否则您的大多数吸气剂都应该在您的 LHS 上。您应该在此处获取数据并进行比较/检查/决定是否应触发规则。
希望知道为什么要知道触发了哪些“get”调用的请求是有意义的——因为在匹配阶段我们将触发大量的“get”调用和然后忽略结果,因为 LHS 的其他部分不评估为真。
我确实考虑过我们可能在这里遇到了通信问题,而实际需要的是知道哪些数据实际上用于执行 (RHS)。在这种情况下,您应该按照我在评论中的建议使用监听器。如果您编写一个挂钩到 Drools 生命周期的侦听器,特别是在执行阶段(AgendaEventListener 的 update
)。此时,您知道规则匹配并实际执行,因此您可以记录或记录规则名称和详细信息。由于您知道每个规则需要和使用的确切数据,因此您可以跟踪实际使用的数据。
说了这么多,我发现这部分是根据我以前的经验:
应用程序提供所有数据,但每个规则集只需要数据的一部分。
我工作的公司采用了这种方法——我们通过将所有内容添加到工作记忆中,使所有数据可用于所有规则。我们的想法是,如果所有数据都可用,那么我们就可以在不更改支持代码的情况下编写规则,因为您将来可能需要的任何数据都已经存在于工作内存中。
当我们有小数据时,这证明是可以的,但是随着公司和产品的增长,这些数据也在增长,我们的规则开始需要大量内存来支持工作内存(尤其是当我们的通话量增加时,因为我们需要为每个规则请求分配更大的堆。)因为我们使用性能极差的对象传递到工作内存(即 HashMap 和扩展了 HashMap 的对象)这一事实,情况更加恶化。
鉴于此,您应该强烈考虑重新考虑您的策略。一旦我们修剪了我们传递到规则中的数据,减少了数量并将结构更改为高性能 POJO,我们不仅看到了资源使用(主要是堆)的大幅减少,而且我们还看到了在更大程度上的性能提升规则吞吐量,因为规则引擎不需要继续处理和评估工作内存中那些海量且低效的数据。
最后,关于你在工作内存中模拟对象的问题——我强烈警告不要尝试这样做。真的不应该在生产代码中使用模拟库。大多数模拟通过利用反射和字节码操作的组合来工作。工作内存中的数据不能保证保持在它传入的初始状态——它在过程中的不同点被序列化和反序列化,所以根据你的特定模拟库的实现方式,你可能会失去“访问” " 到特定的模拟实例,而您的规则将针对该序列化/反序列化过程中的功能等效副本。
虽然我从未在这种情况下尝试过,但如果您真的想检测您的 getter 方法,您可以使用方面。不过,您在那里遇到同样问题的可能性不可忽视。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。