即时在 drools 文件中创建新地图 <String, String>
Create new Map<String, String> in drools file on the fly
场景:
根据一些规则奖励学生。在这里,每个学生都有资格获得多项奖励,例如分数为 80 的学生有资格获得 award_65 和 award_75。因此,在评估结果后,我想要一份学生有资格获得的奖项列表。
这个用例有点不切实际,但我试图对我的问题进行类比(不能post,因为它包含敏感信息)。
流口水的输入将通过以下方法返回:这些返回的对象列表将是流口水的事实。
List<Object> getDroolsFacts(Student student, List<StudentAward> studentAwards) {
..........
}
示例规则如下:
//Assuming all the imports are perfectly done
import java.util.*;
rule "award_65"
when
$Student: Student(status == "active" && marks > 65);
$studentAwards: List(); // DOUBT - I
Map<String, String> metadata = new HashMap<>(); // DOUBT - II
metadata.put("status", "active");
metadata.put("marks", "65");
then
final StudentAward studentAward = StudentAward.from("Award65" , metadata);
$studentAwards.add(studentAward);
end
rule "award_75"
when
$Student: Student(status == "active" && marks > 75);
$studentAwards: List(); // DOUBT - I
Map<String, String> metadata = new HashMap<>(); // DOUBT - II
metadata.put("status", "active");
metadata.put("marks", "75");
then
final StudentAward studentAward = StudentAward.from("Award75" , metadata);
$studentAwards.add(studentAward);
end
根据当前情况,产品中存在 DOUBT-I 行,并且我添加了与元数据相关的行。
如果学生有 80 分,那么根据当前流口水(即没有元数据相关行),我能够在结果列表 studentAwards
中获得两个对象。
DOUBT - I:(参考被称为 DOUBT-I 的代码片段)
$studentAwards: List();
是否对应于提供给 drools 的列表,还是正在创建的新列表?因为目前在评估规则后,我能够按预期获取其中的多个响应。
DOUBT - II:(参考 DOUBT-II 中提到的代码片段)
- MetaData 相关的 3 行是我新添加的它们不起作用。我想实现一个场景,我动态创建一个 HashMap 并添加一些数据,这些数据将被设置为
StudentAwards
对象的一部分。需要为每个规则创建新映射,并且将为每个学生对象执行多个规则,结果 studentAwards
包含所有适用的奖励。
- 那么如何为每个规则动态创建新的
Map<String, String>
并将其添加到正在创建的对象中?
你用一种有趣的方式来解决这个问题。您的规则不起作用的部分原因是您试图将结果放入条件部分。
我们可以将您的问题分解为以下内容。
给定:
- 一个学生,有状态和分数。
规则 1:
- 当 status = active 且分数 > 65 时,学生有资格获得 Award65。
规则 2:
- 当 status = active 且分数 > 75 时,学生有资格获得 Award75。
这很简单。
到目前为止,我们的规则如下所示:
rule "Student is eligible for Award65"
when
Student( status == "active", marks > 65 )
then
// TODO
end
rule "Student is eligible for Awards75"
when
Student( status == "active", marks > 75)
then
// TODO
end
到目前为止,还不错。
现在,我们如何实际举办“有资格获得 awardXX”派对?查看您的示例,您的规则输入包括 List<StudentAward>
;当学生符合条件时,我们将 StudentAward
的新实例添加到该列表中。 StudentAward 构造函数采用奖项名称和一些数据的映射。
我们现在可以更新上述规则中的 // TODO
评论来做到这一点:
rule "Student is eligible for Award65"
when
$awards: List()
Student( status == "active", marks > 65 )
then
Map<String, String> metadata = new HashMap<>();
metadata.put("status", "active");
metadata.put("marks", "65");
StudentAward studentAward = StudentAward.from("Award65" , metadata);
$awards.add(studentAward);
end
rule "Student is eligible for Awards75"
when
$awards: List()
Student( status == "active", marks > 75)
then
Map<String, String> metadata = new HashMap<>();
metadata.put("status", "active");
metadata.put("marks", "75");
StudentAward studentAward = StudentAward.from("Award75" , metadata);
$awards.add(studentAward);
end
就是这样。剩下的就是实际调用规则了。
public List<StudentAward> getAwardsForStudent(Student student) {
KieServices kieServices = KieServices.Factory.get();
KieContainer kContainer = kieServices.getKieClasspathContainer();
KieBase kBase = kContainer.getKieBase(kbaseName);
List<StudentAward> awards = new ArrayList<>();
KieSession session = kBase.newKieSession();
session.insert(student); // insert the Student
session.insert(awards); // insert the list of awards
session.fireAllRules();
return awards; // at this point, awards contains all of the values from the rules
}
就是这样。给定一个学生,我们执行规则并获得奖励列表。
你的规则唯一真正的问题是你在规则的错误一侧实例化元数据映射(这是规则结果的一部分,而不是条件),以及你如何获得奖励列表.
此答案中的规则有很多重复代码,但由于我们正在处理一个“玩具”示例,我不想浪费太多精力重构为共享函数。如果你确实使用了类似的东西,你会想看看你是否可以使用共享函数甚至继承来简化你的规则。
您问了两个具体问题。我唯一没有明确回答的是这个:
Does $studentAwards: List()
correspond to the list provided to drools or is it the new list getting created?
“when”子句中没有创建任何内容。那些是条件。这行是说“在工作内存中获取 List
并将其分配给变量 $studentAwards
。”
如果工作内存中有多个列表,就会出现问题,这就是为什么我通常建议不要将这样的集合放入内存中。我通常的建议是创建某种“结果”对象,其中包含您希望规则输出的计算数据。
请注意,在某些版本的 Drools 中,我在尝试使用参数化类型时遇到了错误——如果您遇到这种情况,请尝试使用 Map foo = new HashMap()
而不是 Map<String, String>
。我一直没弄清楚是什么原因导致了这个问题。
场景:
根据一些规则奖励学生。在这里,每个学生都有资格获得多项奖励,例如分数为 80 的学生有资格获得 award_65 和 award_75。因此,在评估结果后,我想要一份学生有资格获得的奖项列表。
这个用例有点不切实际,但我试图对我的问题进行类比(不能post,因为它包含敏感信息)。
流口水的输入将通过以下方法返回:这些返回的对象列表将是流口水的事实。
List<Object> getDroolsFacts(Student student, List<StudentAward> studentAwards) {
..........
}
示例规则如下:
//Assuming all the imports are perfectly done
import java.util.*;
rule "award_65"
when
$Student: Student(status == "active" && marks > 65);
$studentAwards: List(); // DOUBT - I
Map<String, String> metadata = new HashMap<>(); // DOUBT - II
metadata.put("status", "active");
metadata.put("marks", "65");
then
final StudentAward studentAward = StudentAward.from("Award65" , metadata);
$studentAwards.add(studentAward);
end
rule "award_75"
when
$Student: Student(status == "active" && marks > 75);
$studentAwards: List(); // DOUBT - I
Map<String, String> metadata = new HashMap<>(); // DOUBT - II
metadata.put("status", "active");
metadata.put("marks", "75");
then
final StudentAward studentAward = StudentAward.from("Award75" , metadata);
$studentAwards.add(studentAward);
end
根据当前情况,产品中存在 DOUBT-I 行,并且我添加了与元数据相关的行。
如果学生有 80 分,那么根据当前流口水(即没有元数据相关行),我能够在结果列表 studentAwards
中获得两个对象。
DOUBT - I:(参考被称为 DOUBT-I 的代码片段)
$studentAwards: List();
是否对应于提供给 drools 的列表,还是正在创建的新列表?因为目前在评估规则后,我能够按预期获取其中的多个响应。
DOUBT - II:(参考 DOUBT-II 中提到的代码片段)
- MetaData 相关的 3 行是我新添加的它们不起作用。我想实现一个场景,我动态创建一个 HashMap 并添加一些数据,这些数据将被设置为
StudentAwards
对象的一部分。需要为每个规则创建新映射,并且将为每个学生对象执行多个规则,结果studentAwards
包含所有适用的奖励。 - 那么如何为每个规则动态创建新的
Map<String, String>
并将其添加到正在创建的对象中?
你用一种有趣的方式来解决这个问题。您的规则不起作用的部分原因是您试图将结果放入条件部分。
我们可以将您的问题分解为以下内容。
给定:
- 一个学生,有状态和分数。
规则 1:
- 当 status = active 且分数 > 65 时,学生有资格获得 Award65。
规则 2:
- 当 status = active 且分数 > 75 时,学生有资格获得 Award75。
这很简单。
到目前为止,我们的规则如下所示:
rule "Student is eligible for Award65"
when
Student( status == "active", marks > 65 )
then
// TODO
end
rule "Student is eligible for Awards75"
when
Student( status == "active", marks > 75)
then
// TODO
end
到目前为止,还不错。
现在,我们如何实际举办“有资格获得 awardXX”派对?查看您的示例,您的规则输入包括 List<StudentAward>
;当学生符合条件时,我们将 StudentAward
的新实例添加到该列表中。 StudentAward 构造函数采用奖项名称和一些数据的映射。
我们现在可以更新上述规则中的 // TODO
评论来做到这一点:
rule "Student is eligible for Award65"
when
$awards: List()
Student( status == "active", marks > 65 )
then
Map<String, String> metadata = new HashMap<>();
metadata.put("status", "active");
metadata.put("marks", "65");
StudentAward studentAward = StudentAward.from("Award65" , metadata);
$awards.add(studentAward);
end
rule "Student is eligible for Awards75"
when
$awards: List()
Student( status == "active", marks > 75)
then
Map<String, String> metadata = new HashMap<>();
metadata.put("status", "active");
metadata.put("marks", "75");
StudentAward studentAward = StudentAward.from("Award75" , metadata);
$awards.add(studentAward);
end
就是这样。剩下的就是实际调用规则了。
public List<StudentAward> getAwardsForStudent(Student student) {
KieServices kieServices = KieServices.Factory.get();
KieContainer kContainer = kieServices.getKieClasspathContainer();
KieBase kBase = kContainer.getKieBase(kbaseName);
List<StudentAward> awards = new ArrayList<>();
KieSession session = kBase.newKieSession();
session.insert(student); // insert the Student
session.insert(awards); // insert the list of awards
session.fireAllRules();
return awards; // at this point, awards contains all of the values from the rules
}
就是这样。给定一个学生,我们执行规则并获得奖励列表。
你的规则唯一真正的问题是你在规则的错误一侧实例化元数据映射(这是规则结果的一部分,而不是条件),以及你如何获得奖励列表.
此答案中的规则有很多重复代码,但由于我们正在处理一个“玩具”示例,我不想浪费太多精力重构为共享函数。如果你确实使用了类似的东西,你会想看看你是否可以使用共享函数甚至继承来简化你的规则。
您问了两个具体问题。我唯一没有明确回答的是这个:
Does
$studentAwards: List()
correspond to the list provided to drools or is it the new list getting created?
“when”子句中没有创建任何内容。那些是条件。这行是说“在工作内存中获取 List
并将其分配给变量 $studentAwards
。”
如果工作内存中有多个列表,就会出现问题,这就是为什么我通常建议不要将这样的集合放入内存中。我通常的建议是创建某种“结果”对象,其中包含您希望规则输出的计算数据。
请注意,在某些版本的 Drools 中,我在尝试使用参数化类型时遇到了错误——如果您遇到这种情况,请尝试使用 Map foo = new HashMap()
而不是 Map<String, String>
。我一直没弄清楚是什么原因导致了这个问题。