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

OptaPlanner如何使用同一模型类实现两类排课规划问题差异化配置

你的需求完全可以实现,OptaPlanner原生支持基于XML的域映射配置,可以完全替代Java注解,为两个独立规划场景分别定义不同的求解器配置即可。

方案1:使用XML域映射配置(和你设想的方案一致)

OptaPlanner的求解器配置文件支持<domainAccessType>配置为REFLECTION,然后通过<solutionDescriptor>和<entityDescriptor>标签手动定义规划解、规划实体、规划变量等映射规则,完全不需要在Java类上加注解。

第一步:保留无注解的纯净基础模型

不需要在基础类上加任何OptaPlanner相关注解,保持如下定义即可:

class Schedule {
    List<Teacher> teachers;
    List<CourseRound> courseRounds;
    List<Lecture> lectures;
    List<StudentGroup> studentGroups;
    List<Timeslot> timeslots;
    List<Room> rooms;
    //  getter、setter 省略
}

class CourseRound {
    Teacher teacher;
    String course;
    //  getter、setter 省略
}

class Lecture {
    Timeslot timeslot;
    Room room;
    //  getter、setter 省略
}

第二步:编写教学分配场景的独立求解器配置

新建配置文件teacherAssignmentSolverConfig.xml,定义该场景下的规划映射规则:

<?xml version="1.0" encoding="UTF-8"?>
<solver-config xmlns="https://www.optaplanner.org/xsd/solver"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="https://www.optaplanner.org/xsd/solver https://www.optaplanner.org/xsd/solver/solver.xsd">
  <!-- 配置为反射访问域,不依赖注解 -->
  <domainAccessType>REFLECTION</domainAccessType>
  <!-- 定义规划解Schedule的映射规则 -->
  <solutionDescriptor class="替换为你项目Schedule的全类名">
    <!-- 定义教师可选值范围 -->
    <valueRangeProvider id="teacherRange" field="teachers"/>
    <!-- 定义问题事实属性 -->
    <problemFactCollectionProperty field="studentGroups"/>
    <problemFactCollectionProperty field="lectures"/>
    <problemFactCollectionProperty field="timeslots"/>
    <problemFactCollectionProperty field="rooms"/>
    <!-- 定义规划实体集合 -->
    <planningEntityCollectionProperty field="courseRounds"/>
    <!-- 此处补充你定义的@PlanningScore对应字段的配置 -->
  </solutionDescriptor>
  <!-- 定义规划实体CourseRound的映射规则 -->
  <entityDescriptor class="替换为你项目CourseRound的全类名">
    <!-- 定义规划变量teacher,绑定对应值范围 -->
    <planningVariable field="teacher" valueRangeProviderRefs="teacherRange"/>
  </entityDescriptor>
  <!-- 补充其他求解器配置:评分规则、终止条件等 -->
  <scoreDirectorFactory>
    <constraintProviderClass>替换为教学分配场景的约束类全类名</constraintProviderClass>
  </scoreDirectorFactory>
  <termination>
    <secondsSpentLimit>30</secondsSpentLimit>
  </termination>
</solver-config>

第三步:编写课时排程场景的独立求解器配置

新建配置文件lectureSchedulingSolverConfig.xml,定义该场景下的映射规则:

<?xml version="1.0" encoding="UTF-8"?>
<solver-config xmlns="https://www.optaplanner.org/xsd/solver"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="https://www.optaplanner.org/xsd/solver https://www.optaplanner.org/xsd/solver/solver.xsd">
  <domainAccessType>REFLECTION</domainAccessType>
  <solutionDescriptor class="替换为你项目Schedule的全类名">
    <!-- 定义时间段、教室可选值范围 -->
    <valueRangeProvider id="timeslotRange" field="timeslots"/>
    <valueRangeProvider id="roomRange" field="rooms"/>
    <!-- 定义问题事实属性 -->
    <problemFactCollectionProperty field="teachers"/>
    <problemFactCollectionProperty field="courseRounds"/>
    <problemFactCollectionProperty field="studentGroups"/>
    <!-- 定义规划实体集合 -->
    <planningEntityCollectionProperty field="lectures"/>
    <!-- 此处补充你定义的@PlanningScore对应字段的配置 -->
  </solutionDescriptor>
  <!-- 定义规划实体Lecture的映射规则 -->
  <entityDescriptor class="替换为你项目Lecture的全类名">
    <planningVariable field="timeslot" valueRangeProviderRefs="timeslotRange"/>
    <planningVariable field="room" valueRangeProviderRefs="roomRange"/>
  </entityDescriptor>
  <!-- 补充其他求解器配置:评分规则、终止条件等 -->
  <scoreDirectorFactory>
    <constraintProviderClass>替换为课时排程场景的约束类全类名</constraintProviderClass>
  </scoreDirectorFactory>
  <termination>
    <secondsSpentLimit>60</secondsSpentLimit>
  </termination>
</solver-config>

第四步:代码中分别加载配置创建求解器

// 初始化原始排课数据
Schedule initialSchedule = initScheduleData();

// 加载教学分配配置求解教师分配问题
SolverFactory<Schedule> teacherAssignmentFactory = SolverFactory.createFromXmlResource(
        "你的配置文件路径/teacherAssignmentSolverConfig.xml");
Solver<Schedule> teacherAssignmentSolver = teacherAssignmentFactory.buildSolver();
Schedule teacherAssignedSchedule = teacherAssignmentSolver.solve(initialSchedule);

// 加载课时排程配置,基于教师分配结果求解排课问题
SolverFactory<Schedule> schedulingFactory = SolverFactory.createFromXmlResource(
        "你的配置文件路径/lectureSchedulingSolverConfig.xml");
Solver<Schedule> schedulingSolver = schedulingFactory.buildSolver();
Schedule finalSchedule = schedulingSolver.solve(teacherAssignedSchedule);

方案2:注解模式变通实现

如果你更习惯使用注解配置,也可以通过继承基础类的方式实现:

  • 基础模型保持无注解,分别为两个场景创建子类
    • 教学分配场景:创建TeacherAssignmentSchedule继承Schedule加规划解注解,创建AssignableCourseRound继承CourseRound加规划实体注解
    • 课时排程场景:创建LectureSchedulingSchedule继承Schedule加规划解注解,创建SchedulableLecture继承Lecture加规划实体注解
  • 运行时将基础数据转换为对应场景的子类实例求解即可,优势是注解配置更直观,缺点是需要额外定义一套子类。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 21:45:01