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

如何按业务日期累加Shift时长(OptaPlanner约束实现)

OptaPlanner约束规则编译错误修复:按业务日期累加班次时长

问题背景

现有两个问题事实类:

  • Shift类:包含@PlanningId标识的ID,LocalDateTime类型的start/end属性,通过getShiftDuration()返回班次时长(分钟,Long类型),通过getBusinessDate()返回格式化后的业务日期字符串(yyyy-MM-dd)。
  • DaySettingFlat类:包含businessDate(业务日期字符串)和sumOfShiftDuration(设定的班次时长总和,Integer类型)属性。

需求:针对每个DaySettingFlat条目,累加所有业务日期匹配的Shift时长,并验证是否符合设定的sumOfShiftDuration,不符合则触发惩罚。

原约束规则代码在groupBy环节出现编译错误:

Constraint daySettingStandardNumberOfHours(ConstraintFactory constraintFactory) {
    return constraintFactory.forEach(DaySettingFlat.class)
            .join(Shift.class, equal(DaySettingFlat::getBusinessDate, Shift::getStartDate))
            //Getting error on group by 
            .groupBy(Shift::getStartDate,
                     ConstraintCollectors.toList(),
                     ConstraintCollectors.sumLong(Shift::getShiftDuration))
            .penalize(HardMediumSoftScore.ONE_HARD, (date, list, totalDuration)->{
                return totalDuration;
            }).asConstraint("daySettingStandardNumberOfHours");
}

错误原因

  1. 方法名错误:Shift类中不存在getStartDate()方法,应使用getBusinessDate()来匹配业务日期。
  2. 分组逻辑错误:分组键与收集器的搭配不符合OptaPlanner的API要求,且未关联对应的DaySettingFlat实例,无法获取设定的时长总和进行对比。
  3. 类型不匹配:sumLong返回long类型,而DaySettingFlat.sumOfShiftDuration是Integer类型,需处理类型转换;同时原penalize逻辑未体现约束校验的核心(实际时长与设定值的偏差)。

修复后的约束规则代码

Constraint daySettingStandardNumberOfHours(ConstraintFactory constraintFactory) {
    return constraintFactory.forEach(DaySettingFlat.class)
            // 按业务日期匹配DaySettingFlat和对应的Shift
            .join(Shift.class, equal(DaySettingFlat::getBusinessDate, Shift::getBusinessDate))
            // 按DaySettingFlat分组,累加匹配的Shift时长总和
            .groupBy(
                DaySettingFlat.class,
                ConstraintCollectors.sumLong(Shift::getShiftDuration)
            )
            // 计算实际时长与设定值的偏差,不符合则惩罚
            .penalize(HardMediumSoftScore.ONE_HARD, (daySetting, actualTotalDuration) -> {
                // 处理类型转换,避免空指针
                Integer expectedTotal = daySetting.getSumOfShiftDuration();
                if (expectedTotal == null) {
                    return 0;
                }
                // 返回偏差绝对值,实际与设定不符时触发惩罚
                return Math.abs(actualTotalDuration - expectedTotal);
            })
            .asConstraint("daySettingStandardNumberOfHours");
}

关键修改说明

  • 修正关联条件:将Shift::getStartDate替换为Shift::getBusinessDate,确保业务日期匹配逻辑正确。
  • 调整分组策略:以DaySettingFlat实例为分组键,同时收集该组下所有Shift的时长总和,这样能直接关联到设定的sumOfShiftDuration。
  • 完善惩罚逻辑:计算实际累加时长与设定值的偏差绝对值,只有当两者不相等时才会产生惩罚分数,符合约束规则的校验目的。
  • 类型安全处理:增加对sumOfShiftDuration的空值判断,避免类型转换时出现异常。

内容的提问来源于stack exchange,提问作者I. Ahmed

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 03:04:52