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

OptaPlanner装箱方案结果非最优,求代码问题排查指导

问题排查与优化方案

核心问题分析

你的OptaPlanner结果未达到OR-Tools的最优水平,主要原因集中在约束目标设置、初始解策略、搜索时间配置三个方面,以下是具体问题和修正方案:


1. 软约束逻辑偏差(关键问题)

当前软约束computerCost虽意图最小化总容积,但存在两个缺陷:

  • 若容器池包含Medium类型,Solver未优先选择大容器(总容积更低),原因是约束权重未体现大容器的优势:使用1个Medium的总容积比2个Small更低,但当前惩罚逻辑下大容器的单容器惩罚值更高,导致Solver倾向于选择更多小容器。
  • 未激励容器的容积/重量利用率,导致部分容器空间浪费严重(如你的结果中多个Small容器重量利用率仅20%-30%)。

修正方案:

调整软约束,同时实现最小化总使用容积和最大化容器利用率:

public class CartonizationConstraintProvider implements ConstraintProvider {
    @Override
    public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
        return new Constraint[]{
                requiredWeightTotal(constraintFactory),
                requiredVolumeTotal(constraintFactory),
                minimizeTotalUsedVolume(constraintFactory),
                maximizeVolumeUtilization(constraintFactory),
                maximizeWeightUtilization(constraintFactory)
        };
    }

    // 原硬约束保留
    Constraint requiredWeightTotal(ConstraintFactory constraintFactory) {
        return constraintFactory.forEach(OrderItem.class)
                .groupBy(OrderItem::getContainer, sum(OrderItem::getWeight))
                .filter((container, requiredWeight) -> requiredWeight > container.getMaxWeight())
                .penalize(HardSoftScore.ONE_HARD,
                        (container, requiredWeight) -> requiredWeight - container.getMaxWeight())
                .asConstraint("requiredWeightTotal");
    }

    Constraint requiredVolumeTotal(ConstraintFactory constraintFactory) {
        return constraintFactory.forEach(OrderItem.class)
                .groupBy(OrderItem::getContainer, sum(OrderItem::getVolume))
                .filter((container, requiredVolume) -> requiredVolume > container.getMaxVolume())
                .penalize(HardSoftScore.ONE_HARD,
                        (container, requiredVolume) -> requiredVolume - container.getMaxVolume())
                .asConstraint("requiredVolumeTotal");
    }

    // 最小化已使用容器的总容积,提高权重让Solver优先关注
    Constraint minimizeTotalUsedVolume(ConstraintFactory constraintFactory) {
        return constraintFactory.forEach(CartonContainer.class)
                .ifExists(OrderItem.class, equal(Function.identity(), OrderItem::getContainer))
                .penalize(HardSoftScore.ofSoft(100), CartonContainer::getMaxVolume)
                .asConstraint("minimizeTotalUsedVolume");
    }

    // 最大化容器容积利用率(奖励填满容器)
    Constraint maximizeVolumeUtilization(ConstraintFactory constraintFactory) {
        return constraintFactory.forEach(OrderItem.class)
                .groupBy(OrderItem::getContainer, sum(OrderItem::getVolume))
                .filter((container, usedVolume) -> usedVolume > 0)
                .reward(HardSoftScore.ofSoft(1), (container, usedVolume) -> usedVolume)
                .asConstraint("maximizeVolumeUtilization");
    }

    // 最大化容器重量利用率(奖励填满容器)
    Constraint maximizeWeightUtilization(ConstraintFactory constraintFactory) {
        return constraintFactory.forEach(OrderItem.class)
                .groupBy(OrderItem::getContainer, sum(OrderItem::getWeight))
                .filter((container, usedWeight) -> usedWeight > 0)
                .reward(HardSoftScore.ofSoft(1), (container, usedWeight) -> usedWeight)
                .asConstraint("maximizeWeightUtilization");
    }
}

2. 初始解策略低效

CloudBalance示例的默认初始解策略是随机分配,对于装箱问题效率极低。建议使用**递减最佳适应(Best Fit Decreasing)**生成初始解,让Solver从更优的起点开始搜索。

修正方案:

在SolverConfig中添加构造启发式配置:

SolverFactory<CartonizationSolution> solverFactory = SolverFactory.create(new SolverConfig()
        .withSolutionClass(CartonizationSolution.class)
        .withEntityClasses(OrderItem.class)
        .withConstraintProviderClass(CartonizationConstraintProvider.class)
        // 配置高效初始解策略
        .withConstructionHeuristicConfig(new ConstructionHeuristicConfig()
                .withConstructionHeuristicType(ConstructionHeuristicType.BEST_FIT_DECREASING))
        .withTerminationConfig(new TerminationConfig().withUnimprovedSecondsSpentLimit(15L)));

3. 搜索时间不足

当前设置的withUnimprovedSecondsSpentLimit(5L)仅给了5秒无改进终止时间,对于装箱这类组合优化问题,时间太短。OptaPlanner的元启发式算法需要更多时间探索解空间。

修正方案:

延长无改进时间,同时添加总时间限制:

.withTerminationConfig(new TerminationConfig()
        .withUnimprovedSecondsSpentLimit(15L)
        .withSecondsSpentLimit(60L)) // 最多运行60秒,避免无限等待

4. 其他潜在问题

  • 容器池完整性:确认load()方法加载的CartonRange包含Medium类型容器,若初始数据中没有Medium容器,OptaPlanner无法使用该类型。
  • 分数解释错误:你的代码中scoreManager.explainScore(solution)使用的是初始解solution,而非求解后的solvedSolution,改为solvedSolution才能查看最优解的分数细节,帮助排查约束问题:
    ScoreExplanation<CartonizationSolution, HardSoftScore> explanation = scoreManager.explainScore(solvedSolution);
    System.out.println(scoreManager.getSummary(solvedSolution));
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 22:40:40