OptaPlanner 的 Drools 规则不会在类路径上使用 Spring Boot 的 devtools 触发,因此分数为零
OptaPlanner's Drools rules don't fire with Spring Boot's devtools on the classpath so the score is zero
我让 optaplanner 使用 drools 规则正常工作。
"Suddenly",在我做了一些更改之后,Optaplanner 不再将我的事实放入 drools kSession 中。
我记录了一些日志,我看到 optaplanner 在我的解决方案上调用了 getProblemFacts() 方法,这个方法 returns 一个大小 > 0 的列表。
我写了一个 DRL 规则来简单地计算事实并记录这些计数(这个规则经过单元测试,当我自己将对象放入 ksession 时效果很好)。我也深信optaplanner不会把事实放到working memory中。
ConstructionHeuristics 阶段结束得很好(并且它的工作,因为我的 PlaningVariables 在这个阶段之后不再为空)。只有在 LocalSearch 开始时我才遇到问题。
不知道how/where进一步搜索以了解问题。有什么想法吗?
我有一个建议:我使用 <scanAnnotatedClasses/>
并遇到了这个问题。
如果我将两个 类 "manually" 使用 <solutionClass/>
和 <entityClass/>
然后我得到一个反射错误:
Exception in thread "Solver" java.lang.IllegalArgumentException: object is not an instance of declaring class
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.optaplanner.core.impl.domain.common.accessor.BeanPropertyMemberAccessor.executeGetter(BeanPropertyMemberAccessor.java:67)
at org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor.extractEntityCollection(SolutionDescriptor.java:626)
at org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor.getEntityCount(SolutionDescriptor.java:489)
at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner$FieldAccessingSolutionClonerRun.cloneSolution(FieldAccessingSolutionCloner.java:200)
at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner.cloneSolution(FieldAccessingSolutionCloner.java:70)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.cloneSolution(AbstractScoreDirector.java:147)
at org.optaplanner.core.impl.solver.scope.DefaultSolverScope.setWorkingSolutionFromBestSolution(DefaultSolverScope.java:197)
at org.optaplanner.core.impl.solver.DefaultSolver.solvingStarted(DefaultSolver.java:195)
at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:175)
at ****.services.impl.SolverServiceImpl.lambda[=11=](SolverServiceImpl.java:169)
In my app I have everywhere an
org.springframework.boot.devtools.restart.classloader.RestartClassLoader
这不是默认的类加载器,因此类加载魔法正在发生。根据您的评论,它与用于加载 optaplanner 类 的类加载器不同。所以你需要提供你的类加载器:
Classloader classloader = TimeTable.class.getClassLoader();
... = SolverFactory.createFromXmlResource(".../solverConfig.xml", classloader);
可能需要升级到 6.4.0.Beta2
,我上个月修复了一些高级类加载问题。
我正在使用 spring 开发工具根据源文件中的更改自动重新加载我的 Web 应用程序。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
这就是问题所在。要执行热重载,项目的所有资源和 类 都由 spring 的 RestartClassLoader
加载和监视,但库(依赖项,例如 Drools 和 Optaplanner)由 Base ClassLoader 加载(实际上 AppClassLoader
)。因此问题。
要修复它,请配置 spring 开发工具以在 RestartClassLoader 中加载 Drools 库,以及项目的 类:
using-boot-devtools-customizing-classload
所以我的问题不是很好命名。 Drools 工作内存不为空,但包含不属于 instanceof
我 类 的对象,因为不在同一个 ClassLoader 中。
为了理解这一点,我使用了以下规则:
rule "countProblemFacts"
when
$nLectures : Long() from accumulate($lectures : Lecture(), count( $lectures ))
$nCourses : Long() from accumulate($courses : Course(), count( $courses ))
$nRooms : Long() from accumulate($rooms : Room(), count( $rooms ))
$nPeriods : Long() from accumulate($periods : Period(), count( $periods ))
$nObjects : Long() from accumulate($objects : Object(), count( $objects ))
then
DroolsUtil.log(drools, "Drools working memory");
DroolsUtil.log("Lectures:", $nLectures);
DroolsUtil.log("Courses:", $nCourses);
DroolsUtil.log("Rooms:", $nRooms);
DroolsUtil.log("Periods:", $nPeriods);
DroolsUtil.log("Objects:", $nObjects);
DroolsUtil.log(drools, "Total", ($nLectures + $nCourses + $nRooms + $nPeriods), "objects");
end
$nObjects 计数为 12,所有其他对象计数为 0,因为 类 不是 "the same".
问题应该在 Drools 7.23 中解决。0.Final。参见 https://issues.jboss.org/browse/DROOLS-1540。
我让 optaplanner 使用 drools 规则正常工作。 "Suddenly",在我做了一些更改之后,Optaplanner 不再将我的事实放入 drools kSession 中。
我记录了一些日志,我看到 optaplanner 在我的解决方案上调用了 getProblemFacts() 方法,这个方法 returns 一个大小 > 0 的列表。
我写了一个 DRL 规则来简单地计算事实并记录这些计数(这个规则经过单元测试,当我自己将对象放入 ksession 时效果很好)。我也深信optaplanner不会把事实放到working memory中。
ConstructionHeuristics 阶段结束得很好(并且它的工作,因为我的 PlaningVariables 在这个阶段之后不再为空)。只有在 LocalSearch 开始时我才遇到问题。
不知道how/where进一步搜索以了解问题。有什么想法吗?
我有一个建议:我使用 <scanAnnotatedClasses/>
并遇到了这个问题。
如果我将两个 类 "manually" 使用 <solutionClass/>
和 <entityClass/>
然后我得到一个反射错误:
Exception in thread "Solver" java.lang.IllegalArgumentException: object is not an instance of declaring class
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.optaplanner.core.impl.domain.common.accessor.BeanPropertyMemberAccessor.executeGetter(BeanPropertyMemberAccessor.java:67)
at org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor.extractEntityCollection(SolutionDescriptor.java:626)
at org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor.getEntityCount(SolutionDescriptor.java:489)
at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner$FieldAccessingSolutionClonerRun.cloneSolution(FieldAccessingSolutionCloner.java:200)
at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner.cloneSolution(FieldAccessingSolutionCloner.java:70)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.cloneSolution(AbstractScoreDirector.java:147)
at org.optaplanner.core.impl.solver.scope.DefaultSolverScope.setWorkingSolutionFromBestSolution(DefaultSolverScope.java:197)
at org.optaplanner.core.impl.solver.DefaultSolver.solvingStarted(DefaultSolver.java:195)
at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:175)
at ****.services.impl.SolverServiceImpl.lambda[=11=](SolverServiceImpl.java:169)
In my app I have everywhere an
org.springframework.boot.devtools.restart.classloader.RestartClassLoader
这不是默认的类加载器,因此类加载魔法正在发生。根据您的评论,它与用于加载 optaplanner 类 的类加载器不同。所以你需要提供你的类加载器:
Classloader classloader = TimeTable.class.getClassLoader();
... = SolverFactory.createFromXmlResource(".../solverConfig.xml", classloader);
可能需要升级到 6.4.0.Beta2
,我上个月修复了一些高级类加载问题。
我正在使用 spring 开发工具根据源文件中的更改自动重新加载我的 Web 应用程序。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
这就是问题所在。要执行热重载,项目的所有资源和 类 都由 spring 的 RestartClassLoader
加载和监视,但库(依赖项,例如 Drools 和 Optaplanner)由 Base ClassLoader 加载(实际上 AppClassLoader
)。因此问题。
要修复它,请配置 spring 开发工具以在 RestartClassLoader 中加载 Drools 库,以及项目的 类: using-boot-devtools-customizing-classload
所以我的问题不是很好命名。 Drools 工作内存不为空,但包含不属于 instanceof
我 类 的对象,因为不在同一个 ClassLoader 中。
为了理解这一点,我使用了以下规则:
rule "countProblemFacts"
when
$nLectures : Long() from accumulate($lectures : Lecture(), count( $lectures ))
$nCourses : Long() from accumulate($courses : Course(), count( $courses ))
$nRooms : Long() from accumulate($rooms : Room(), count( $rooms ))
$nPeriods : Long() from accumulate($periods : Period(), count( $periods ))
$nObjects : Long() from accumulate($objects : Object(), count( $objects ))
then
DroolsUtil.log(drools, "Drools working memory");
DroolsUtil.log("Lectures:", $nLectures);
DroolsUtil.log("Courses:", $nCourses);
DroolsUtil.log("Rooms:", $nRooms);
DroolsUtil.log("Periods:", $nPeriods);
DroolsUtil.log("Objects:", $nObjects);
DroolsUtil.log(drools, "Total", ($nLectures + $nCourses + $nRooms + $nPeriods), "objects");
end
$nObjects 计数为 12,所有其他对象计数为 0,因为 类 不是 "the same".
问题应该在 Drools 7.23 中解决。0.Final。参见 https://issues.jboss.org/browse/DROOLS-1540。