如何从OptaPlanner中的解决方案访问汇总结果

时间:2019-05-27 17:35:01

标签: java drools optaplanner

问题

我想用口水法则评估解决方案的总价值。例如,在学校日程安排中,员工每周不得超过40小时。如何使用TimeGrain模式在约束中实现此方案?

实验

我已经使用EasyScoreCalculator和Drools对这种情况进行了两种实现(请参见下面的代码)。关系模型如下所示: model

  1. 计划代表一个星期。

  2. getTotalHours(...)方法返回一周中计划的总小时数。

EasyScoreCalculator

    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中获得此案例的方案汇总结果?

1 个答案:

答案 0 :(得分:2)

在流口水中,您可以使用要对特定老师进行分组的累加(我假设您的Teacher对象中有一个ID,因此您可以按特定老师进行分组,并在ScheduleTime中安排一分钟) 。这是有关累积http://blog.athico.com/2009/06/how-to-implement-accumulate-functions.htmlhttps://docs.jboss.org/drools/release/6.2.0.Final/drools-docs/html/ch07.html(搜索“累积”)的更详细的文章。此检查将在所有Teacher实例上执行。

当教师的作业总数大于40小时时,应匹配“何时”条件。由于条件已在“时间”中进行过滤,因此无需将条件放在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);

`