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

OptaPlanner软约束未优化求助:硬约束生效但软约束无得分

问题分析与解决方案

核心问题:两个约束均未触发,得分全0

你的求解器返回0Hard/0Medium/0Soft,说明硬约束和软约束的逻辑都没有匹配到任何符合条件的对象,导致惩罚逻辑从未执行。以下是具体问题和修复方案:


一、软约束逻辑错误(完全未触发)

1. 统计范围错误

当前软约束用filter(wd -> wd.isFreeToWork())筛选可工作的日期,再结合!hasBreakDayBySolver过滤休息日,这会遗漏员工可工作且被安排工作的核心数据。应该直接筛选实际被安排工作的日期:

// 替换原filter逻辑
.from(WorkingDay.class)
.filter(WorkingDay::hasWork) // 直接统计已安排工作的日期

2. 惩罚逻辑反向

你的软约束目标是「尽可能多安排工作时长」,但当前逻辑对超过66小时的情况也会惩罚,这会引导求解器尽量让时长等于66,而非最大化工作时长。修正为仅惩罚不足66小时的情况:

.penalizeConfigurable(AVERAGE_HOURS_WORKING, ((agent, count) -> {
    int totalHours = count * 7;
    // 仅当总时长不足66时惩罚,超过则不惩罚(鼓励多安排)
    return totalHours < 66 ? (66 - totalHours) * 2 : 0;
}))

3. 冗余分组条件

WorkingDay::hasBreakDayBySolver的分组条件是冗余的,因为hasWork()已经能判断是否为工作日,可移除该分组条件,简化逻辑:

.groupBy(WorkingDay::getAgent, ConstraintCollectors.count())
// 移除后续的filter(!hasBreakDayBySolver)逻辑

二、硬约束逻辑错误(未正确识别连续工作天数)

原硬约束的join条件无法准确统计「连续5天工作」的情况,wd2.getDayJava() >= wd1.getDayJava().minusDays(4)会把5天窗口内的所有工作日都统计进去,而非连续的日期。改用OptaPlanner的sequence统计连续序列:

private Constraint fiveConsecutiveWorkingDaysMax(ConstraintFactory constraintFactory) {
    return constraintFactory
            .from(WorkingDay.class)
            .filter(WorkingDay::hasWork)
            // 按员工分组,将日期按顺序排列,判断连续天数
            .groupBy(WorkingDay::getAgent,
                    ConstraintCollectors.sequence(WorkingDay::getDayJava,
                            (prevDay, currDay) -> ChronoUnit.DAYS.between(prevDay.getDayJava(), currDay.getDayJava()) == 1))
            // 连续工作天数≥5时触发惩罚
            .filter((agent, workSequence) -> workSequence.size() >= 5)
            // 每多1天连续工作,惩罚1(可根据需求调整权重)
            .penalizeConfigurable(FIVE_CONSECUTIVE_WORKING_DAYS_MAX,
                    (agent, workSequence) -> workSequence.size() - 4);
}

三、验证得分配置

确保在求解器配置中正确绑定约束权重:

SolverFactory<YourSolution> solverFactory = SolverFactory.create(new SolverConfig()
        .withSolutionClass(YourSolution.class)
        .withEntityClasses(WorkingDay.class)
        .withScoreDirectorFactory(new ScoreDirectorFactoryConfig()
                .withScoreDefinitionClass(HardSoftScoreDefinition.class)
                .withConstraintProviderClass(YourConstraintProvider.class)
                // 配置约束权重(硬约束100,软约束100)
                .withConstraintConfiguration(new ConstraintConfiguration()
                        .addConstraintWeight("FIVE_CONSECUTIVE_WORKING_DAYS_MAX", HardSoftScore.ofHard(100))
                        .addConstraintWeight("AVERAGE_HOURS_WORKING", HardSoftScore.ofSoft(100)))));

四、调试建议

  1. 在约束的filter方法中添加日志,确认是否有数据进入后续逻辑;
  2. 检查hasWork()、hasBreakDayBySolver等方法的返回值是否符合预期,避免逻辑反转;
  3. 用OptaPlanner的调试工具(如SolverManager的日志、ScoreDirector的解释功能)查看得分计算过程,定位未触发的约束。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 05:05:30