You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OptaPlanner员工排班:优先填充Priority 1班次方案咨询

实现OptaPlanner中Priority 1班次优先于Priority 2班次分配的约束方案

需求明确

核心目标:

  • Priority 1(对应代码中的SCHEDULED_SHIFT)班次必须优先完成分配
  • 仅当所有Priority 1班次已分配员工后,才能开始分配Priority 2(ALTERNATE_SHIFT)班次

现有方案问题分析

  1. 第一种分组过滤方案:
    按工地分组的检查逻辑本身合理,但约束惩罚权重(20)未设置为硬约束级别,导致求解器可接受违规情况;同时该逻辑仅覆盖单工地范围,跨工地存在未分配Priority 1班次时无法触发约束。

  2. 第二种双硬约束方案:
    assignEveryShift惩罚所有未分配班次,prioritizeScheduledRankShift额外惩罚未分配的Priority 1班次,这种设置会让求解器同时尝试填充两类班次,无法实现“完全填满Priority 1再处理Priority 2”的排他性优先级。

正确约束配置方案

方案1:硬约束强制排他优先级(推荐)

通过硬约束禁止存在未分配Priority 1班次时分配Priority 2班次,同时确保Priority 1班次必须全部分配(业务强制要求时启用),Priority 2班次分配作为软约束处理。

import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
import org.optaplanner.core.api.score.stream.Constraint;
import org.optaplanner.core.api.score.stream.ConstraintFactory;
import org.optaplanner.core.api.score.stream.ConstraintProvider;

public class ShiftSchedulingConstraintProvider implements ConstraintProvider {

    private static final String CONSTRAINT_PRIORITY1_FIRST = "priority1-shift-must-be-assigned-first";
    private static final String CONSTRAINT_ASSIGN_ALL_PRIORITY1 = "assign-all-priority1-shifts";
    private static final String CONSTRAINT_ASSIGN_PRIORITY2 = "assign-priority2-shifts";

    @Override
    public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
        return new Constraint[]{
                // 硬约束:全局范围内只要有未分配的Priority1班次,就不能分配Priority2班次
                priority1First(constraintFactory),
                // 硬约束:所有Priority1班次必须分配员工(业务强制要求时启用)
                assignAllPriority1Shifts(constraintFactory),
                // 软约束:分配Priority2班次(可选,根据业务需求调整)
                assignPriority2Shifts(constraintFactory)
        };
    }

    private Constraint priority1First(ConstraintFactory constraintFactory) {
        return constraintFactory.forEach(Shift.class)
                .filter(shift -> shift.getRank().equals(SchedulingConstants.SCHEDULED_SHIFT) && shift.getClinician() == null)
                .join(Shift.class)
                .filter((priority1Shift, priority2Shift) -> 
                        priority2Shift.getRank().equals(SchedulingConstants.ALTERNATE_SHIFT) && priority2Shift.getClinician() != null)
                .penalize(HardSoftScore.ONE_HARD)
                .asConstraint(CONSTRAINT_PRIORITY1_FIRST);
    }

    private Constraint assignAllPriority1Shifts(ConstraintFactory constraintFactory) {
        return constraintFactory.forEachIncludingNullVars(Shift.class)
                .filter(shift -> shift.getRank().equals(SCHEDULED_SHIFT) && shift.getClinician() == null)
                .penalize(HardSoftScore.ONE_HARD)
                .asConstraint(CONSTRAINT_ASSIGN_ALL_PRIORITY1);
    }

    private Constraint assignPriority2Shifts(ConstraintFactory constraintFactory) {
        return constraintFactory.forEachIncludingNullVars(Shift.class)
                .filter(shift -> shift.getRank().equals(ALTERNATE_SHIFT) && shift.getClinician() == null)
                .penalize(HardSoftScore.ONE_SOFT)
                .asConstraint(CONSTRAINT_ASSIGN_PRIORITY2);
    }
}

方案2:权重差异实现优先级

若不需要严格硬约束,可通过设置极大权重差,让求解器优先填满Priority 1班次:

private Constraint prioritizePriority1Shifts(ConstraintFactory constraintFactory) {
    // 未分配的Priority1班次惩罚权重远高于Priority2,驱动求解器优先处理
    return constraintFactory.forEachIncludingNullVars(Shift.class)
            .filter(shift -> shift.getClinician() == null)
            .penalizeConfigurable(shift -> 
                    shift.getRank().equals(SchedulingConstants.SCHEDULED_SHIFT) ? 1000 : 1)
            .asConstraint("prioritize-priority1-shifts");
}

求解器配置建议

在application.properties中配置合适的分数类型与终止条件:

# 使用硬软分数类型,适配硬约束+软约束的配置
optaplanner.solver.score-type=HARD_SOFT
# 设置求解超时,确保有足够时间完成Priority1班次的分配
optaplanner.solver.termination.spent-limit=30s

验证方法

  1. 构造测试场景:创建3个未分配的Priority 1班次和2个Priority 2班次
  2. 运行求解器,观察初始阶段仅分配Priority 1班次
  3. 确认所有Priority 1班次分配完成后,求解器才开始处理Priority 2班次
  4. 手动修改解(给Priority 2班次分配员工但仍有未分配的Priority 1),应触发硬分数惩罚

内容的提问来源于stack exchange,提问作者sicario_23

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 00:27:34