首页 > 解决方案 > OptaPlanner:Drools 对连续班次分配的规则

问题描述

上下文是使用 Drools 规则计算分数的 OptaPlanner 的员工轮班分配。我的员工不能连续工作超过三天而没有休息日。我非常愚蠢地实现了这样的约束:

rule "No more than three consecutive working days"
    when
        ShiftAssignment(
            $id1 : id,
            $empoloyee : empoloyee != null,
            $shift1 : shift
            )
        ShiftAssignment(
            id > $id1,
            empoloyee == $empoloyee,
            shift.isConsecutiveDay($shift1),
            $id2 : id,
            $shift2 : shift
            )
        ShiftAssignment(
            id > $id2,
            empoloyee == $empoloyee,
            shift.isConsecutiveDay($shift2),
            $id3 : id,
            $shift3 : shift
            )
        ShiftAssignment(
            id > $id3,
            empoloyee == $empoloyee,
            shift.isConsecutiveDay($shift10)
            )
    then
        scoreHolder.penalize(kcontext);
end

我希望方法/变量的名称清楚地揭示了它们的作用/含义。有没有更方便、更智能的方式来实现这样的规则?请记住,上面的三天可能需要更改为更大的数字(我使用三天来避免规则中更现实的十行或更多行代码)。谢谢。

标签: droolsoptaplanner

解决方案


如果我们可以假设员工每天最多轮班,并且shift.isConsecutiveDay()可以用类似的东西代替shift.day == $shift1.day + 1exists可以使用:

when
    ShiftAssignment($employee : empoloyee != null, $shift1 : shift)
    exists ShiftAssignment(employee == $employee, shift.day == $shift1.day + 1)
    exists ShiftAssignment(employee == $employee, shift.day == $shift1.day + 2)
    exists ShiftAssignment(employee == $employee, shift.day == $shift1.day + 3)
then

如果无法做出这样的假设,您的解决方案应该可行,并考虑一个潜在的极端情况:

该规则试图按条件过滤掉相同班次的组合id > $id1。此条件有效,但 ID 必须在班次时按升序生成,否则会与shift.isConsecutiveDay(...). 如果无法保证此属性,则最好检查 ID 不等式。


推荐阅读