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

从Drools迁移至Constraint Streams:动态约束级别配置求助

解决Constraint Streams动态约束级别与权重的方案

针对你从Drools迁移到Constraint Streams时遇到的动态约束配置问题,这里提供两种简洁的实现方案,避免冗余代码:

方案一:通过约束配置实体动态计算惩罚分数

这种方式直接将约束的级别、权重作为问题事实(Problem Fact)加入规划模型,在约束流中关联实体与配置,动态生成对应级别的惩罚分数。

步骤1:定义约束配置类

public class ConstraintConfig {
    private String constraintType; // 约束类型标识,用于匹配对应的业务逻辑
    private ConstraintLevel level;
    private int weight;
    private int maxAllowedOvertime; // 示例业务参数,可根据实际场景调整

    // 构造器、getter、setter
}

步骤2:编写约束流逻辑

在ConstraintProvider中,通过join关联业务实体与约束配置,根据配置动态生成惩罚分数:

public class MyConstraintProvider implements ConstraintProvider {
    @Override
    public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
        return new Constraint[] {
            dynamicOvertimeConstraint(constraintFactory)
        };
    }

    private Constraint dynamicOvertimeConstraint(ConstraintFactory cf) {
        return cf.from(Employee.class)
                // 关联对应的约束配置,匹配约束类型
                .join(ConstraintConfig.class, Joiners.equal(Employee::getDeptType, ConstraintConfig::getConstraintType))
                // 过滤符合约束违规条件的实体
                .filter((employee, config) -> employee.getOvertimeHours() > config.getMaxAllowedOvertime())
                // 根据配置的级别和权重返回对应Score
                .penalize((employee, config) -> switch(config.getLevel()) {
                    case HARD -> HardMediumSoftScore.ofHard(-config.getWeight());
                    case MEDIUM -> HardMediumSoftScore.ofMedium(-config.getWeight());
                    case SOFT -> HardMediumSoftScore.ofSoft(-config.getWeight());
                })
                .asConstraint("Dynamic Overtime Constraint");
    }
}

步骤3:动态更新配置

当UI修改约束的级别、权重或业务参数时,直接更新ConstraintConfig实例(比如从数据库读取或通过接口传入),重新构建问题并触发求解即可。

方案二:使用penalizeConfigurable结合ConstraintConfiguration

这种方式通过ConstraintConfiguration管理每个约束实例的权重与级别,适合需要为同一逻辑创建多个独立约束实例的场景。

步骤1:定义约束配置映射

创建ConstraintConfiguration子类,管理每个约束ID对应的权重配置:

public class CustomConstraintConfiguration extends ConstraintConfiguration {
    private Map<String, ConstraintWeightConfiguration> constraintWeightMap = new HashMap<>();

    // 更新指定约束的级别与权重
    public void updateConstraint(String constraintId, ConstraintLevel level, int weight) {
        Score<?> score = switch(level) {
            case HARD -> HardMediumSoftScore.ofHard(-weight);
            case MEDIUM -> HardMediumSoftScore.ofMedium(-weight);
            case SOFT -> HardMediumSoftScore.ofSoft(-weight);
        };
        constraintWeightMap.put(constraintId, new ConstraintWeightConfiguration(constraintId, score));
    }

    @Override
    public ConstraintWeightConfiguration getConstraintWeight(String constraintPackage, String constraintName) {
        return constraintWeightMap.get(constraintName);
    }
}

步骤2:生成动态约束实例

在ConstraintProvider中,遍历所有约束配置,为每个配置生成共享同一逻辑的约束实例:

public class MyConstraintProvider implements ConstraintProvider {
    @Override
    public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
        List<Constraint> constraints = new ArrayList<>();
        // 从外部获取所有动态约束配置(比如UI传入的配置列表)
        List<ConstraintConfig> configs = getDynamicConfigs();

        for (ConstraintConfig config : configs) {
            Constraint constraint = constraintFactory.from(Employee.class)
                    .filter(employee -> employee.getOvertimeHours() > config.getMaxAllowedOvertime())
                    .penalizeConfigurable(config.getConstraintId(), constraintFactory.getScoreDefinition())
                    .asConstraint(config.getConstraintId());
            constraints.add(constraint);
        }

        return constraints.toArray(new Constraint[0]);
    }

    private List<ConstraintConfig> getDynamicConfigs() {
        // 示例:返回UI配置的约束列表
        List<ConstraintConfig> configs = new ArrayList<>();
        configs.add(new ConstraintConfig("deptA-overtime", ConstraintLevel.HARD, 10, 10));
        configs.add(new ConstraintConfig("deptB-overtime", ConstraintLevel.SOFT, 5, 15));
        return configs;
    }
}

步骤3:关联配置与求解器

在求解器配置中指定自定义的ConstraintConfiguration,UI更新时直接修改配置类并重启求解器:

SolverFactory<EmployeeRoster> solverFactory = SolverFactory.create(new SolverConfig()
        .withSolutionClass(EmployeeRoster.class)
        .withEntityClasses(Employee.class)
        .withConstraintProviderClass(MyConstraintProvider.class)
        .withConstraintConfigurationClass(CustomConstraintConfiguration.class));

// UI更新配置时执行
CustomConstraintConfiguration config = solverFactory.getSolverConfig().getConstraintConfiguration();
config.updateConstraint("deptA-overtime", ConstraintLevel.MEDIUM, 8);

Solver<EmployeeRoster> solver = solverFactory.buildSolver();
// 执行求解逻辑

两种方案中,方案一更适合同一约束逻辑对应多组配置的场景,代码更简洁;方案二更适合需要独立管理每个约束实例的场景,灵活性更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 00:05:25