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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 12:47:51