如何在OptaPlanner中自定义ConstraintProvider?

问题描述

这是一个排班计划应用程序。我已经通过改变重量来动态控制一些约束的开/关,这很棒。某些特定的约束已经可以通过计划对象属性(员工合同的最大值)动态控制。我仍然没有找到一种方法来根据配置对ConstraintProvider进行参数化。我的问题是:

可以通过编程方式创建ConstraintProvider而不是在SolverConfig.xml中进行定义吗?这样我就可以注入自己的参数

我希望可以不仅仅以10小时的固定持续时间(即10 * 60的硬编码值)来动态调整此约束条件:

Constraint breakBetweenNonConsecutiveShiftsIsAtLeastTenHours(ConstraintFactory constraintFactory) {
        return getAssignedShiftConstraintStream(constraintFactory)
                .join(Shift.class,equal(Shift::getEmployee),lessthan(Shift::getEndDateTime,Shift::getStartDateTime))
                .filter((s1,s2) -> !Objects.equals(s1,s2))
                .filter((s1,s2) -> s1.getEndDateTime().until(s2.getStartDateTime(),ChronoUnit.HOURS) < 10)
                .penalizeConfigurableLong(CONSTRAINT_BREAK_BETWEEN_NON_CONSECUTIVE_SHIFTS,(s1,s2) -> {
                    long breakLength = s1.getEndDateTime().until(s2.getStartDateTime(),ChronoUnit.MINUTES);
                    return (10 * 60) - breakLength;
                });
    }

(我可以在Shift上添加一个字段,以为所有班次返回相同的值,但这很麻烦。)

解决方法

当前,最好的方法是创建一个自定义类来存储持续时间(例如:MinimumBreakBetweenNonConsecutiveShifts),将其添加为花名册的字段,并用@ProblemFact注释该字段。然后,您可以使用constraintFactory.from(...).join(MinimumBreakBetweenNonConsecutiveShifts.class)将带有问题事实的信息流加入流中。我们目前在这里讨论访问问题事实的替代方法:https://kie.zulipchat.com/#narrow/stream/232679-optaplanner/topic/Constraint.20context

https://github.com/kiegroup/optaweb-employee-rostering/issues/502#issuecomment-701479372