Optaplanner 7.48迁移至8.3.0时Drools ExpressionTyper异常问题咨询
OptaPlanner 版本迁移过程中的DRL规则兼容问题
迁移背景
项目从 OptaPlanner 7.48(对应依赖 Drools 7.48 版本)迁移至 OptaPlanner 8.3.0(对应依赖 Drools 7.50 版本)时,原有DRL规则无法正常运行,初步推断问题根源与 Drools 7.50 版本的规则解析逻辑变化相关。
迁移前可正常运行的DRL规则
rule "applyHomeTeamConstraints" enabled true when $f1: ProblemFixture(slot != null, $ht: homeTeam) $tu: ProblemSoftConstraint(this memberOf $ht.constraints, matches($f1.slot.dateTime) ) then scoreHolder.penalize(kcontext, -$tu.getWeight()); end
异常表现
上述规则在 OptaPlanner 7.48/Drools 7.48 环境下可正常编译运行,切换到新版本环境后抛出定位信息极度模糊的异常,早期堆栈压缩状态下的报错内容为:
java.lang.IllegalStateException: There is an error in a scoreDrl or scoreDrlFile. at uk.me.selwyn_family.league.scheduler.solver.SolverTest.testBuildSeasonSolver(SolverTest.java:47) Caused by: java.lang.UnsupportedOperationException at uk.me.selwyn_family.league.scheduler.solver.SolverTest.testBuildSeasonSolver(SolverTest.java:47)
排查过程
- 逐行定位异常后,确认错误实际抛出位置为
org.drools.modelcompiler.builder.generator.expressiontyper.ExpressionTyper类的第243行,对应源码逻辑为:Expression parentLeft = findLeftLeafOfNameExpr(halfPointFreeExpr.getParentNode().orElseThrow(UnsupportedOperationException::new)); - 异常触发的直接原因是代码中获取的父节点对象为空,抛出的异常未携带任何规则解析的上下文信息,大幅增加排查成本。
- 临时解决方案:在
matches()方法调用前补充this.关键字,即可绕开解析异常,修改后的规则片段为:rule "applyHomeTeamConstraints" enabled true when $f1: ProblemFixture(slot != null, $ht: homeTeam) $tu: ProblemSoftConstraint(this memberOf $ht.constraints, this.matches($f1.slot.dateTime) ) then scoreHolder.penalize(kcontext, -$tu.getWeight()); end
核心待确认问题
- 旧版本下不带
this.的方法调用写法可正常运行,是否属于旧版本解析的兼容疏漏、本身不符合Drools语法规范,还是Drools 7.50 版本引入的解析bug? - 该场景下的编译报错信息缺失关键上下文,排查耗时极长,是否能优化错误提示的清晰度,让用户直接定位到规则内的具体语法问题?
关闭堆栈压缩后的完整异常栈
java.lang.IllegalStateException: There is an error in a scoreDrl or scoreDrlFile. at org.optaplanner.core.impl.score.director.ScoreDirectorFactoryFactory.buildDroolsScoreDirectorFactory(ScoreDirectorFactoryFactory.java:280) at org.optaplanner.core.impl.score.director.ScoreDirectorFactoryFactory.decideMultipleScoreDirectorFactories(ScoreDirectorFactoryFactory.java:103) at org.optaplanner.core.impl.score.director.ScoreDirectorFactoryFactory.buildScoreDirectorFactory(ScoreDirectorFactoryFactory.java:68) at org.optaplanner.core.impl.solver.DefaultSolverFactory.buildScoreDirectorFactory(DefaultSolverFactory.java:116) at org.optaplanner.core.impl.solver.DefaultSolverFactory.getScoreDirectorFactory(DefaultSolverFactory.java:73) at org.optaplanner.core.api.score.ScoreManager.create(ScoreManager.java:59) at uk.me.selwyn_family.league.scheduler.solver.SeasonSolver.<init>(SeasonSolver.java:31) at uk.me.selwyn_family.league.scheduler.solver.SolverTest.testBuildSeasonSolver(SolverTest.java:47) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:85) at org.testng.internal.Invoker.invokeMethod(Invoker.java:696) at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:882) at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1189) at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:124) at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:108) at org.testng.TestRunner.privateRun(TestRunner.java:767) at org.testng.TestRunner.run(TestRunner.java:617) at org.testng.SuiteRunner.runTest(SuiteRunner.java:348) at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:343) at org.testng.SuiteRunner.privateRun(SuiteRunner.java:305) at org.testng.SuiteRunner.run(SuiteRunner.java:254) at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52) at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86) at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224) at org.testng.TestNG.runSuitesLocally(TestNG.java:1149) at org.testng.TestNG.run(TestNG.java:1057) at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:136) at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.executeSingleClass(TestNGDirectoryTestSuite.java:112) at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.execute(TestNGDirectoryTestSuite.java:99) at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:145) at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:428) at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162) at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:562) at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:548) Caused by: java.lang.UnsupportedOperationException at java.base/java.util.Optional.orElseThrow(Optional.java:408) at org.drools.modelcompiler.builder.generator.expressiontyper.ExpressionTyper.toTypedExpressionRec(ExpressionTyper.java:243) at org.drools.modelcompiler.builder.generator.expressiontyper.ExpressionTyper.toTypedExpression(ExpressionTyper.java:153) at org.drools.modelcompiler.builder.generator.drlxparse.ConstraintParser.getDrlxParseResult(ConstraintParser.java:174) at org.drools.modelcompiler.builder.generator.drlxparse.ConstraintParser.drlxParse(ConstraintParser.java:104) at org.drools.modelcompiler.builder.generator.visitor.pattern.PatternDSL.findAllConstraint(PatternDSL.java:139) at org.drools.modelcompiler.builder.generator.visitor.pattern.PatternDSL.buildPattern(PatternDSL.java:241) at org.drools.modelcompiler.builder.generator.visitor.ModelGeneratorVisitor.visit(ModelGeneratorVisitor.java:145) at org.drools.compiler.lang.descr.PatternDescr.accept(PatternDescr.java:303) at org.drools.modelcompiler.builder.generator.visitor.AndVisitor.visit(AndVisitor.java:50) at org.drools.modelcompiler.builder.generator.visitor.ModelGeneratorVisitor.visit(ModelGeneratorVisitor.java:86) at org.drools.modelcompiler.builder.generator.ModelGenerator.processRule(ModelGenerator.java:187) at org.drools.modelcompiler.builder.generator.ModelGenerator.generateModel(ModelGenerator.java:160) at org.drools.modelcompiler.builder.ModelBuilderImpl.compileKnowledgePackages(ModelBuilderImpl.java:284) at org.drools.modelcompiler.builder.ModelBuilderImpl.buildRules(ModelBuilderImpl.java:220) at org.drools.modelcompiler.builder.ModelBuilderImpl.postBuild(ModelBuilderImpl.java:130) at org.drools.compiler.builder.impl.CompositeKnowledgeBuilderImpl.build(CompositeKnowledgeBuilderImpl.java:115) at org.drools.compiler.builder.impl.CompositeKnowledgeBuilder.build(CompositeKnowledgeBuilder.java:99) at org.drools.compiler.kie.builder.impl.AbstractKieProject.buildKnowledgePackages(AbstractKieProject.java:268) at org.drools.compiler.kie.builder.impl.AbstractKieProject.buildKnowledgePackages(AbstractKieProject.java:216) at org.drools.compiler.kie.builder.impl.AbstractKieProject.verify(AbstractKieProject.java:80) at org.drools.compiler.kie.builder.impl.KieBuilderImpl.buildKieProject(KieBuilderImpl.java:277) at org.drools.compiler.kie.builder.impl.KieBuilderImpl.buildAll(KieBuilderImpl.java:245) at org.drools.compiler.kie.builder.impl.KieBuilderImpl.buildAll(KieBuilderImpl.java:202) at org.kie.internal.utils.KieHelper.getKieContainer(KieHelper.java:100) at org.kie.internal.utils.KieHelper.build(KieHelper.java:82) at org.optaplanner.core.impl.score.director.ScoreDirectorFactoryFactory.buildDroolsScoreDirectorFactory(ScoreDirectorFactoryFactory.java:272) ... 36 more
内容的提问来源于stack exchange,提问作者Chris Selwyn
相关产品推荐
相关产品推荐

