代码之家  ›  专栏  ›  技术社区  ›  aioobe

由于groupBy操作,OptaPlanner中出现ClassCastException

  •  0
  • aioobe  · 技术社区  · 4 年前

    我正在创建一个学校时间表生成器,我的一个约束条件出现了一个例外,它检查所有学生是否每天都有午休时间。

    public Constraint studentsShouldHaveLunchEveryDay(ConstraintFactory cf) {
        return cf.from(RecurringLecture.class)
                .filter(RecurringLecture::isScheduled)                     // [Lecture]...
                .groupBy(l -> l, l -> l.getCourseRound().getStudents())    // [Lecture, Set<Student>]...
                .flattenLast(students -> students)                         // [Lecture, Student]...
                .groupBy((l, s) -> s,                                      // [Student, Map<Day, Set<Lecture>>]...
                        ConstraintCollectors.toMap(
                                (l, s) -> l.getStartTimeslot().getDay(),
                                (l, s) -> l))
                //.flattenLast(Map::values)                                // [Student, Set<Lecture>]...
                //.filter((student, dailyLectures) -> !LunchBreakAnalyzer.hasLunchBreak(dailyLectures))
                .penalize(StudentLunchProblem.class.getName(), HardSoftScore.ONE_HARD);
    }
    

    我暂时将 flattenLast filter 由于调试原因,问题仍然存在。如果我把最后一个注释掉 groupBy

    Student ( ImmutableStudent 精确地说)到 Object[] .

    框架中抛出的行位于 ArrayElementReader 看起来像这样:

    public Object getValue(InternalWorkingMemory workingMemory,
                           Object object) {
        Object[] array = (Object[]) this.arrayReadAccessor.getValue( workingMemory,
                                                                     object );
        return array[this.index];
    }
    

    完整异常如下所示:

    java.util.concurrent.ExecutionException: java.lang.IllegalStateException: The move thread with moveThreadIndex (1) has thrown an exception. Relayed here in the parent thread.
        at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
        at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
        at java.desktop/javax.swing.SwingWorker.get(SwingWorker.java:613)
        at vngschedules.ui.automation.AutomationPanel$1$1.done(AutomationPanel.java:44)
        at java.desktop/javax.swing.SwingWorker$5.run(SwingWorker.java:750)
        at java.desktop/javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(SwingWorker.java:847)
        at java.desktop/sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112)
        at java.desktop/javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(SwingWorker.java:857)
        at java.desktop/javax.swing.Timer.fireActionPerformed(Timer.java:317)
        at java.desktop/javax.swing.Timer$DoPostEvent.run(Timer.java:249)
        at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
        at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
        at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
        at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
        at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
        at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
        at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
        at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
        at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
        at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
        at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
    Caused by: java.lang.IllegalStateException: The move thread with moveThreadIndex (1) has thrown an exception. Relayed here in the parent thread.
        at org.optaplanner.core.impl.heuristic.thread.OrderByMoveIndexBlockingQueue.take(OrderByMoveIndexBlockingQueue.java:147)
        at org.optaplanner.core.impl.localsearch.decider.MultiThreadedLocalSearchDecider.forageResult(MultiThreadedLocalSearchDecider.java:189)
        at org.optaplanner.core.impl.localsearch.decider.MultiThreadedLocalSearchDecider.decideNextStep(MultiThreadedLocalSearchDecider.java:160)
        at org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:95)
        at org.optaplanner.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:99)
        at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:192)
    Caused by: java.lang.IllegalStateException: The move thread with moveThreadIndex (1) has thrown an exception. Relayed here in the parent thread.
    
        at vngschedules.ui.automation.SolverSwingWorker.doInBackground(SolverSwingWorker.java:29)
        at vngschedules.ui.automation.SolverSwingWorker.doInBackground(SolverSwingWorker.java:10)
        at java.desktop/javax.swing.SwingWorker$1.call(SwingWorker.java:304)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at java.desktop/javax.swing.SwingWorker.run(SwingWorker.java:343)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.base/java.lang.Thread.run(Thread.java:834)
    Caused by: java.lang.ClassCastException: class vngschedules.schedule.ImmutableStudent cannot be cast to class [Ljava.lang.Object; (vngschedules.schedule.ImmutableStudent is in unnamed module of loader 'app'; [Ljava.lang.Object; is in module java.base of loader 'bootstrap')
        at org.drools.core.base.extractors.ArrayElementReader.getValue(ArrayElementReader.java:162)
        at org.drools.core.base.extractors.ArrayElementReader.getValue(ArrayElementReader.java:279)
        at org.drools.modelcompiler.KiePackagesBuilder.lambda$getBindingFunction$66de2761$1(KiePackagesBuilder.java:794)
        at org.drools.modelcompiler.constraints.LambdaReadAccessor.getValue(LambdaReadAccessor.java:43)
        at org.drools.core.rule.Declaration.getValue(Declaration.java:257)
        at org.optaplanner.core.impl.score.stream.drools.common.AbstractAccumulator.extractValue(AbstractAccumulator.java:42)
    Caused by: java.lang.ClassCastException: class vngschedules.schedule.ImmutableStudent cannot be cast to class [Ljava.lang.Object; (vngschedules.schedule.ImmutableStudent is in unnamed module of loader 'app'; [Ljava.lang.Object; is in module java.base of loader 'bootstrap')
    
        at org.optaplanner.core.impl.score.stream.drools.common.BiAccumulator.accumulate(BiAccumulator.java:55)
        at org.drools.core.rule.SingleAccumulate.accumulate(SingleAccumulate.java:96)
        at org.drools.modelcompiler.constraints.LambdaGroupByAccumulate.accumulate(LambdaGroupByAccumulate.java:121)
        at org.drools.modelcompiler.constraints.LambdaGroupByAccumulate.accumulate(LambdaGroupByAccumulate.java:114)
        at org.drools.core.phreak.PhreakAccumulateNode.addMatch(PhreakAccumulateNode.java:736)
        at org.drools.core.phreak.PhreakAccumulateNode.doRightInserts(PhreakAccumulateNode.java:253)
        at org.drools.core.phreak.PhreakAccumulateNode.doNode(PhreakAccumulateNode.java:99)
        at org.drools.core.phreak.RuleNetworkEvaluator.switchOnDoBetaNode(RuleNetworkEvaluator.java:586)
        at org.drools.core.phreak.RuleNetworkEvaluator.evalBetaNode(RuleNetworkEvaluator.java:555)
        at org.drools.core.phreak.RuleNetworkEvaluator.evalNode(RuleNetworkEvaluator.java:382)
        at org.drools.core.phreak.RuleNetworkEvaluator.innerEval(RuleNetworkEvaluator.java:342)
        at org.drools.core.phreak.RuleNetworkEvaluator.evalStackEntry(RuleNetworkEvaluator.java:240)
        at org.drools.core.phreak.RuleNetworkEvaluator.outerEval(RuleNetworkEvaluator.java:183)
        at org.drools.core.phreak.RuleNetworkEvaluator.evaluateNetwork(RuleNetworkEvaluator.java:136)
        at org.drools.core.phreak.RuleExecutor.reEvaluateNetwork(RuleExecutor.java:235)
        at org.drools.core.phreak.RuleExecutor.evaluateNetworkAndFire(RuleExecutor.java:91)
        at org.drools.core.concurrent.AbstractRuleEvaluator.internalEvaluateAndFire(AbstractRuleEvaluator.java:33)
        at org.drools.core.concurrent.SequentialRuleEvaluator.evaluateAndFire(SequentialRuleEvaluator.java:43)
        at org.drools.core.common.DefaultAgenda.fireLoop(DefaultAgenda.java:869)
        at org.drools.core.common.DefaultAgenda.internalFireAllRules(DefaultAgenda.java:816)
        at org.drools.core.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:808)
        at org.drools.core.impl.StatefulKnowledgeSessionImpl.internalFireAllRules(StatefulKnowledgeSessionImpl.java:1343)
        at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1334)
        at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1326)
        at org.optaplanner.core.impl.score.director.stream.DroolsConstraintStreamScoreDirector.calculateScore(DroolsConstraintStreamScoreDirector.java:90)
        at org.optaplanner.core.impl.score.director.AbstractScoreDirector.doAndProcessMove(AbstractScoreDirector.java:220)
        at org.optaplanner.core.impl.heuristic.thread.MoveThreadRunner.run(MoveThreadRunner.java:147)
        at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        ... 3 more
    

    我已经注释掉了程序中的所有其他约束流。

    问题

    1. 这看起来像是我的代码中的错误,还是OptaPlanner的问题?

    如果需要,很乐意提供更多类型,但是 RecurringLecture 其实很简单 是编译成 .

    我正在使用OptaPlanner 8.12.0.Final和Java 11。

    使现代化

    public Constraint studentsShouldHaveLunchEveryDay(ConstraintFactory cf) {
        return cf.from(RecurringLecture.class)
                .filter(RecurringLecture::isScheduled)                     // [Lecture]...
                .groupBy(l -> l, l -> l.getCourseRound().getStudents())    // [Lecture, Set<Student>]...
                .flattenLast(students -> students)                         // [Lecture, Student]...
                .groupBy((l, s) -> ImmutableStudentAndDay.of(s, l.getStartTimeslot().getDay()),
                        ConstraintCollectors.toSet((l, s) -> l))
                .filter((student, dailyLectures) -> !LunchBreakAnalyzer.hasLunchBreak(dailyLectures))
                .penalize(StudentLunchProblem.class.getName(), HardSoftScore.ONE_HARD);
    }
    

    这避免了 toMap 收藏家。然而,我仍然遇到了完全相同的问题。

    0 回复  |  直到 4 年前
        1
  •  1
  •   LukáÅ¡ Petrovický    4 年前

    一般来说,如果约束编译后代码仍然抛出 ClassCastException

    我建议重构约束,使其看起来像这样:

    public Constraint studentsShouldHaveLunchEveryDay(ConstraintFactory cf) {
        return cf.from(RecurringLecture.class)
            .filter(RecurringLecture::isScheduled)
            .join(Student.class,
                  Joiners.filtering((l, s) -> l.getCourseRound().getStudents().contains(s)))
            .groupBy((l, s) -> ImmutableStudentAndDay.of(s, l.getStartTimeslot().getDay()),
                    ConstraintCollectors.toSet((l, s) -> l))
            .filter((student, dailyLectures) -> !LunchBreakAnalyzer.hasLunchBreak(dailyLectures))
            .penalize(StudentLunchProblem.class.getName(), HardSoftScore.ONE_HARD);
    }
    

    我希望这会表现得更好,也可能会消除这个异常。无论如何,异常仍然是一个问题,如果您提供简化的可执行复制程序,我将进一步调查它。