OptaPlanner如何通过DRL实现最小化所有分组的最大任务时长总和
问题排查与修正方案
原有规则的错误点
- 语法错误:内层accumulate中引用Group变量时漏写
$符号,且两层accumulate的参数格式不符合Drools语法规范,缺少分隔符 - 冗余依赖:groupId本身是Task的固定属性,不需要匹配Group实例也可以完成分组求和,避免Group实例缺失导致的匹配失败问题
- 逻辑遗漏:原有嵌套accumulate的分组逻辑未对齐,会导致分组求和结果计算错误
修正后的可用规则
rule "Minimize the largest group duration" when // 先按groupId分组,计算每个已初始化分组的总时长S accumulate( Task(index != null, $groupId: groupId, $d: duration); group by $groupId, $s: sum($d) ) // 再取所有分组总时长的最大值 accumulate( $s: Number(); $smax: max($s.intValue()) ) then // 软约束罚分,最大值越大罚分越高,符合最小化最大值的目标 scoreHolder.addSoftConstraintMatch(kcontext, 1, -$smax.intValue()); end
补充注意点
- 若使用OptaPlanner 8及以上版本,也可以用约束流实现,代码可读性和运行性能更优,示例如下:
public Constraint minimizeMaxGroupDuration(ConstraintFactory constraintFactory) { return constraintFactory.forEach(Task.class) .filter(task -> task.getIndex() != null) .groupBy(Task::getGroupId, sum(Task::getDuration)) .groupBy(max(Integer::valueOf)) .penalize(HardSoftScore.ONE_SOFT, maxDuration -> maxDuration) .asConstraint("Minimize the largest group duration"); }
- 需确认duration对应的ShadowVariable监听规则已正确配置,在当前规则执行前已完成赋值,避免取到空值或初始值导致计算错误
内容的提问来源于stack exchange,提问作者brewphone
相关产品推荐
相关产品推荐

