OptaPlanner中动态Placement列表的处理方案及示例需求
解决方案:调整建模思路,基于物料拆分单元构建规划实体
OptaPlanner的规划实体集合在初始化时必须是固定大小的,不支持动态扩展。因此你需要调整模型,将物料的拆分单元作为规划实体,而非动态的放置步骤。以下是具体实现方案:
1. 重新定义规划实体:MaterialAllocation
每个MaterialAllocation代表一份可分配的物料单元(可按最小单位拆分,或合并为合理批次),OptaPlanner将为每个单元分配目标容器。
@PlanningEntity @Data @AllArgsConstructor @NoArgsConstructor public class MaterialAllocation { // 唯一标识,用于区分不同分配单元 private Long id; // 关联的原始物料(标记为@PlanningPin,避免OptaPlanner修改) @PlanningPin private Material material; // 当前单元的物料数量(可固定为最小单位,如1,或按需设置批次大小) private int quantity; // 规划变量:该单元分配到的容器 @PlanningVariable(valueRangeProviderRefs = "containerRange") private Container container; }
2. 调整规划解决方案模型
将原placement列表替换为固定数量的MaterialAllocation集合,初始时根据物料总数量生成足够的分配单元:
@PlanningSolution @Data @AllArgsConstructor @ToString @NoArgsConstructor public class AllocationSolution { // 规划实体集合:所有待分配的物料单元 @PlanningEntityCollectionProperty private List<MaterialAllocation> materialAllocations; // 容器范围提供者,供规划变量使用 @ValueRangeProvider(id = "containerRange") @ProblemFactCollectionProperty private List<Container> containers; // 原始物料信息(作为问题事实) @ProblemFactCollectionProperty private List<Material> materials; // 评分结果 @PlanningScore private HardSoftScore score; }
3. 初始化解决方案
根据每个物料的总数量,生成对应的MaterialAllocation实体。例如,若某物料总数量为150,可拆分为150个数量为1的单元,或15个数量为10的批次:
public static AllocationSolution createInitialSolution(List<Container> containers, List<Material> materials) { List<MaterialAllocation> allocations = new ArrayList<>(); long idCounter = 0; for (Material material : materials) { int totalQuantity = material.getTotalQuantity(); // 按最小单位拆分(可根据业务调整为批次拆分) for (int i = 0; i < totalQuantity; i++) { allocations.add(new MaterialAllocation(idCounter++, material, 1, null)); } } return new AllocationSolution(allocations, containers, materials, null); }
4. 定义约束规则
通过约束确保分配逻辑符合业务需求,例如:
- 硬约束:每个容器的总物料数量不超过其最大容量(若容器容量已知)
- 硬约束:同一物料的所有分配单元数量总和等于原始物料总数量(避免遗漏或超额)
- 软约束:尽量减少使用的容器数量(若容器数量可变)
- 软约束:优先将同类型物料分配到同一容器(按需添加)
示例约束(使用ConstraintStream API):
public class AllocationConstraintProvider implements ConstraintProvider { @Override public Constraint[] defineConstraints(ConstraintFactory constraintFactory) { return new Constraint[] { // 硬约束:容器总容量不超限 containerCapacityLimit(constraintFactory), // 软约束:减少空容器使用 minimizeEmptyContainers(constraintFactory) }; } private Constraint containerCapacityLimit(ConstraintFactory constraintFactory) { return constraintFactory.from(MaterialAllocation.class) .groupBy(MaterialAllocation::getContainer, sum(MaterialAllocation::getQuantity)) .filter((container, totalQuantity) -> totalQuantity > container.getMaxCapacity()) .penalize("Container capacity exceeded", HardSoftScore.ONE_HARD); } private Constraint minimizeEmptyContainers(ConstraintFactory constraintFactory) { return constraintFactory.from(Container.class) .filter(container -> constraintFactory.from(MaterialAllocation.class) .filter(allocation -> container.equals(allocation.getContainer())) .count() == 0) .penalize("Empty container", HardSoftScore.ONE_SOFT); } }
5. 处理容器数量未知的场景
若你不确定需要多少个容器,可预先生成足够多的空容器(数量大于预估最大值),然后通过minimizeEmptyContainers软约束惩罚空容器,OptaPlanner会自动优化为最少的容器使用量。
内容的提问来源于stack exchange,提问作者ericbin
相关产品推荐
相关产品推荐

