适用场景:APS / 排程系统、使用 ConstraintStream 或 Drools DRL、依赖实时规划(Real-time Planning)
参考来源:OptaPlanner 发展方向与问题
一、升级前评估(必做)
-
[ ] 确认当前版本
-
当前 OptaPlanner 版本:_______(例如 7.44.0.Final)
-
是否使用 Drools DRL 评分:✅ 是 / ❌ 否
-
是否使用链式规划(@PlanningChain/ PlanningVariable(graphType = CHAINED)):✅ 是 / ❌ 否
-
是否使用 VariableListener:✅ 是 / ❌ 否
-
是否使用实时规划(SolverManager.addProblemChange()):✅ 是 / ❌ 否
-
-
[ ] 确认目标版本
-
计划升级到:8.___.Final
-
Spring Boot 版本是否 ≥ 2.7(8.x 最低要求)
-
-
[ ] 阅读官方迁移指南
-
OptaPlanner 8 Migration Guide
-
重点关注 ConstraintStream 与 Drools 的生命周期说明
-
二、依赖与构建配置
-
[ ] 升级 OptaPlanner BOM / Dependency
<dependency>
<groupId>org.optaplanner</groupId>
<artifactId>optaplanner-core</artifactId>
<version>8.x.x.Final</version>
</dependency>
-
[ ] 移除或升级 Drools 相关依赖
-
若计划保留 Drools:确认 optaplanner-drools版本一致
-
若计划迁移:移除 optaplanner-drools、kie-ci等依赖
-
-
[ ] 清理本地构建缓存
-
Maven:mvn clean
-
Gradle:gradle clean build –refresh-dependencies
-
三、API 迁移(核心修改)
1. ConstraintProvider(ApsConstraintProvider.java)
-
[ ] penalize / reward 方法签名调整
// 7.x
.penalize("超时惩罚", HardSoftScore.ONE_HARD);
// 8.x
.penalize(HardSoftScore.ONE_HARD)
.asConstraint("超时惩罚");
-
[ ] 统一约束命名规则
-
所有约束均以 asConstraint("xxx")结尾
-
避免匿名约束,便于调试与分数分析
-
-
[ ] 验证所有 ConstraintStream 流
-
from()/ join()/ ifExists()行为是否变化
-
是否存在因类型推断导致的编译错误
-
2. VariableListener 包路径变更
-
[ ] 修改 import 语句
// 7.x
import org.optaplanner.core.impl.domain.variable.listener.VariableListener;
import org.optaplanner.core.impl.score.director.ScoreDirector;
// 8.x
import org.optaplanner.core.api.domain.variable.VariableListener;
import org.optaplanner.core.api.score.director.ScoreDirector;
-
[ ] 检查所有自定义 VariableListener
-
文件名示例:*VariableListener.java
-
确认无 impl包残留引用
-
3. ScoreDirector API 变更
-
[ ] 字符串属性名 → 方法引用
// 7.x
scoreDirector.beforeVariableChanged(entity, "planStartTime");
scoreDirector.afterVariableChanged(entity, "planStartTime");
// 8.x
scoreDirector.beforeVariableChanged(entity, Entity::getPlanStartTime);
scoreDirector.afterVariableChanged(entity, Entity::getPlanStartTime);
-
[ ] 全局搜索关键词
-
beforeVariableChanged
-
afterVariableChanged
-
variableChanged
-
四、实时规划(Real-time Planning)适配
1. ProblemChange 接口统一
-
[ ] 确认所有实时变更逻辑已迁移到 ProblemChange
public class AddTaskProblemChange implements ProblemChange<Schedule> {
@Override
public void doChange(Schedule schedule, ScoreDirector<Schedule> scoreDirector) {
// …
}
}
-
[ ] 移除旧版实时规划相关代码
-
Solver.addEntity()
-
Solver.removeEntity()
-
Solver.addProblemFact()
-
2. SolverManager Problem ID 治理(⚠️ 重要)
参考博文:SolverManager 存在 Problem ID 复用异常问题
-
[ ] 平台侧接管 Problem ID 生成
-
客户端传入业务 ID(如 orderId)
-
平台生成内部 problemId(UUID / 自增 ID)
-
-
[ ] 接口层改造
-
启动规划:返回内部 problemId
-
查询 / 终止 / 实时变更:使用内部 problemId
-
-
[ ] 增加 Problem ID 清理机制
-
规划完成后主动调用 solverManager.close(solverJobId)
-
避免异常中断导致状态残留
-
五、链式规划与新特性评估
1. 现有链模型(CHAINED)
-
[ ] 暂不迁移到 @PlanningListVariable
-
确认当前链模型运行稳定
-
8.x 新链模型尚未完全成熟(参考博文)
-
-
[ ] 验证 Shadow Variable 行为
-
@CustomShadowVariable监听器是否正常触发
-
时间计算逻辑是否与之前一致
-
2. 新特性试用(可选)
-
[ ] @PlanningListVariable(仅限新模块)
-
明确标注为“实验性功能”
-
准备回退方案
-
-
[ ] @IndexShadowVariable
-
仅在非核心链路中试用
-
六、Drools DRL 迁移(长期必做)
Drools DRL 将在 OptaPlanner 9.x 移除
-
[ ] 制定 DRL → ConstraintStream 迁移计划
-
优先级:核心约束 > 次要约束 > 调试约束
-
-
[ ] 增量迁移
-
每次迁移 1–2 条约束
-
对比新旧分数结果一致性
-
-
[ ] 或评估 Incremental Java Score Calculation
-
性能要求极高时考虑
-
实现成本较高(参考博文)
-
七、测试与验证
-
[ ] 单元测试
-
所有 ConstraintProvider 测试通过
-
边界条件(空集合、单实体)验证
-
-
[ ] 集成测试
-
典型业务场景全量规划
-
实时规划(添加 / 删除任务)验证
-
-
[ ] 回归测试
-
与 7.x 在相同数据集上运行
-
对比解的质量与分数构成
-
允许分数结构变化,但业务结果应一致
-
-
[ ] 性能测试
-
规划耗时是否显著增加
-
GC / CPU 使用率是否在可接受范围
-
八、部署与回滚预案
-
[ ] 灰度发布
-
先在非核心业务线启用 8.x
-
观察 1–2 个迭代周期
-
-
[ ] 回滚方案
-
Git tag / 分支保留 7.x 稳定版本
-
数据库 schema 无破坏性变更(如有需单独处理)
-
-
[ ] 监控增强
-
Solver 执行时长监控
-
Problem ID 泄漏检测
-
异常 SolverJob 自动清理
-
九、升级完成确认
-
[ ] 所有 javax.*/ impl包引用已清除
-
[ ] 所有约束均有 asConstraint()命名
-
[ ] 实时规划功能经生产流量验证
-
[ ] 团队已了解 8.x API 变化点
-
[ ] 文档已更新(架构图、API 说明)
附录:常见搜索关键词(用于全局替换)
beforeVariableChanged
afterVariableChanged
VariableListener
ScoreDirector
penalize(
reward(
impl.domain.variable
impl.score.director
✅ 预计修改工作量:2–3 小时
✅ 主要风险点:SolverManager Problem ID 管理、新链模型成熟度
✅ 推荐节奏:先升级 + 稳定 API,再逐步迁移 Drools




