如何解决如何在 Drools 文件中传递多个对象并提取所需的对象
我真的是 Drools 的新手。对于一个项目,我试图将多个对象传递到 drl 文件中,但我不知道如何在同一规则中处理多个对象!
这是我的流口水逻辑:
rule "SNAP when Employed"
when
citizenDataObject: CitizenData(planName=="SNAP" && employed==true)
then
PlanData planDataObject= new PlanData();
planDataObject.setPlanStatus("DN");
planDataObject.setDenialReason("Salaried Employee");
end
当我执行此规则时,我无法检索 planDataObject。
在java端,我传递CitizenData对象和PlanData对象:
WorkingMemory workingMemory = ruleBase.newStatefulSession();
workingMemory.insert(citizenData);
workingMemory.insert(planData);
workingMemory.fireAllRules();
解决方法
有多种方法可以从规则中获取数据。它们是:
- 调用具有副作用的操作。
- 设置/修改全局变量。
- 使用事实句柄从工作内存中提取数据。
第一个是最简单的,也是我建议做的。第二个是我们在“旧时代”(大约 10 年前,使用 Drools 5)过去的做法。最后一个在技术上可能但非常复杂,我从未做过。
我已在对 this other question 的回答中涵盖了所有这些内容,我认为它是重复的,但由于没有赞成的答案,因此无法投票。
有副作用的动作
这是推荐的方法。具有副作用的操作是您调用的可以在规则之外看到的操作。一个极端的例子可能是保存到数据库,但一个更简单的例子可能是将一个对象添加到列表中。
以这个玩具情况为例。如果学生有超过 3 次无故缺勤,则会生成一张便条并将其寄回家给父母。以下是我们可以对这种情况进行建模的两种方式。一个规则是将注释添加到学生对象本身的变量中。另一个规则调用一个效用函数将笔记发送给父母。第三个将规则添加到笔记集。
rule "Unexcused absences: notify by adding note to the student record"
when
$student: Student( absences >= 3,$name: name )
then
$student.addNote( "Student '" + $name + "' has had too many unexcused absences");
end
rule "Unexcused absences: notify by email"
when
$student: Student( absences >= 3,$name: name )
$emailSystem: MailSystem() // Some utility class which can send emails
then
$emailSystem.sendNote(
$student,"Student '" + $name + "' has had too many unexcused absences"
);
end
rule "Unexcused absences: append note to a list"
when
Student( absences >= 3,$name: name )
$notes: List()
then
$notes.add("Student '" + $name + "' has had too many unexcused absences.");
end
所有这些规则的工作方式是它们更改外部应用程序(邮件系统)或输入对象(学生或笔记列表)中的数据。规则生效后,这些副作用将被外界看到。
全局变量
这是旧的做事方式,全局变量。它们通常与 Java 中的静态变量相同,但您不能依赖它们来跟踪规则执行之间的数据。 (就像静态变量和线程一样,规则可见的数据有点复杂。)
但如果我们只想跟踪规则输出,这是一个可行的替代方案。
首先,在调用如下规则之前,您针对会话设置了一个全局变量:
KieSession session = ruleBase.newStatefulSession();
session.insert(...); // insert data
session.setGlobal( "myGlobalFoo",value ); // sets the global; note the name must match the rule file!
session.fireAllRules();
然后在您的规则文件中,您将使用 global
关键字在文件顶部、导入下方声明您的全局变量。您的全局名称必须与您传递给 setGlobal
方法的名称完全匹配。
使用与之前相同的示例(缺勤 3 次以上的学生收到一封寄回家的便条),我们可以使用如下全局变量。在第一个示例中,我们可以使用 List<string> notes
发送回家的笔记,并将其设置为全局:
global List notes;
rule "Student absences: add note to global List"
when
Student( absences >= 3,$name: name )
then
notes.add("Student '" + $name + "' has been absent too many times!");
end
一旦所有规则都被触发,你传递给全局的对象就会添加值。请注意,保留对对象的引用很重要——不要调用 session.setGlobal("notes",new ArrayList<>())
之类的东西!那样你就不会参考那个笔记列表。
KieSession javadoc 谈到了一些全局变量以及一些注意事项。
第三种方法是使用事实句柄提取数据。这没有得到很好的记录,我也没有亲自做过,但应该是可能的。通常它用于保持对传递到工作内存的数据的“句柄”,以便您可以将其取出用于单元测试或诸如此类。我认为有可能定位并提取您新实例化的数据。
我个人不会走这条路,因为它不是标准的工作流程,而且与 Drools 库的其他部分相比,围绕这些 API 的文档很差(因为这主要用于内部和测试。)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。