在Timefold中创建多ConstraintProviders进行基准测试的异常解决及配置建议
异常原因与解决思路
你遇到的异常是因为Spring自动扫描时发现多个ConstraintProvider实现类,Timefold默认会自动识别该接口的实现,但存在多个实现时会导致Bean冲突。解决思路如下:
1. 显式指定ConstraintProvider
不要依赖Spring自动扫描,而是在每个测试/基准配置中手动指定要使用的ConstraintProvider类:
- 在
SolverConfig中通过setConstraintProviderClass()方法指定具体实现; - 若使用XML配置,在
<scoreDirectorFactory>节点内添加<constraintProviderClass>标签指定类路径。
2. Spring环境临时兼容方案(仅单方案测试用)
如果只是临时测试单个方案,可通过Spring注解控制Bean选择:
- 给其中一个
ConstraintProvider添加@Primary注解,让Spring优先注入; - 在
@ComponentScan中通过excludeFilters排除不需要的ConstraintProvider实现类。
多ConstraintProviders基准测试实现建议
推荐使用Timefold官方的Benchmark模块来对比多方案,它能自动运行所有配置组合、收集性能数据并生成可视化报告,完美适配你的需求(对比约束方案、CH类型、LS配置)。
步骤1:准备约束实现
根据你的两个方案,有两种实现方式:
方式A:创建独立ConstraintProvider
FullConstraintProvider:包含所有约束(对应方案一);ReducedConstraintProvider:移除assignHighPriorityFirst约束(对应方案二)。
方式B:用约束过滤减少重复代码(更简洁)
只维护一个FullConstraintProvider,通过ConstraintFilter禁用指定约束:
public class ExcludeHighPriorityConstraintFilter implements ConstraintFilter { @Override public boolean accept(String constraintName) { return !"assignHighPriorityFirst".equals(constraintName); } }
步骤2:配置Benchmark(XML示例)
创建benchmarkConfig.xml,定义所有需要对比的方案组合:
<?xml version="1.0" encoding="UTF-8"?> <benchmark xmlns="https://timefold.ai/xsd/benchmark" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://timefold.ai/xsd/benchmark https://timefold.ai/xsd/benchmark/benchmark.xsd"> <benchmarkDirectory>./benchmark-results</benchmarkDirectory> <!-- 所有方案共享的基础配置 --> <inheritedSolverBenchmark> <solver> <solutionClass>your.package.TaskAssignmentSolution</solutionClass> <entityClass>your.package.TaskAssignment</entityClass> <termination> <secondsSpentLimit>30</secondsSpentLimit> <!-- 每个方案运行30秒 --> </termination> </solver> </inheritedSolverBenchmark> <!-- 方案一:ONLY_DOWN + FIRST_FIT_DECREASING + 全约束 --> <solverBenchmark name="Scheme1-FullConstraints-OnlyDown-FFD"> <solver> <scoreDirectorFactory> <constraintProviderClass>your.package.FullConstraintProvider</constraintProviderClass> </scoreDirectorFactory> <constructionHeuristic> <constructionHeuristicType>FIRST_FIT_DECREASING</constructionHeuristicType> <changeMoveSelector> <selectionOrder>ONLY_DOWN</selectionOrder> </changeMoveSelector> </constructionHeuristic> <localSearch> <localSearchType>HILL_CLIMBING</localSearchType> </localSearch> </solver> </solverBenchmark> <!-- 方案二:WEAKEST_FIT_DECREASING + 禁用指定约束 --> <solverBenchmark name="Scheme2-ReducedConstraints-WFD"> <solver> <scoreDirectorFactory> <constraintProviderClass>your.package.FullConstraintProvider</constraintProviderClass> <constraintFilter>your.package.ExcludeHighPriorityConstraintFilter</constraintFilter> </scoreDirectorFactory> <constructionHeuristic> <constructionHeuristicType>WEAKEST_FIT_DECREASING</constructionHeuristicType> </constructionHeuristic> <localSearch> <localSearchType>TABU_SEARCH</localSearchType> <tabuSize>7</tabuSize> </localSearch> </solverBenchmark> <!-- 可添加更多组合:比如方案一搭配TABU搜索、方案二搭配HILL_CLIMBING等 --> <solverBenchmark name="Scheme1-FullConstraints-OnlyDown-FFD-Tabu"> <solver> <scoreDirectorFactory> <constraintProviderClass>your.package.FullConstraintProvider</constraintProviderClass> </scoreDirectorFactory> <constructionHeuristic> <constructionHeuristicType>FIRST_FIT_DECREASING</constructionHeuristicType> <changeMoveSelector> <selectionOrder>ONLY_DOWN</selectionOrder> </changeMoveSelector> </constructionHeuristic> <localSearch> <localSearchType>TABU_SEARCH</localSearchType> <tabuSize>5</tabuSize> </localSearch> </solver> </solverBenchmark> </benchmark>
步骤3:运行基准测试
通过Java代码启动Benchmark:
public class TaskAssignmentBenchmarkRunner { public static void main(String[] args) { BenchmarkFactory.createFromXmlResource("benchmarkConfig.xml") .benchmark(); } }
运行完成后,benchmark-results目录会生成HTML报告,包含各方案的得分、求解时间、内存占用等对比数据。
内容的提问来源于stack exchange,提问作者HeWhoHasNoName
相关产品推荐
相关产品推荐

