You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ValueSelector阻止特定移动时触发ClassCastException问题排查

OptaPlanner移动过滤器实现问题

问题背景

我有一个包含startTime规划变量和固定时长的Lecture类,想要过滤掉那些会导致结束时间超过16:00的移动操作。

编写的选择过滤器代码

public class LectureOutOfBoundsSelectionFilter
        implements SelectionFilter<Schedule, Lecture> {

    @Override
    public boolean accept(ScoreDirector<Schedule> sd, Lecture lecture) {
        return !lecture.isOutOfBounds();
    }
}

配置文件内容

<changeMoveSelector>
    <filterClass>package.PinnedTimeslotChangeMoveFilter</filterClass>
    <valueSelector>
        <filterClass>packager.LectureOutOfBoundsSelectionFilter</filterClass>
    </valueSelector>
</changeMoveSelector>

遇到的异常

  • 直接使用上述配置时,出现与Lecture类中另一个规划变量相关的ClassCastException;
  • 尝试添加variableName="startTime"属性后,触发了另一种类型转换异常。

疑问

  1. 我的实现思路是否正确?
  2. variableName属性的实际作用是什么?

解答

1. 实现思路的问题

你的核心需求方向是对的,但过滤器的类型和使用位置选错了:

  • 当前的LectureOutOfBoundsSelectionFilter是用来过滤Lecture实体的,而你需要的是过滤会导致结束时间超标的移动操作(或对应的变量值);
  • valueSelector中的过滤器应该针对startTime的变量值类型(比如Timeslot),而非Lecture实体本身,这是导致类型转换异常的直接原因。

更合适的方案是使用MoveFilter直接判断移动操作是否合法,或者调整valueSelector的过滤器为变量值类型的过滤器。

2. variableName的实际作用

当一个实体(比如Lecture)拥有多个规划变量时(比如startTime和room),variableName用来明确指定当前移动选择器操作的目标规划变量:

  • 不指定该属性时,框架会默认处理实体的所有规划变量,导致你的过滤器被错误应用到其他变量的类型上,引发第一次的ClassCastException;
  • 添加variableName后,框架会聚焦到startTime变量,但你的过滤器仍然是针对Lecture实体的,和valueSelector需要的变量值类型不匹配,所以还是会触发类型转换异常。

修正方案

推荐使用MoveFilter直接过滤非法的移动操作,示例代码如下:

public class LectureMoveOutOfBoundsFilter implements MoveFilter<Schedule> {
    @Override
    public boolean accept(ScoreDirector<Schedule> scoreDirector, Move<Schedule> move) {
        // 只处理ChangeMove类型的操作
        if (!(move instanceof ChangeMove)) {
            return true;
        }
        ChangeMove<Schedule> changeMove = (ChangeMove<Schedule>) move;
        Lecture lecture = (Lecture) changeMove.getEntity();
        Timeslot newTimeslot = (Timeslot) changeMove.getValue();
        
        // 计算结束时间并判断是否超过16:00
        LocalTime endTime = newTimeslot.getStartTime().plusMinutes(lecture.getDuration());
        return !endTime.isAfter(LocalTime.of(16, 0));
    }
}

对应的配置调整为:

<changeMoveSelector>
    <filterClass>package.LectureMoveOutOfBoundsFilter</filterClass>
    <variableName="startTime"/>
</changeMoveSelector>

这样就能精准过滤掉所有会导致Lecture结束时间超过16:00的startTime变更操作。


内容的提问来源于stack exchange,提问作者aioobe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 11:44:53