OptaPlanner 自定义员工名册 - 约束提供者中的 WeeklyHoursLimit 问题

OptaPlanner Custom Employee Rostering - Issues with WeeklyHoursLimit in the Constraint Provider

我一直在按照员工排班示例创建自定义员工排班服务。我正在尝试实施每周工作时间限制。但是,我未能达到每位员工每周最多工作 40 小时的预期限制。我试图复制 OptaPlanner 员工排班解决方案。这是我想出的,但是解决方案 returns 无论我尝试什么输入都不匹配。

 Constraint weeklyHoursUpperLimit(ConstraintFactory constraintFactory) {
    return constraintFactory.from(Employee.class)
            .join(Schedule.class, equal(Function.identity(), Schedule::getEmployee))
            .groupBy((employee, schedule) -> employee,
                    ((employee, schedule) -> ZonedDateTime.parse(schedule.getTimeslot().getStart()).toLocalDate()
                            .with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY))),
                    sumDuration((employee, schedule) -> Duration.between(ZonedDateTime.parse(schedule.getTimeslot().getStart()),
                            ZonedDateTime.parse(schedule.getTimeslot().getEnd()))))
            .filter((practitioner, day, time) -> time.toHoursPart() > 40)
            .penalize("Practitioners cannot work more than 40 hours per week", HardMediumSoftScore.ONE_HARD);

解决方案是一个包含员工和相应时间段的 Schedule 类型的列表,似乎与所需的行为不匹配。

使用以下输入:

{
    "employees": [
        {
            "id": "0458d419-da18-4d86-82de-31a2272f018a"
        }
    ],
    "timeslots": [
        {
            "start": "2021-05-24T00:00:00-04:00",
            "end": "2021-05-24T12:00:00-04:00",
            "slotId": 1
        },
        {
            "start": "2021-05-24T12:00:00-04:00",
            "end": "2021-05-25T00:00:00-04:00",
            "slotId": 7
        },
        {
            "start": "2021-05-25T12:00:00-04:00",
            "end": "2021-05-26T00:00:00-04:00",
            "slotId": 4
        },
        {
            "start": "2021-05-27T12:00:00-04:00",
            "end": "2021-05-28T00:00:00-04:00",
            "slotId": 5
        }
    ]
}

ScoreExplanation 是这样说的: 约束条件(从业者每周工作时间不能超过 40 小时)有 0 个匹配项。

应该说什么: constraint (Practitioner work cannot work more than 40 hours per week) has 1 matches.

有了这个输入,唯一可能的解决方案必须符合这个限制条件。检测到其他约束并对其进行惩罚,所以我想知道为什么这个约束从不 returns 任何匹配项。

我怀疑问题出在过滤器中: .filter((practitioner, day, time) -> time.toHoursPart() > 40)

Duration#toHoursPart() returns总小时数除以一天中的小时数后的余数,介于 0 和 23 之间。 过滤器可能应该使用 Duration#toHours() 代替。