寻找检查 Drools 与 Facts 交互的方法

Looking for way of inspecting Drools interactions with Facts

我正在向 KieSession 中插入类似 pojo 的 objects/facts 并具有与这些对象交互的规则。在触发所有规则后,我希望能够检查规则访问了哪些对象及其方法。在概念上,这类似于模拟。

我尝试使用 Mockito 并将模拟对象插入到 kieSession 中。我能够获得被调用的方法列表,但似乎并非所有交互都显示出来。 不确定这是 Mockito 的限制还是关于 Drools 如何管理打破模拟的事实和生命周期。

也许有更好的方法来完成这个?

更新: 推理 - 我们有一个执行各种规则集的应用程序。应用程序提供所有数据,但每个规则集只需要部分数据。有一些监控需求,我们希望通过给定的规则集准确查看访问了哪些数据(在事实对象上调用 getter)。

这部分问题表明您(或者更可能是您的管理层)根本不了解基本的 Drools 生命周期:

Reasoning - we have an application executing various rule sets. Application makes available all of data but each rule set needs only some subset of the data. There are some monitoring needs where we want to see exactly what data was accessed (getters called on fact objects) by given rule set.

以下是对其工作原理的非常简单的解释。更详细的解释将超出 Whosebug 上答案字段的字符限制。

当您在 Drools 中调用 fireAllRules 时,规则引擎会进入一个称为“匹配”的阶段,即决定哪些规则实际上将成为 运行。首先,规则引擎根据您的特定规则集(通过显着性、自然顺序等)对规则进行排序,然后遍历此规则列表并执行左侧(LHS;又名“when 子句”或“条件”)只是为了确定规则是否有效。在每个规则的 LHS 上,每个语句按顺序执行,直到任何单个语句的计算结果都不为真。

在 Drools 检查了所有规则的 LHS 之后,它进入“执行”阶段。在这一点上,它决定有效触发的所有规则都被执行。使用匹配阶段的相同顺序,遍历每个规则,然后执行规则右侧的语句。

当您考虑到 Drools 支持继承时,事情变得更加复杂,因此规则 B 可以扩展规则 A,因此规则 A 的 LHS 中的语句将在匹配阶段执行两次 -- 一次在引擎评估时它是否可以触发规则 B,并且在引擎评估它是否可以触发规则 A 时也会触发一次。

进一步 变得复杂,因为您可以通过使用右侧的特定关键字(RHS;又名“then”)从执行中重新进入匹配阶段规则的条款”或“后果”)——特别是通过调用 updateinsertmodifyretract/delete 等。其中一些insert 等关键字将重新评估规则的子集,而 update 等其他关键字将在第二个匹配阶段重新评估所有单词。

我在本次讨论中重点关注了 LHS,因为您的陈述是:

There are some monitoring needs where we want to see exactly what data was accessed (getters called on fact objects) ....

你的大部分 getters 应该在你的 LHS 上,除非你有一些非常不标准的规则。这是您应该获取数据并就是否应触发您的规则做出 comparisons/checks/making 决定的地方。

希望知道为什么知道触发了哪些“get”调用的请求没有任何意义——因为在匹配阶段我们将触发大量的“get”调用调用然后忽略结果,因为 LHS 的某些其他部分未评估为真。


我确实考虑过我们这里可能存在通信问题,实际需要知道哪些数据实际用于执行 (RHS)。在这种情况下,您应该按照我在评论中的建议使用监听器。如果您编写一个挂接到 Drools 生命周期的侦听器,特别是挂接到执行阶段(AgendaEventListenerafterMatchFired)。此时,您知道规则匹配并实际执行了,因此您可以记录或记录规则名称和详细信息。由于您知道每个规则需要和使用的确切数据,这将允许您跟踪实际使用的数据。


综上所述,我发现这部分与我以前的经验有关:

Application makes available all of data but each rule set needs only some subset of the data.

我工作的公司采用了这种方法——我们通过将 everything 添加到工作内存中,使所有数据对所有规则可用。这个想法是,如果所有数据都可用,那么我们就可以在不更改支持代码的情况下编写规则,因为您将来可能需要的任何数据都已经在工作内存中可用。

事实证明,当我们的数据量较小时,这还可以,但随着公司和产品的发展,这些数据也会增长,我们的规则开始需要大量内存来支持工作内存(尤其是当我们的通话量增加时,因为我们需要为每个规则请求分配更大的堆。)由于我们使用性能极差的对象传递到工作内存——即 HashMap 和扩展 HashMap 的对象——这一事实加剧了这种情况。

鉴于此,您应该强烈考虑重新考虑您的策略。一旦我们修剪了我们传递给规则的数据,减少了数据量并将结构更改为高性能 POJO,我们不仅看到资源使用(主要是堆)的大幅减少,而且我们还看到了更大的性能改进规则吞吐量,因为规则引擎不需要继续处理和评估工作内存中那些海量和低效的数据。


最后,就您提出的关于在工作内存中模拟对象的问题而言——我强烈警告不要尝试这样做。模拟库真的不应该在生产代码中使用。大多数模拟通过利用反射和字节码操作的组合来工作。工作内存中的数据不能保证保持在传入时的初始状态——它会在过程中的不同点进行序列化和反序列化,因此根据您的特定模拟库的实现方式,您可能会失去“访问权限” " 到特定的模拟实例,而您的规则将针对来自该 serialization/deserialization 进程的功能等效副本起作用。

虽然我从未在这种情况下尝试过,但如果您真的想检测 getter 方法,您可以使用方面。不过,您很有可能 运行 遇到同样的问题。