OptaPlanner多规划实体配置异常求助:未指定entityClass无法自动推导
解决OptaPlanner多规划实体下QueuedEntityPlacerConfig无法推导实体类的异常
这个异常的核心原因很明确:当你的Solver里存在多个@PlanningEntity类(也就是你定义的Task和PDItem)时,构造启发式阶段的QueuedEntityPlacer无法自动判断该优先处理哪个实体,所以必须显式指定实体类才能正常启动。
下面给你具体的解决步骤,顺便帮你修正代码里的几个小问题:
1. 显式为每个构造启发式阶段指定实体类
不管你是用XML配置还是Java代码配置Solver,都需要为每个实体单独配置构造启发式阶段,明确指定对应的entityClass。
方式一:XML配置(solverConfig.xml)
<solver> <!-- 基础配置(求解器终止条件、评分器等) --> <termination> <secondsSpentLimit>60</secondsSpentLimit> </termination> <scoreDirectorFactory> <scoreDrl>your-score-rules.drl</scoreDrl> </scoreDirectorFactory> <!-- 为Task配置构造启发式阶段 --> <constructionHeuristic> <queuedEntityPlacer> <entitySelector> <entityClass>Planning_v3.Domain.Task</entityClass> </entitySelector> </queuedEntityPlacer> </constructionHeuristic> <!-- 为PDItem配置构造启发式阶段 --> <constructionHeuristic> <queuedEntityPlacer> <entitySelector> <entityClass>Planning_v3.Domain.PDItem</entityClass> </entitySelector> </queuedEntityPlacer> </constructionHeuristic> <!-- 后续的局部搜索阶段 --> <localSearch> <!-- 你的局部搜索配置 --> </localSearch> </solver>
方式二:Java代码配置SolverConfig
public class PlanningAPP3 { public static void main(String[] args) { SolverConfig solverConfig = new SolverConfig() .withSolutionClass(YourSolutionClass.class) .withScoreDirectorFactory(sdf -> sdf.withScoreDrl("your-score-rules.drl")) .withTerminationConfig(new TerminationConfig().withSecondsSpentLimit(60L)); // 为Task创建构造启发式阶段 ConstructionHeuristicPhaseConfig taskChPhase = new ConstructionHeuristicPhaseConfig(); QueuedEntityPlacerConfig taskPlacer = new QueuedEntityPlacerConfig(); taskPlacer.setEntitySelectorConfig(new EntitySelectorConfig().withEntityClass(Task.class)); taskChPhase.setEntityPlacerConfig(taskPlacer); // 为PDItem创建构造启发式阶段 ConstructionHeuristicPhaseConfig pdItemChPhase = new ConstructionHeuristicPhaseConfig(); QueuedEntityPlacerConfig pdItemPlacer = new QueuedEntityPlacerConfig(); pdItemPlacer.setEntitySelectorConfig(new EntitySelectorConfig().withEntityClass(PDItem.class)); pdItemChPhase.setEntityPlacerConfig(pdItemPlacer); // 将两个阶段加入求解器配置 solverConfig.setPhaseList(List.of(taskChPhase, pdItemChPhase)); // 构建并启动求解器 Solver<YourSolutionClass> solver = SolverFactory.create(solverConfig).buildSolver(); // ... 后续求解逻辑 } }
2. 修正实体类的ValueRangeProvider配置
你的实体类里有个不符合OptaPlanner规范的地方:@ValueRangeProvider不应该放在实体类的方法里(除非你确实需要每个实体实例有独立的范围),通常我们会把全局的范围定义在@PlanningSolution类中,这样所有实体都能共享同一个范围:
修正后的Solution类示例
@PlanningSolution public class ProductionScheduleSolution { // 存储所有待规划的Task和PDItem private List<Task> taskList; private List<PDItem> pdItemList; // 全局等待时间范围 @ValueRangeProvider(id = "wtRange") public CountableValueRange<Integer> getWaitTimeRange() { // 根据你的业务需求定义范围,这里示例为0到100 return ValueRangeFactory.createIntValueRange(0, 101); } // 全局可用机器类型范围 @ValueRangeProvider(id = "macRange") public List<DyeMachineType> getMachineTypeRange() { // 返回所有可用的机器类型 return Arrays.asList(DyeMachineType.values()); } // 别忘了添加评分方法和所有字段的getter/setter @PlanningScore public HardSoftScore getScore() { // ... 你的评分逻辑 } // getter和setter方法 public List<Task> getTaskList() { return taskList; } public void setTaskList(List<Task> taskList) { this.taskList = taskList; } // ... 其他字段的getter/setter }
修正后的Task类
@PlanningEntity(difficultyComparatorClass = TaskDifficultyComparator.class) public class Task { private Integer waitting_time; @PlanningVariable(valueRangeProviderRefs = {"wtRange"}) public Integer getWaitting_time() { return waitting_time; } // 必须添加setter,OptaPlanner需要修改规划变量的值 public void setWaitting_time(Integer waitting_time) { this.waitting_time = waitting_time; } }
修正后的PDItem类
@PlanningEntity(difficultyComparatorClass = TaskDifficultyComparator.class) public class PDItem { private DyeMachineType machine_type; @PlanningVariable(valueRangeProviderRefs = {"macRange"}) public DyeMachineType getMachine_type() { return machine_type; } // 必须添加setter public void setMachine_type(DyeMachineType machine_type) { this.machine_type = machine_type; } }
做完以上两步,你的Solver应该就能正常启动,不会再抛出那个实体类无法推导的异常了。
内容的提问来源于stack exchange,提问作者heyif
相关产品推荐
相关产品推荐

