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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:51:57