OptaPlanner多技能工人任务调度问题咨询(Java API/OSGI环境)
用Java API + EasyScoreCalculator解决OSGI环境下的多技能工人任务调度问题
核心背景梳理
你提到在OSGI插件里没法顺利加载XML/DRL配置文件,所以选择用Java API直接创建求解器,同时基于EasyScoreCalculator做分数计算——这个方向完全没问题,毕竟OSGI的类加载隔离特性确实会给规则文件的读取带来不少麻烦,用纯Java API实现能完美避开这个坑。
实现步骤拆解
1. 定义领域模型
首先得把任务和工人的核心属性明确下来,别忘了加上OptaPlanner的核心注解:
- Task类:标记为
@PlanningEntity,包含任务ID、所需技能、预计时长,以及用于分配的工人变量 - Worker类:存储工人ID、掌握的技能集合、可用时间等核心属性
- Schedule类:作为
@PlanningSolution,管理任务列表、工人列表、分配结果和计算出的分数
示例代码片段:
@PlanningEntity public class Task { private Long id; private String requiredSkill; private int duration; @PlanningVariable(valueRangeProviderRefs = {"workerRange"}) private Worker assignedWorker; // 构造器、getter/setter省略 } @PlanningSolution public class Schedule { @ProblemFactCollectionProperty @ValueRangeProvider(id = "workerRange") private List<Worker> workers; @PlanningEntityCollectionProperty private List<Task> tasks; @PlanningScore private HardSoftScore score; // 构造器、getter/setter省略 }
2. 实现EasyScoreCalculator
因为不用DRL规则文件,得自己写分数计算逻辑,核心要覆盖两类约束:
- 硬约束:任务必须分配给具备对应技能的工人(违反直接扣硬分数,这类约束是必须满足的)
- 软约束:比如工人负载均衡、任务优先级等(根据你的业务需求定义,软分数影响调度的优化程度)
示例实现:
public class WorkerTaskScoreCalculator implements EasyScoreCalculator<Schedule, HardSoftScore> { @Override public HardSoftScore calculateScore(Schedule schedule) { int hardScore = 0; int softScore = 0; // 检查硬约束:任务分配的工人是否匹配技能 for (Task task : schedule.getTasks()) { Worker worker = task.getAssignedWorker(); if (worker == null) { hardScore--; // 未分配任务的硬扣分 continue; } if (!worker.getSkills().contains(task.getRequiredSkill())) { hardScore--; // 技能不匹配的硬扣分 } } // 检查软约束:工人负载均衡(总任务时长差值越小,软分数越高) Map<Worker, Integer> workerLoadMap = new HashMap<>(); for (Task task : schedule.getTasks()) { Worker worker = task.getAssignedWorker(); if (worker != null) { workerLoadMap.put(worker, workerLoadMap.getOrDefault(worker, 0) + task.getDuration()); } } if (!workerLoadMap.isEmpty()) { int maxLoad = Collections.max(workerLoadMap.values()); for (int load : workerLoadMap.values()) { softScore -= (maxLoad - load); } } return HardSoftScore.of(hardScore, softScore); } }
3. 用Java API创建求解器
在OSGI环境里,直接通过SolverFactory的builder模式构建求解器,完全不用依赖外部配置文件:
// 构建求解器配置 SolverConfig solverConfig = new SolverConfig(); solverConfig.withSolutionClass(Schedule.class); solverConfig.withEntityClasses(Task.class); // 绑定自定义分数计算器 solverConfig.withScoreCalculatorClass(WorkerTaskScoreCalculator.class); // 设置求解终止条件(比如限制30秒内完成) solverConfig.withTerminationConfig(new TerminationConfig() .withSecondsSpentLimit(30L)); // 创建求解器实例 SolverFactory<Schedule> solverFactory = SolverFactory.create(solverConfig); Solver<Schedule> solver = solverFactory.buildSolver(); // 准备问题数据(从OSGI服务中获取你的任务和工人列表) Schedule problem = new Schedule(workerList, taskList); // 执行求解 Schedule solution = solver.solve(problem); // 处理求解结果 for (Task task : solution.getTasks()) { System.out.printf("任务ID %d 分配给工人 %d(技能匹配:%b)%n", task.getId(), task.getAssignedWorker().getId(), task.getAssignedWorker().getSkills().contains(task.getRequiredSkill())); }
OSGI环境额外注意事项
- 类加载器:确保OptaPlanner核心类和你的领域模型类在同一类加载器范围内,或者通过OSGI的
Import-Package正确导入相关包 - 服务注册:如果求解器需要作为公共服务供其他组件调用,记得把
SolverFactory或Solver注册为OSGI服务 - 线程管理:OptaPlanner求解会占用线程,在OSGI环境里要注意线程池配置,避免影响其他插件的正常运行
内容的提问来源于stack exchange,提问作者eldorado
相关产品推荐
相关产品推荐

