简体   繁体   中英

Optaplanner add constraint for max amount of shifts allowable for an employee in ConstraintProvider class

I am trying to add a constraint that limits the amount of shifts assigned to employees in a ConstraintProvider class but I want to know if there is a better way to define this rather than having to add an attribute in both my @PlanningEntity and @PlanningVariable class?

Here is my @PlanningEntity class attributes:

 @PlanningEntity
    @Entity
    public class Shift {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        @Column(name = "shiftId")
        private int shiftId;

        @Column(name = "startTime")
        private LocalTime startTime;

        @Column(name = "endTime")
        private LocalTime endTime;

        @Column(name = "day")
        private String day;

        @Column(name = "requiredSkillLevel")
        private int requiredSkillLevel;

        @Column(name = "shiftAmount")
        private int shiftAmount;

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

Here is my @PlanningVariable class:

    @Entity
    public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "employeeId")
    private int employeeId;

    @Column(name = "employeeName")
    private String employeeName;

    @Column(name = "skillLevel")
    private int skillLevel;

    @Column(name = "employeeType")
    @Enumerated(EnumType.STRING)
    private EmployeeType employeeType;

    @Column(name = "associatedDepartment")
    @Enumerated(EnumType.STRING)
    private Departments associatedDepartment;

    @Column(name = "weeklyShiftAllowance")
    private int weeklyShiftAllowance;

My constraints are as follows:

    public class ScheduleConstraintProvider implements org.optaplanner.core.api.score.stream.ConstraintProvider {
    @Override
    public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
        return new Constraint[]{
                requiredSkillLevelOfEmployeesForShifts(constraintFactory),
                maximumNumberOfAllowableShiftsForEmployees(constraintFactory)
        };
    }

    private Constraint maximumNumberOfAllowableShiftsForEmployees(ConstraintFactory constraintFactory) {
        return constraintFactory.from(Shift.class)
                .groupBy(Shift::getEmployee, sum(Shift::getShiftAmount))
                .filter((employee, shiftAmount) -> shiftAmount > employee.getWeeklyShiftAllowance())
                .penalize("Weekly Shift Allowance for each Employee",
                        HardSoftScore.ONE_HARD,
                        (employee, shiftAmount) -> shiftAmount - employee.getWeeklyShiftAllowance());
    }

    private Constraint requiredSkillLevelOfEmployeesForShifts(ConstraintFactory constraintFactory) {
        return constraintFactory.from(Shift.class)
                .groupBy(Shift::getEmployee, sum(Shift::getRequiredSkillLevel))
                .filter((employee, requiredSkillLevel) -> requiredSkillLevel > employee.getSkillLevel())
                .penalize("Required Skill Level for a Shift",
                HardSoftScore.ONE_HARD,
                (employee, requiredSkillLevel) -> requiredSkillLevel - employee.getSkillLevel());
    }


}

Rather than having shiftAmount in my Shift class can I add something that treats each Shift as counting as 1 shift assignment?

Yes

Instead of:

return constraintFactory.from(Shift.class)
                .groupBy(Shift::getEmployee, sum(Shift::getShiftAmount))

do

return constraintFactory.from(Shift.class)
                .groupBy(Shift::getEmployee, count())

(If you want a long, use countLong() .)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM