如何在 Drools 文件中传递多个对象并提取所需的对象
How to pass multiple objects in a Drools file and extract the desired object
我是 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();
有多种方法可以从您的规则中获取数据。他们是:
- 使用 side-effects 调用操作。
- Set/modify 全局变量。
- 使用事实句柄从工作内存中提取数据。
第一个是最简单的,我建议这样做。第二个是我们在“过去”(大约 10 年前,使用 Drools 5)时的做法。最后一个在技术上是可行的,但非常复杂,我从未做过。
我已经在 this other question 的答案中涵盖了所有这些,我认为这是重复的,但不能投票给它,因为它没有被赞成的答案。
side-effects
的操作
这是执行此操作的推荐方法。具有副作用的动作是您所说的可以在规则之外看到的东西。一个极端的例子可能是保存到数据库,但一个更简单的例子可能是将 object 添加到列表中。
例如,考虑这种玩具情况。如果学生无故缺勤超过 3 次,则会生成一张便条,并随他们一起寄回家 parents。以下是我们可以对这种情况进行建模的两种方式。一条规则将注释添加到学生 object 本身的变量中。另一个规则调用实用程序函数将注释发送到 parents。第三个将规则添加到笔记集合中。
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
所有这些规则的工作方式是它们更改外部应用程序(邮件系统)或输入 objects(学生或笔记列表)中的数据。规则触发后,这些副作用将对外界可见。
全局变量
这是老办法,全局变量。它们 通常 与 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
触发所有规则后,您传递到全局的 object 将添加值。请注意,保留对 object 的引用很重要——不要调用 session.setGlobal("notes", new ArrayList<>())
之类的东西!这样你就不会引用那个笔记列表了。
KieSession javadoc 讨论了一些全局变量以及一些注意事项。
第三种方法是使用事实句柄提取数据。这没有很好的记录,我也没有亲自做过,但它应该是可能的。通常它用于对传递到工作内存的数据保留一个“句柄”,以便您可以将其取出进行单元测试或诸如此类的东西。我认为可以定位并提取您新实例化的数据。
就我个人而言,我不会走这条路,因为它不是标准的工作流程,而且与 Drools 库的其他部分相比,围绕这些 API 的文档很差(因为这主要用于内部和测试。)
我是 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();
有多种方法可以从您的规则中获取数据。他们是:
- 使用 side-effects 调用操作。
- Set/modify 全局变量。
- 使用事实句柄从工作内存中提取数据。
第一个是最简单的,我建议这样做。第二个是我们在“过去”(大约 10 年前,使用 Drools 5)时的做法。最后一个在技术上是可行的,但非常复杂,我从未做过。
我已经在 this other question 的答案中涵盖了所有这些,我认为这是重复的,但不能投票给它,因为它没有被赞成的答案。
side-effects
的操作这是执行此操作的推荐方法。具有副作用的动作是您所说的可以在规则之外看到的东西。一个极端的例子可能是保存到数据库,但一个更简单的例子可能是将 object 添加到列表中。
例如,考虑这种玩具情况。如果学生无故缺勤超过 3 次,则会生成一张便条,并随他们一起寄回家 parents。以下是我们可以对这种情况进行建模的两种方式。一条规则将注释添加到学生 object 本身的变量中。另一个规则调用实用程序函数将注释发送到 parents。第三个将规则添加到笔记集合中。
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
所有这些规则的工作方式是它们更改外部应用程序(邮件系统)或输入 objects(学生或笔记列表)中的数据。规则触发后,这些副作用将对外界可见。
全局变量
这是老办法,全局变量。它们 通常 与 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
触发所有规则后,您传递到全局的 object 将添加值。请注意,保留对 object 的引用很重要——不要调用 session.setGlobal("notes", new ArrayList<>())
之类的东西!这样你就不会引用那个笔记列表了。
KieSession javadoc 讨论了一些全局变量以及一些注意事项。
第三种方法是使用事实句柄提取数据。这没有很好的记录,我也没有亲自做过,但它应该是可能的。通常它用于对传递到工作内存的数据保留一个“句柄”,以便您可以将其取出进行单元测试或诸如此类的东西。我认为可以定位并提取您新实例化的数据。
就我个人而言,我不会走这条路,因为它不是标准的工作流程,而且与 Drools 库的其他部分相比,围绕这些 API 的文档很差(因为这主要用于内部和测试。)