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

使用OptaPlanner Spring Boot Starter配置ListChangeMove过滤器

How to Configure ListChangeMove Filter with OptaPlanner Spring Boot Starter (No XML)

Got it, let's tackle this problem step by step. Since you're using the OptaPlanner Spring Boot Starter and avoiding XML configs, you'll need to define your move selector filters programmatically using either the SolverConfig API or OptaPlanner's annotation-based configuration.

First, a quick note on why your XML config might not have worked: when using the Spring Boot Starter, Java-based configuration often takes priority over XML, or your filter class might have had a typo in its fully qualified name, or wasn't being scanned properly by the Spring context. Let's jump straight to the working programmatic approaches.

1. Configure via SolverConfig @Bean

You can define a SolverConfig bean directly in your Spring configuration, building out the local search phase and move selector with your filter:

import org.optaplanner.core.config.solver.SolverConfig;
import org.optaplanner.core.config.phase.LocalSearchPhaseConfig;
import org.optaplanner.core.config.heuristic.selector.move.composite.UnionMoveSelectorConfig;
import org.optaplanner.core.config.heuristic.selector.move.generic.ListChangeMoveSelectorConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OptaPlannerConfig {

    @Bean
    public SolverConfig solverConfig() {
        // Start with a base default config (or build entirely from scratch)
        SolverConfig solverConfig = SolverConfig.createFromXmlResource("org/optaplanner/core/config/solver/defaultSolverConfig.xml");
        
        // Set your solution and entity classes specific to your vehicle routing problem
        solverConfig.withSolutionClass(VehicleRoutingSolution.class)
                   .withEntityClasses(Visit.class);

        // Build custom local search phase
        LocalSearchPhaseConfig localSearchPhaseConfig = new LocalSearchPhaseConfig();
        UnionMoveSelectorConfig unionMoveSelectorConfig = new UnionMoveSelectorConfig();

        // Configure ListChangeMoveSelector with your filter
        ListChangeMoveSelectorConfig listChangeMoveSelectorConfig = new ListChangeMoveSelectorConfig();
        // Option 1: Specify the filter class (OptaPlanner will handle instantiation)
        listChangeMoveSelectorConfig.setFilterClass(MyListChangeMoveFilter.class);
        // Option 2: Inject a Spring-managed filter bean (useful if your filter needs dependencies)
        // listChangeMoveSelectorConfig.setFilter(myListChangeMoveFilter());

        unionMoveSelectorConfig.addMoveSelectorConfig(listChangeMoveSelectorConfig);
        localSearchPhaseConfig.setMoveSelectorConfig(unionMoveSelectorConfig);

        // Replace default phases with your custom local search phase
        solverConfig.setPhaseConfigs(List.of(localSearchPhaseConfig));
        return solverConfig;
    }

    // If using Option 2, define your filter as a Spring bean
    @Bean
    public MyListChangeMoveFilter myListChangeMoveFilter() {
        return new MyListChangeMoveFilter();
    }
}

2. Configure via @PlanningSolver Annotation

If you're using OptaPlanner 8+ annotation-based solver definition, use @PlanningSolverConfigurer to customize the solver config directly in your solver class:

import org.optaplanner.core.api.solver.PlanningSolver;
import org.optaplanner.core.api.solver.PlanningSolverConfigurer;
import org.optaplanner.core.config.phase.LocalSearchPhaseConfig;
import org.optaplanner.core.config.heuristic.selector.move.composite.UnionMoveSelectorConfig;
import org.optaplanner.core.config.heuristic.selector.move.generic.ListChangeMoveSelectorConfig;

@PlanningSolver
public class VehicleRoutingSolver {

    @PlanningSolverConfigurer
    public void configure(PlanningSolverConfigurer<VehicleRoutingSolution> configurer) {
        configurer.getSolverConfig()
            // Override default phases with your custom local search setup
            .withPhaseConfigs(List.of(createLocalSearchPhaseConfig()));
    }

    private LocalSearchPhaseConfig createLocalSearchPhaseConfig() {
        LocalSearchPhaseConfig localSearchPhaseConfig = new LocalSearchPhaseConfig();
        UnionMoveSelectorConfig unionMoveSelectorConfig = new UnionMoveSelectorConfig();

        ListChangeMoveSelectorConfig listChangeMoveSelectorConfig = new ListChangeMoveSelectorConfig();
        listChangeMoveSelectorConfig.setFilterClass(MyListChangeMoveFilter.class);

        unionMoveSelectorConfig.addMoveSelectorConfig(listChangeMoveSelectorConfig);
        localSearchPhaseConfig.setMoveSelectorConfig(unionMoveSelectorConfig);
        return localSearchPhaseConfig;
    }
}

3. Implement Your Move Filter

Your filter class must implement the MoveFilter interface, targeting the specific ListChangeMove type for type safety:

import org.optaplanner.core.api.score.director.ScoreDirector;
import org.optaplanner.core.impl.heuristic.move.ListChangeMove;
import org.optaplanner.core.impl.heuristic.move.filter.MoveFilter;

public class MyListChangeMoveFilter implements MoveFilter<ListChangeMove<Visit>> {

    @Override
    public boolean accept(ScoreDirector<VehicleRoutingSolution> scoreDirector, ListChangeMove<Visit> move) {
        // Add your custom filtering logic here
        Visit movedVisit = move.getEntity();
        Vehicle targetVehicle = (Vehicle) move.getToDestination();

        // Example: Block moving low-priority visits to vehicles restricted to high-priority tasks
        return !targetVehicle.isRestrictedToHighPriority() || movedVisit.isHighPriority();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 20:17:36