OptaPlanner:Drools规则的连续轮班分配



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

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

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

如果我们可以假设一名员工每天只上一个班,shift.isConsecutiveDay()可能会被shift.day == $shift1.day + 1之类的东西取代,则可以使用exists

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不等式。

我使用了规则组合来实现这一点。第一条规则设置连续工作序列的开始,第二条规则设置结束,第三条规则创建";"工作顺序";适合在开始和结束之间。最后;最大连续天数";规则实际上检查您的";"工作顺序";对连续天数的限制。

这种模式实际上存在于护士名册示例中:https://github.com/kiegroup/optaplanner/blob/master/optaplanner-examples/src/main/resources/org/optaplanner/examples/nurserostering/solver/nurseRosteringConstraints.drl

最新更新