OptaPlanner的Drools规则不会在类路径上使用Spring Boot的devtools触发,因此得分为零

问题描述 投票:2回答:2

我有optaplanner正确使用drools规则。 “突然”,在我做了一些改变后,Optaplanner不再把我的事实放在流氓kSession中了。

我进行了一些日志记录,我看到optaplanner在我的Solution上调用了getProblemFacts()方法,这个方法返回一个大小> 0的列表。

我写了一个DRL规则来简单地统计事实并记录这些计数(这个规则经过单元测试,当我把对象放在ksession中时效果很好)。我也相信,optaplanner并没有把事实放在工作记忆中。

ConstructionHeuristics阶段很好地终止(并且它的工作正常,因为在此阶段之后我的PlaningVariables不再为null)。我只在LocalSearch开始时才遇到我的问题。

不知道如何/在哪里进一步搜索以了解问题。有任何想法吗?

我有一个建议:我使用<scanAnnotatedClasses/>并有这个问题。如果我使用<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$0(SolverServiceImpl.java:169)
spring-boot drools optaplanner
2个回答
4
投票

我正在使用spring dev工具在源文件中自动重新加载我的webapp uppon更改。

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>

这是问题所在。为了执行热重新加载,项目的所有资源和类都由spring的RestartClassLoader加载和监视,但是Librairies(依赖项,例如Drools和Optaplanner)由Base ClassLoader加载(实际上是AppClassLoader)。因此存在问题。

要修复它,配置spring dev工具以在RestartClassLoader中加载Drools librairies,以及项目的类: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,因为类不是“相同”。


0
投票

在我的应用程序中,我到处都有org.springframework.boot.devtools.restart.classloader.RestartClassLoader

那不是默认的类加载器,所以有类加载魔法。根据你的评论,它与用于加载optaplanner类的类加载器不同。所以你需要提供你的类加载器:

Classloader classloader = TimeTable.class.getClassLoader();
... = SolverFactory.createFromXmlResource(".../solverConfig.xml", classloader);

可能需要升级到6.4.0.Beta2,我上个月修复了一些高级类加载问题。


0
投票

问题应该在Drools 7.23.0.Final中解决。见https://issues.jboss.org/browse/DROOLS-1540

© www.soinside.com 2019 - 2024. All rights reserved.