如何按业务日期累加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"); }
错误原因
- 方法名错误:
Shift类中不存在getStartDate()方法,应使用getBusinessDate()来匹配业务日期。 - 分组逻辑错误:分组键与收集器的搭配不符合OptaPlanner的API要求,且未关联对应的
DaySettingFlat实例,无法获取设定的时长总和进行对比。 - 类型不匹配:
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
相关产品推荐
相关产品推荐

