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

OptaPlanner多规划实体组合报错及调度需求实现咨询

OptaPlanner调度问题错误排查与需求实现指导

错误根源分析

你遇到的错误是因为普通@PlanningVariable只能绑定单个候选值,但你定义的employeeList是List<Employee>类型,而@ValueRangeProvider提供的是单个Employee实例的集合,类型不匹配导致无法赋值。

错误修复方案

OptaPlanner 8.2及以上版本支持集合类型的规划变量,使用@PlanningListVariable替代@PlanningVariable即可解决类型匹配问题,它会自动从候选集中生成合法的子集作为变量值。

代码修正示例

1. Vehicle实体类调整

@PlanningEntity
public class Vehicle {
    // 车辆容量属性
    private Integer capacity;
    // 替换@PlanningVariable为@PlanningListVariable,指定值范围提供者ID
    @PlanningListVariable(valueRangeProviderRefs = "employeeRange")
    private List<Employee> employeeList;

    // 省略getter、setter及其他字段
}

2. Solution类保持原ValueRangeProvider(无需修改)

@PlanningSolution
public class ScheduleSolution {
    private List<Employee> employees;
    private List<Vehicle> vehicles;
    private List<Job> jobs;
    // 评分器等其他字段

    // 提供单个Employee的候选集
    @ValueRangeProvider(id = "employeeRange")
    public List<Employee> getEmployees() {
        return employees;
    }

    // 省略getter、setter及其他方法
}

核心需求实现

1. 车辆搭载员工数不超容量

通过约束规则限制employeeList的大小不超过车辆容量:

@Constraint
public Constraint vehicleEmployeeCapacity(ConstraintFactory constraintFactory) {
    return constraintFactory.from(Vehicle.class)
            .filter(vehicle -> vehicle.getEmployeeList().size() > vehicle.getCapacity())
            .penalize("Vehicle over capacity", HardSoftScore.ONE_HARD,
                    vehicle -> vehicle.getEmployeeList().size() - vehicle.getCapacity());
}

2. 员工任务数控制在10-30之间

首先给Employee添加派生属性assignedJobs(从Job的分配结果聚合得到),再编写约束:

// Employee类中添加派生属性
public List<Job> getAssignedJobs() {
    // 从所有Job中筛选分配给当前员工的任务
    return jobs.stream()
            .filter(job -> this.equals(job.getAssignedEmployee()))
            .collect(Collectors.toList());
}

// 约束规则
@Constraint
public Constraint employeeJobCountRange(ConstraintFactory constraintFactory) {
    return constraintFactory.from(Employee.class)
            .filter(employee -> employee.getAssignedJobs().size() < 10 || employee.getAssignedJobs().size() > 30)
            .penalize("Employee job count out of range", HardSoftScore.ONE_HARD,
                    employee -> Math.abs(employee.getAssignedJobs().size() - 20));
}

3. 员工总工时不超限

给Employee添加总工时派生属性,再编写约束:

// Employee类中添加总工时计算
public int getTotalWorkHours() {
    return getAssignedJobs().stream()
            .mapToInt(Job::getWorkHours)
            .sum();
}

// 约束规则
@Constraint
public Constraint employeeTotalHoursLimit(ConstraintFactory constraintFactory) {
    return constraintFactory.from(Employee.class)
            .filter(employee -> employee.getTotalWorkHours() > employee.getMaxWorkHours())
            .penalize("Employee total hours exceed limit", HardSoftScore.ONE_HARD,
                    employee -> employee.getTotalWorkHours() - employee.getMaxWorkHours());
}

额外注意事项

  • 若使用OptaPlanner 8.2以下版本,不支持@PlanningListVariable,需调整建模思路:将Employee设为规划实体,给每个Employee分配Vehicle,Vehicle的员工集合改为从Employee的分配结果聚合生成,避免直接用集合作为规划变量。
  • 所有派生属性(如assignedJobs、totalWorkHours)无需添加规划注解,仅作为约束计算的辅助字段。

内容的提问来源于stack exchange,提问作者Scott A. Levinson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 21:48:28