如何从 OptaPlanner 中的解决方案访问聚合结果
How to access an aggregate result from a solution in OptaPlanner
问题
我想评估流口水规则中解决方案的聚合值。例如,在学校调度场景中,员工每周工作时间不得超过 40 小时。我如何使用 TimeGrain 模式在约束中实现这种情况?
实验
我已经使用 EasyScoreCalculator 和 Drools 实现了这个场景的两个实现(参见下面的代码)。关系模型如下所示:
时间表代表一周。
方法 getTotalHours(...) returns 一周内安排的总小时数。
简易分数计算器
public HardSoftScore calculateScore(Schedule schedule) {
int hardScore = 0;
int softScore = 0;
int maxTimePerWeek = 40;
for (Teacher teacher : schedule.getTeachers()) {
int totalDuration = Schedule.getTotalHours(schedule.getScheduleTimes(),teacher);
System.out.println("totalDuration for teacher: " + totalDuration);
if(totalDuration > maxTimePerWeek)
softScore += totalDuration - maxTimePerWeek;
}
return HardSoftScore.of(hardScore, softScore);
}
流口水
rule "Teacher should have max 40 hours"
when
ScheduleTime(teacher != null, $teacher : teacher)
Schedule($scheduleTimes: scheduleTimes)
then
int totalDuration = Schedule.getTotalHours($scheduleTimes, $teacher);
System.out.println("totalDuration for teacher: " + totalDuration);
if( totalDuration > 40){
scoreHolder.penalize(kcontext, totalDuration - 40);
}
end
流口水文件已正确配置,因为其他约束正常工作。
结果
第一个解决方案运行良好,但根据文档,EasyScoreCalculator 可能会导致性能问题。
第二个不起作用,因为控制台输出永远不会执行。但是,如果我删除 Schedule($scheduleTimes: scheduleTimes)
和相关代码,则会执行 "then" 子句。如何在 Drools 中获取此案例场景的聚合结果?
在 drools 中,你可以使用 accumulate 来对特定的老师进行分组(我假设你的 Teacher 对象中有一个 id,这样你就可以按特定的老师分组,并在你的计划时间)。这是关于累积 http://blog.athico.com/2009/06/how-to-implement-accumulate-functions.html and https://docs.jboss.org/drools/release/6.2.0.Final/drools-docs/html/ch07.html 的更详细的文章(搜索 "accumulate")。此检查将在所有 Teacher 实例上执行。
当教师的作业总时长超过 40 小时时,应匹配 "when" 条件。在"when"中已经过滤掉了,就不用在then中放条件了。
`
什么时候
$teacher : 教师( $tId:id != null)
$totalMinutes: Long(longValue > 40 * 60 )
accumulate(
ScheduleTime(
teacher != null,
teacher.id == $tId
),sum(minutes)
)
then
System.out.println("totalDuration for teacher: " + $totalMinutes/60);
scoreHolder.penalize(kcontext, $totalMinutes/60- 40);
`
问题
我想评估流口水规则中解决方案的聚合值。例如,在学校调度场景中,员工每周工作时间不得超过 40 小时。我如何使用 TimeGrain 模式在约束中实现这种情况?
实验
我已经使用 EasyScoreCalculator 和 Drools 实现了这个场景的两个实现(参见下面的代码)。关系模型如下所示:
时间表代表一周。
方法 getTotalHours(...) returns 一周内安排的总小时数。
简易分数计算器
public HardSoftScore calculateScore(Schedule schedule) {
int hardScore = 0;
int softScore = 0;
int maxTimePerWeek = 40;
for (Teacher teacher : schedule.getTeachers()) {
int totalDuration = Schedule.getTotalHours(schedule.getScheduleTimes(),teacher);
System.out.println("totalDuration for teacher: " + totalDuration);
if(totalDuration > maxTimePerWeek)
softScore += totalDuration - maxTimePerWeek;
}
return HardSoftScore.of(hardScore, softScore);
}
流口水
rule "Teacher should have max 40 hours"
when
ScheduleTime(teacher != null, $teacher : teacher)
Schedule($scheduleTimes: scheduleTimes)
then
int totalDuration = Schedule.getTotalHours($scheduleTimes, $teacher);
System.out.println("totalDuration for teacher: " + totalDuration);
if( totalDuration > 40){
scoreHolder.penalize(kcontext, totalDuration - 40);
}
end
流口水文件已正确配置,因为其他约束正常工作。
结果
第一个解决方案运行良好,但根据文档,EasyScoreCalculator 可能会导致性能问题。
第二个不起作用,因为控制台输出永远不会执行。但是,如果我删除 Schedule($scheduleTimes: scheduleTimes)
和相关代码,则会执行 "then" 子句。如何在 Drools 中获取此案例场景的聚合结果?
在 drools 中,你可以使用 accumulate 来对特定的老师进行分组(我假设你的 Teacher 对象中有一个 id,这样你就可以按特定的老师分组,并在你的计划时间)。这是关于累积 http://blog.athico.com/2009/06/how-to-implement-accumulate-functions.html and https://docs.jboss.org/drools/release/6.2.0.Final/drools-docs/html/ch07.html 的更详细的文章(搜索 "accumulate")。此检查将在所有 Teacher 实例上执行。
当教师的作业总时长超过 40 小时时,应匹配 "when" 条件。在"when"中已经过滤掉了,就不用在then中放条件了。 ` 什么时候 $teacher : 教师( $tId:id != null)
$totalMinutes: Long(longValue > 40 * 60 )
accumulate(
ScheduleTime(
teacher != null,
teacher.id == $tId
),sum(minutes)
)
then
System.out.println("totalDuration for teacher: " + $totalMinutes/60);
scoreHolder.penalize(kcontext, $totalMinutes/60- 40);
`