涵盖所有班次的约束条件

问题描述 投票:0回答:1

在一个简单的排班问题中,我希望OptaPlanner在我的日程安排中返回“空缺”,以便在没有任何员工具备所需技能的情况下,发现某些班次。

假设3个基本类,并且我只想用HardMediumSoftScore.ONE_SOFT惩罚未发现的班次。

如何写这样的约束?

Employee.java

public class Employee {

    private long id = 0L;

    private List<Skill> skills;

Shift.java

@PlanningEntity
public class Shift {

    private RequiredSkills

    @PlanningVariable(valueRangeProviderRefs = "employeeRange")
    private Employee employee;

    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX")
    private OffsetDateTime start;

    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX")
    private OffsetDateTime end;

Schedule.java

@PlanningSolution
public class Schedule {

    @PlanningEntityCollectionProperty
    private List<Shift> shifts;

    @ProblemFactCollectionProperty
    @ValueRangeProvider(id = "employeeRange")
    private List<Employee> employees;

进一步假设一个简单的ConstraintProvider

public class ScheduleConstraints implements ConstraintProvider {

    @Override
    public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {

        return new Constraint[]{
            requiredSkill(constraintFactory),
        };
    }

    private Constraint requiredSkill(ConstraintFactory constraintFactory) {
        return constraintFactory.from(Shift.class)
                .filter(shift -> {
                    return !shift.getEmployee().hasSkills(shift.getSkills());
                }).penalize("Required skill", HardMediumSoftScore.ONE_HARD);
    }

这是我的尝试。好吗?

private Constraint allShiftsMustBeCovered(ConstraintFactory constraintFactory) {
        return constraintFactory.fromUnfiltered(Shift.class)
                .filter(shift-> {
                    return shift.getEmployee().getId() == 0L;
                }).penalize("All shifts must be covered", HardMediumSoftScore.ONE_SOFT);
    }
optaplanner
1个回答
2
投票

除非我没有记错,否则您的代码将抛出NullPointerException。如果未涵盖班次,则Shift.employeenull。您的约束条件假设Employee永远不会是null-您必须解决此问题,也许是这样的:

// I added a null check as from() only excludes uninitialized entities.
// If employee is nullable, from() will still return Shifts with null employees.
private Constraint requiredSkill(ConstraintFactory constraintFactory) {
    return constraintFactory.from(Shift.class)
            .filter(shift -> shift.getEmployee() != null)
            .filter(shift -> {
                return !shift.getEmployee().hasSkills(shift.getSkills());
            }).penalize("Required skill", HardMediumSoftScore.ONE_HARD);
}

private Constraint allShiftsMustBeCovered(ConstraintFactory constraintFactory) {
    return constraintFactory.fromUnfiltered(Shift.class)
            .filter(shift-> shift.getEmployee() == null || 
                shift.getEmployee().getId() == 0L
            ).penalize("All shifts must be covered", HardMediumSoftScore.ONE_SOFT);
}

由于null在此处是有效值,因此请确保Shift.employee variable is nullable。这种方法在文档中称为过度约束的计划

© www.soinside.com 2019 - 2024. All rights reserved.