Optaplanner多规划实体建模报错及优化方案咨询
问题
基于OptaPlanner的Task Assigning示例进行变体开发,业务中存在多种任务类型,每种类型有独特规划变量,因此将这些任务建模为多个规划实体,均继承自抽象类Activity,该类又继承根类ActivityOrActor。解决方案构建完成后出现如下错误:
INFO [15:37:33] DefaultSolver | Solving started: time spent (98), best score (0hard/0soft), environment mode (FULL_ASSERT), move thread count (4), random (JDK with seed 1). INFO [15:37:33] DefaultConstructionHeuristicPhase | Construction Heuristic phase (0) ended: time spent (130), best score (0hard/0soft), score calculation speed (200/sec), step total (0). INFO [15:37:33] DefaultConstructionHeuristicPhase | Construction Heuristic phase (1) ended: time spent (152), best score (0hard/0soft), score calculation speed (294/sec), step total (0). Exception in thread "main" java.lang.IllegalStateException: The move thread with moveThreadIndex (0) has thrown an exception. Relayed here in the parent thread. at org.optaplanner.core.impl.heuristic.thread.OrderByMoveIndexBlockingQueue.take(OrderByMoveIndexBlockingQueue.java:131) at org.optaplanner.core.impl.localsearch.decider.MultiThreadedLocalSearchDecider.forageResult(MultiThreadedLocalSearchDecider.java:185) at org.optaplanner.core.impl.localsearch.decider.MultiThreadedLocalSearchDecider.decideNextStep(MultiThreadedLocalSearchDecider.java:150) at org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:72) at org.optaplanner.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:83) at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:193) at com.macro_optimizer.domain.solution.solver.MacroSolutionSolver.solve(MacroSolutionSolver.java:38) at com.macro_optimizer.PlannerApp.main(PlannerApp.java:27) Caused by: java.lang.IllegalStateException: The supply (ExternalizedSingletonInverseVariableSupply(previousActivityOrActor)) is corrupted, because the entity (com.macro_optimizer.domain.activity.Deploy@418aaae1) for sourceVariable (previousActivityOrActor) cannot be inserted: another entity (com.macro_optimizer.domain.activity.Deploy@63aaede0) already has that value (com.macro_optimizer.domain.activity.Deploy@3585120c). at org.optaplanner.core.impl.domain.variable.inverserelation.ExternalizedSingletonInverseVariableSupply.insert(ExternalizedSingletonInverseVariableSupply.java:83) at org.optaplanner.core.impl.domain.variable.inverserelation.ExternalizedSingletonInverseVariableSupply.afterVariableChanged(ExternalizedSingletonInverseVariableSupply.java:61) at org.optaplanner.core.impl.domain.variable.listener.support.VariableChangedNotification.triggerAfter(VariableChangedNotification.java:20) at org.optaplanner.core.impl.domain.variable.listener.support.VariableChangedNotification.triggerAfter(VariableChangedNotification.java:6) at org.optaplanner.core.impl.domain.variable.listener.support.AbstractNotifiable.triggerAllNotifications(AbstractNotifiable.java:84) at org.optaplanner.core.impl.domain.variable.listener.support.VariableListenerSupport.triggerVariableListenersInNotificationQueues(VariableListenerSupport.java:180) at org.optaplanner.core.impl.score.director.AbstractScoreDirector.triggerVariableListeners(AbstractScoreDirector.java:261) at org.optaplanner.core.impl.heuristic.move.AbstractMove.doMoveOnly(AbstractMove.java:27) at org.optaplanner.core.impl.heuristic.move.AbstractMove.doMove(AbstractMove.java:20) at org.optaplanner.core.impl.heuristic.move.AbstractMove.doMove(AbstractMove.java:15) at org.optaplanner.core.impl.score.director.AbstractScoreDirector.doAndProcessMove(AbstractScoreDirector.java:195) at org.optaplanner.core.impl.heuristic.thread.MoveThreadRunner.run(MoveThreadRunner.java:131) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:829)
2022-08-24更新:已将所有规划变量从抽象
Activity类移至具体活动类,且仅保留一种活动类型(规划实体数量为1)进行优化测试,仍出现相同错误。
解决建议
错误排查与修复
核心问题是previousActivityOrActor这个单例逆变量的约束被打破:两个不同的Deploy实体同时指向了同一个前置实体,违反了每个前置实体只能被一个后续实体引用的唯一性规则。按以下步骤排查修复:
- 检查注解配置:确认
previousActivityOrActor的@InverseRelationShadowVariable注解是否关联了正确的源变量(比如nextActivityOrActor),且源变量的逻辑确保每个实体只能有一个后续实体。 - 验证初始数据:检查初始解决方案中是否存在多个实体的
previousActivityOrActor指向同一实体的情况——FULL_ASSERT模式会严格校验这种约束,初始数据违规直接触发报错。 - 排查自定义逻辑:如果有自定义变量监听器或移动实现,检查修改变量时是否正确维护了逆变量的唯一性,比如修改某实体的前置变量时,是否遗漏了清除原前置实体的对应后续引用。
- 临时切换单线程:将
solverConfig中的moveThreadCount设为1,排除多线程环境下的变量同步问题,确认错误是否由多线程逻辑冲突导致。
领域建模优化(减少规划实体数量)
如果希望简化模型、减少规划实体类型,可采用以下思路:
- 统一实体+类型字段:将所有任务合并为一个
Activity规划实体,用taskType枚举区分类型,针对不同类型的独特规划变量,使用@Nullable标记为可选变量,在分数计算时仅对对应类型的任务校验该变量的约束。 - 共享抽象+扩展变量:在抽象
Activity类中定义通用规划变量(如previousActivityOrActor),具体任务类中扩展独特变量,确保影子变量、逆变量的注解在继承体系中配置一致,避免约束冲突。 - 规划值分组替代多实体:如果不同任务类型需要分配到特定资源组,可给规划值(如Actor)添加分组标签,通过约束规则限制任务类型与资源组的匹配关系,无需拆分多个规划实体。
内容的提问来源于stack exchange,提问作者score_corruption_hurts2
相关产品推荐
相关产品推荐

