Method: scheduling.solveShiftScheduling

通过为员工分配班次,让员工的班次符合要求,解决了给定 SolveShiftSchedulingRequest 的固定轮班调度问题最大限度提高时间安排偏好设置,并最大限度地减少时间安排限制违规。

HTTP 请求

POST https://optimization.googleapis.com/v1/scheduling:solveShiftScheduling

网址采用 gRPC 转码语法。

请求正文

请求正文中包含结构如下的数据:

JSON 表示法
{
  "requestId": string,
  "solveParameters": {
    object (SolveParameters)
  },
  "employees": [
    {
      object (Employee)
    }
  ],
  "shifts": [
    {
      object (Shift)
    }
  ],
  "coverageRequirements": [
    {
      object (CoverageRequirement)
    }
  ],
  "roleIds": [
    string
  ],
  "skillIds": [
    string
  ],
  "locationIds": [
    string
  ],
  "budgetRequirements": [
    {
      object (BudgetRequirement)
    }
  ],
  "assignmentsHint": [
    {
      object (ShiftAssignment)
    }
  ]
}
字段
requestId

string

问题或请求 ID。

solveParameters

object (SolveParameters)

用于控制问题求解的参数。

employees[]

object (Employee)

安排所有有空的员工。

shifts[]

object (Shift)

形成时间表。

coverageRequirements[]

object (CoverageRequirement)

整个规划范围的覆盖范围要求。用于指定在特定时间范围内或一系列轮班 ID 内必须担任每种角色或拥有某项技能的员工人数。所有覆盖范围要求都必须使用时间范围或班次 ID 列表来指定(但不能同时指定两者)。范围要求的时间范围(如果已指定)不能与每个指定地理位置重叠。对于角色要求,每个限制条件的默认优先级为 PRIORITY_MANDATORY;对于技能要求,默认优先级为 PRIORITY_LOW。如需了解详情,请参阅 Priority 枚举。

roleIds[]

string

员工中所有可能的角色的列表。每位员工必须至少拥有一个可分配其轮班的角色。角色是指轮班期间的具体工作分配(即注册护士、执行厨师、服务员等)。如果为某个员工分配了某个轮班,他们也会分配到一个特定的角色。

skillIds[]

string

员工可能具备的所有技能的列表。技能是指员工可能拥有的与具体可分配职位无关的任何额外资格(例如认证、所用语言等)。此列表可以为空。某名员工在接受轮班时,必须具备该轮班所需的全部技能。

locationIds[]

string

包含时间表中一组班次的所有可能位置的列表。此列表可以为空。指定不同的位置会很有用,例如当护士经理想为医院的不同部门安排多位护士,或者酒店经理想为员工安排多个酒店的员工时。

budgetRequirements[]

object (BudgetRequirement)

时间安排问题的预算规范。每项要求的默认优先级均为 PRIORITY_LOW。如需了解详情,请参阅 Priority 枚举。

assignmentsHint[]

object (ShiftAssignment)

转换分配,用作调度问题的暂定解决方案(即解决方案提示)。如果分配与不可分配的偏移或调度请求冲突,则分配提示会被忽略。

响应正文

对员工时间安排 API 的响应。对于每个响应,如果返回的 solutionStatusNOT_SOLVED_DEADLINE_EXCEEDEDINFEASIBLE,则 shiftAssignments 将为空。如果返回的 solutionStatusOPTIMALFEASIBLE,则会在 shiftAssignments 中返回有效的偏移分配。对于有效的轮班分配,应具备以下属性:

  1. 每个员工 ID 都包含在请求中指定的员工集中。
  2. 分配给员工的每个角色 ID 都包含在给定员工的角色 ID 集中。
  3. 每个班次 ID 都包含在请求中指定的班次集合中。
  4. 对于指定员工,每个班次 ID 都不是其中一个不可分配的班次 ID。
  5. 某位员工绝不会分配到两个重叠的班次。
  6. 对于指定的时间安排,优先级为 PRIORITY_MANDATORY 的所有限制条件或请求均未违反。

如果成功,响应正文将包含结构如下的数据:

JSON 表示法
{
  "requestId": string,
  "solutionStatus": enum (SolutionStatus),
  "shiftAssignments": [
    {
      object (ShiftAssignment)
    }
  ],
  "statusMessage": string
}
字段
requestId

string

与此响应关联的请求的 ID。

solutionStatus

enum (SolutionStatus)

所返回解决方案的状态。如果解决方案不可行或不可优化,则此 proto 中的其他字段可能为空。如果状态为 NOT_SOLVED_DEADLINE_EXCEEDED,则表示在未找到可行解决方案或无法确定是否存在可行解决方案的情况下,已达到时间限制。如果优先级 MANDATORY 的限制条件无法全部满足,则请求可能是不可行的。

shiftAssignments[]

object (ShiftAssignment)

所有分配的列表。每个 ShiftAssignment 都会指定一名员工、分配给他们的轮班,以及他们在该轮班所分配到的角色。

statusMessage

string

如果 solutionStatus 不是最佳值,则此字段可能包含有关求解器的其他信息。

SolveParameters

用于控制轮班调度问题的一次解决的参数。

JSON 表示法
{
  "timeLimit": string
}
字段
timeLimit

string (Duration format)

求解器应该在解题上花费的时间上限。如果未设置,则默认为 1 分钟。

该值不是硬性限制,并且不考虑通信开销。解决此问题的预期延迟时间可能会略微超过此值。

该时长以秒为单位,最多包含九个小数位,以“s”结尾。示例:"3.5s"

员工

要安排的员工中的员工。

JSON 表示法
{
  "id": string,
  "roleIds": [
    string
  ],
  "skillIds": [
    string
  ],
  "shiftPreferences": [
    {
      object (ShiftPreference)
    }
  ],
  "schedulingConstraints": [
    {
      object (SchedulingConstraint)
    }
  ],
  "resourceConstraints": [
    {
      object (ResourceConstraint)
    }
  ],
  "shiftRequests": [
    {
      object (ShiftRequest)
    }
  ],
  "hourlyContract": {
    object (HourlyContract)
  }
}
字段
id

string

分配给此员工的唯一 ID。

roleIds[]

string

此员工可以执行的角色 ID。必须至少指定一个角色。如果为某个员工分配了某个轮班,该员工也会分配到此列表中的一个角色。在时间安排的时间范围内,员工可能会被分配不同的角色。

skillIds[]

string

此员工拥有的技能 ID。此列表可以为空。为某个员工分配轮班时,该员工会使用此处所列的任意技能来满足在整个轮班期间的技能要求。

shiftPreferences[]

object (ShiftPreference)

调整此员工的偏好设置。此处指定的班次表示员工希望在预约时限内分配的班次。shiftPreferences 中指定的班次 ID 必须是唯一的。求解器会尝试最大化所有符合要求的 shiftPreferencesShiftPreference.preference 值的总和。

schedulingConstraints[]

object (SchedulingConstraint)

此员工的时间安排限制列表。其中每个限制条件的默认优先级均为 PRIORITY_MEDIUM。如需了解详情,请参阅 Priority 枚举。

resourceConstraints[]

object (ResourceConstraint)

可在此处向 resourceConstraints 添加未在 schedulingConstraints 中指定的任何其他调度约束条件。ResourceConstraint 是一种更抽象的表示法,用于限制员工的资源。其中每个限制条件的默认优先级均为 PRIORITY_MEDIUM。如需了解详情,请参阅 Priority 枚举。

shiftRequests[]

object (ShiftRequest)

员工的排班请求列表。该请求可以是为员工分配或不分配给特定班次的请求。员工的所有固定调度分配都可以用优先级为 PRIORITY_MANDATORYShiftRequest 表示。轮班 ID 最多只能出现在该员工的一个日程安排请求中。其中每个请求的默认优先级均为 PRIORITY_LOW。如需了解详情,请参阅 Priority 枚举。

hourlyContract

object (HourlyContract)

规定员工的常规每小时费率和加班费率的合同。

ShiftPreference

特定班次 ID 的数字偏好设置。

JSON 表示法
{
  "shiftId": string,
  "preference": integer
}
字段
shiftId

string

已指定偏好设置的 Shift ID。

preference

integer

偏好值越大,表示变化更可取。

SchedulingConstraint

特定员工的特定调度限制条件。指定的限制条件仅在给定的时间间隔 [startDateTime, endDateTime) 内应用。

JSON 表示法
{
  "priority": enum (Priority),
  "startDateTime": {
    object (DateTime)
  },
  "endDateTime": {
    object (DateTime)
  },

  // Union field type can be only one of the following:
  "minimumMinutes": integer,
  "maximumMinutes": integer,
  "minimumConsecutiveWorkDays": integer,
  "maximumConsecutiveWorkDays": integer,
  "minimumShiftCount": integer,
  "maximumShiftCount": integer,
  "minimumRestMinutes": integer
  // End of list of possible types for union field type.
}
字段
priority

enum (Priority)

此调度限制条件的优先级。所有调度限制条件的默认优先级为 PRIORITY_MEDIUM

startDateTime

object (DateTime)

应用此调度限制条件的开始时间(含此时间)。

endDateTime

object (DateTime)

应用此调度限制条件的结束时间(不含)。

联合字段 type。要指定的限制条件的类型。每个限制条件仅在上面指定的时间范围内应用。type 只能是下列其中一项:
minimumMinutes

integer

员工可以工作的最短分钟数。如果为员工分配的班次与时间窗口完全或部分重叠,则此班次与时间窗口重叠的分钟数会计入此计数中。

maximumMinutes

integer

员工在相应时间范围内可以工作的分钟数上限。如果为员工分配的班次与时间窗口完全或部分重叠,则此班次与时间窗口重叠的分钟数会计入此计数中。

minimumConsecutiveWorkDays

integer

员工可以工作的最短连续天数。如果某位员工被分配到的排班从当天开始,则会在特定的某一天工作。该计数包含分配给该员工的任何从该时间窗口开始的班次。

maximumConsecutiveWorkDays

integer

员工可以工作的最长连续天数。如果某位员工被分配到的排班从当天开始,则会在特定的某一天工作。该计数包含分配给该员工的任何从该时间窗口开始的班次。

minimumShiftCount

integer

员工可以轮班的最少班次。分配给该员工的任何班次(与时间范围完全重叠)都包含在此计数中。

maximumShiftCount

integer

员工可以轮班的次数上限。分配给该员工的任何班次(与时间范围完全重叠)都包含在此计数中。

minimumRestMinutes

integer

一个班次结束后,员工必须休息的最短分钟数,才能被分配到另一个班次。此限制条件适用于完全包含在 [startDateTimeendDateTime] 中的每对偏移。

优先级

针对员工时间表或覆盖范围要求的任何限制条件的优先级。其中包括 SchedulingConstraintResourceConstraintShiftRequestCoverageRequirement。由于可能存在有冲突的约束,因此并不总是能够满足每个约束条件。因此,每类约束条件都有一个优先级(由用户指定或默认优先级),用于告知求解器给定完整时间表的所有约束条件的相对重要性。

枚举
PRIORITY_UNSPECIFIED 未知的优先级。
PRIORITY_LOW 最低优先级。与其他限制条件相比,具有此优先级的限制条件不太重要。如果找不到可行的解决方案,这些合作伙伴会优先考虑违规。
PRIORITY_MEDIUM 优先级:中。具有此优先级的限制条件比优先级为 PRIORITY_LOW 的限制条件重要,但不如优先级为 PRIORITY_HIGH 的限制条件重要。如果在放宽优先级为 PRIORITY_LOW 的所有限制条件后找不到可行的解决方案,则接下来将考虑优先级为 PRIORITY_MEDIUM 的约束条件。
PRIORITY_HIGH 最高优先级。此优先级的限制条件是最重要的。如果在放宽较低优先级的约束条件后无法找到可行的解决方案,那么这些订单项将是最后的违规行为。
PRIORITY_MANDATORY 表示求解器不能违反的内容的优先级。如果求解器返回 SolutionStatus.INFEASIBLE,可能是因为 PRIORITY_MANDATORY 约束条件过多。

ResourceConstraint

限制特定“资源”数量的一般限制条件由员工使用这是更具体的 SchedulingConstraint 的抽象版本,对用户来说更加灵活。您可以改用此消息指定无法在 SchedulingConstraint.type 中指定的许多调度约束。

JSON 表示法
{
  "priority": enum (Priority),
  "resourceUsages": {
    string: number,
    ...
  },
  "minimumResourceUsage": number,
  "maximumResourceUsage": number
}
字段
priority

enum (Priority)

此资源限制条件的优先级。所有资源限制条件的默认优先级为 PRIORITY_MEDIUM

resourceUsages

map (key: string, value: number)

轮班使用的资源量。例如,如果此约束条件应用于某员工在特定周的最短和最长工作时间,则此映射将包含该周的班次以及每次班次的时长(以小时为单位)。

包含一系列 "key": value 对的对象。示例:{ "name": "wrench", "mass": "1.3kg", "count": "3" }

minimumResourceUsage

number

要满足资源限制条件的最低资源使用量。

maximumResourceUsage

number

要满足资源限制条件的最大资源使用量。

ShiftRequest

员工希望被分配或不会被分配到特定班次的请求。

JSON 表示法
{
  "priority": enum (Priority),
  "shiftIds": [
    string
  ],
  "type": enum (WorkStatus)
}
字段
priority

enum (Priority)

此安排请求的优先级。所有调度请求的默认优先级为 PRIORITY_LOW

shiftIds[]

string

时间安排请求的班次 ID。

type

enum (WorkStatus)

请求类型,例如是否将请求分配给一组轮班。

WorkStatus

员工是否在工作。

枚举
WORK_STATUS_UNSPECIFIED 未知工作状态。
STATUS_WORK 代表在职员工的身份。
STATUS_NOT_WORK 代表非在职员工的身份。

HourlyContract

指定基本时薪、差价和加班乘数,以确定员工的薪酬。请注意,不同地区的法规对加班薪酬的计算方式可能有所不同。求解器会估算加班费,以便尽可能降低总费用或满足预算要求(请参阅 BudgetRequirement)。它不用作计算工资的工具。

JSON 表示法
{
  "baseHourlyRate": number,
  "hourlyRateShiftDifferentials": {
    string: number,
    ...
  },
  "overtimePeriods": [
    {
      object (OvertimePeriod)
    }
  ]
}
字段
baseHourlyRate

number

非加班时间的薪酬。如果员工适用多个费率,则会根据此基本小时费率应用差价。此外,如果有多种费率,则基本每小时费率应为这些费率的最小值。

hourlyRateShiftDifferentials

map (key: string, value: number)

baseHourlyRate之上支付每小时费率的差额。例如,如果基本每小时费率为 $30/小时,则“shift_1”按 40 美元/小时的费率支付,“shift_2”费率为 $45/小时,则 proto 表示法为:baseHourlyRate: 30 hourlyRateShiftDifferentials {key: "shift_1" value: 10} hourlyRateShiftDifferentials {key: "shift_2" value: 15}

包含一系列 "key": value 对的对象。示例:{ "name": "wrench", "mass": "1.3kg", "count": "3" }

overtimePeriods[]

object (OvertimePeriod)

必须计算加时值的所有时间段的列表。这些时段不得重叠。

OvertimePeriod

固定和有规律的周期(通常为 168 小时或连续的 24 小时时间段),用于确定加班工资金额。每个时间段都有一个加时乘数(例如,1.5)(相对于baseHourlyRate)以及对被视为常规(非加班)工作的小时数限制。与 startDateTime(含)和 endDateTime(不含)时间范围重叠的任何班次都将计入此时间段内的工作时间总数。如果重叠部分是部分重叠,则仅统计重叠时段。

JSON 表示法
{
  "overtimeMultiplier": number,
  "startDateTime": {
    object (DateTime)
  },
  "endDateTime": {
    object (DateTime)
  },
  "maximumRegularHours": number
}
字段
overtimeMultiplier

number

用于计算加班时间每小时费率的调节系数(必须大于或等于 1.0)。加时型每小时费率通常按 baseHourlyRate * overtimeMultiplier 计算。如果 hourlyRateShiftDifferentials 指定了多个速率,则求解器会使用一段时间内适用的速率的简单平均值来近似计算随时间变化的小时速率。注意:不同地方的法规对加班薪酬的计算方式可能有所不同。求解器会估算加班工资,以尽可能降低总费用或满足预算要求,但并不是用于计算工资的工具。

startDateTime

object (DateTime)

加时时间段内的开始时间。如果此时间偏移时差,则从 startDateTime 开始计算此类偏移的小时数。

endDateTime

object (DateTime)

加时时间段内的结束时间。如果此时间调整的时间与时间重叠,则此类偏移的小时数最多计为 endDateTime

maximumRegularHours

number

按常规(非加班)费率支付的最长工作时间。此数量必须为正数。

Shift

轮班会指定员工可以工作的固定时间段。

JSON 表示法
{
  "id": string,
  "locationId": string,
  "startDateTime": {
    object (DateTime)
  },
  "endDateTime": {
    object (DateTime)
  },
  "breakRules": [
    {
      object (BreakRule)
    }
  ]
}
字段
id

string

分配给此班次的唯一 ID。

locationId

string

执行此偏移的地理位置 ID。此字段可以为空。

startDateTime

object (DateTime)

班次的开始时间(含此时间)。

endDateTime

object (DateTime)

班次的结束时间(不含)。目前,该求解器仅支持时长不超过 24 小时的移位。

breakRules[]

object (BreakRule)

转移期间发生的违反规则的列表。执行此轮班的员工每break_rule会获得一次休息时间,在此期间他们无法满足其履行职责的需求。每个 BreakRule 个时间范围都必须完全包含在此转变的时间范围内。

BreakRule

用于确定在轮班期间可以开始休息的时间以及休息时长的规则。系统会以 ruleIncrementMinutes 为增量来确定考虑的所有可能的插播时间点。例如,如果一条广告插播规则模拟一个从 10:00 到 11:00 之间开始的 30 分钟的广告插播时间点,并且规则递增单位为 20 分钟,则考虑的广告插播时间点列表包括:[10:00, 10:30]、[10:20, 10:50]、[10:1.0.0.1.40,

JSON 表示法
{
  "earliestStartTime": {
    object (DateTime)
  },
  "latestStartTime": {
    object (DateTime)
  },
  "durationMinutes": integer,
  "ruleIncrementMinutes": integer
}
字段
earliestStartTime

object (DateTime)

广告插播的最早开始时间(含此时间)。只能设置 hoursminutes

latestStartTime

object (DateTime)

广告插播的最晚开始时间(含此时间)。只能设置 hoursminutes

durationMinutes

integer

广告插播时长(以分钟为单位)。

ruleIncrementMinutes

integer

[可选] 可纳入此广告插播规则中的所有广告插播时间点的时间增量(以分钟为单位)。如果未设置,则默认为 durationMinutes

CoverageRequirement

保险范围要求规定了在特定时间段和指定地点担任一组角色和/或技能所需的员工人数。特定位置的日期时间间隔不能重叠。或者,您也可以提供班次 ID 列表,而不是时间范围和地点。只有可分配到特定角色(或拥有特定技能)的员工才能满足此要求。

对于给定的角色和/或技能,当时间范围内每个时刻(或shiftIds的每班班次)至少有 targetEmployeeCount 名员工在工作,即满足保险范围要求。相反,如果在某个时间段的任何时间点(或shiftIds的任何班次),在这段时间内工作的员工人数少于 targetEmployeeCount,则不符合保险范围要求。即使员工人数多于 targetEmployeeCount,仍满足要求,但求解器可以最大限度地减少人手过多。

JSON 表示法
{
  "startDateTime": {
    object (DateTime)
  },
  "endDateTime": {
    object (DateTime)
  },
  "locationId": string,
  "shiftIds": [
    string
  ],
  "roleRequirements": [
    {
      object (RoleRequirement)
    }
  ],
  "skillRequirements": [
    {
      object (SkillRequirement)
    }
  ]
}
字段
startDateTime

object (DateTime)

覆盖范围要求的开始时间(含此时间)。如果设置,shiftIds 必须为空。

endDateTime

object (DateTime)

保修要求的结束时间(不含)。如果设置,shiftIds 必须为空。

locationId

string

需要员工的工作地点。“shiftIds”不为空,此字段必须为空。

shiftIds[]

string

如果已设置,角色和技能要求会单独应用于此列表中的每个班次 ID。如果 shiftId 为非空,则 startDateTimeendDateTimelocationId 必须为空。

roleRequirements[]

object (RoleRequirement)

在时间范围内分配给指定角色的员工人数要求。对于每个角色 ID,最多只能提供一个 role_requirement。每项要求的默认优先级为 PRIORITY_MANDATORY。如果在这段时间内的任意时间点分配给指定角色的员工少于 targetEmployeeCount 人,就会违反这些限制。

skillRequirements[]

object (SkillRequirement)

在相应时间范围内轮班的具有指定技能的员工人数要求。每个技能 ID 最多只能提供一个 skill_requirement。每项要求的默认优先级为 PRIORITY_LOW。如果在任意时间点拥有指定技能的员工少于 targetEmployeeCount 人,就会违反这些限制。

RoleRequirement

在时间范围内分配给指定角色的员工人数要求。

JSON 表示法
{
  "roleId": string,
  "targetEmployeeCount": integer,
  "priority": enum (Priority)
}
字段
roleId

string

要求的角色 ID。

targetEmployeeCount

integer

在时间范围内分配给相应角色的员工人数。

priority

enum (Priority)

此要求限制条件的优先级。所有资源限制条件的默认优先级为 PRIORITY_MANDATORY

SkillRequirement

在这段时间内工作且具备指定技能的员工人数要求。

JSON 表示法
{
  "skillId": string,
  "targetEmployeeCount": integer,
  "priority": enum (Priority)
}
字段
skillId

string

要求的技能 ID。

targetEmployeeCount

integer

在指定时间范围内工作且具有指定技能的期望员工人数。

priority

enum (Priority)

此要求限制条件的优先级。所有资源限制条件的默认优先级为 PRIORITY_LOW

BudgetRequirement

给定时间间隔内的预算要求。

JSON 表示法
{
  "totalBudget": number,
  "startDateTime": {
    object (DateTime)
  },
  "endDateTime": {
    object (DateTime)
  },
  "priority": enum (Priority)
}
字段
totalBudget

number

指定时间间隔内的总预算。如果优先级为 PRIORITY_MANDATORY,则必须指定总预算。

如果未设置 totalBudget,则系统会根据指定的 priority 将时间表的总费用降至最低。例如,如果预算的 priorityPRIORITY_MEDIUM,则求解器会在减少任何优先级为 PRIORITY_LOW 的限制条件违规行为之前将成本降至最低。

startDateTime

object (DateTime)

此预算适用的开始时间。如果未指定开始时间,则将其设置为所有给定班次的最早开始时间。

endDateTime

object (DateTime)

此预算适用的结束时间。如果未指定结束时间,则将其设置为所有给定班次的最晚结束时间。

priority

enum (Priority)

在指定时间范围内满足预算要求的优先级。默认优先级为 PRIORITY_LOW。如果优先级设置为 PRIORITY_MANDATORY,则必须设置 totalBudget

请注意,如果此优先级高于其他限制条件优先级,并且 totalBudget 比较紧张,那么生成的时间表可能会严重违反员工限制条件或覆盖范围要求。

ShiftAssignment

负责轮班的员工。

JSON 表示法
{
  "employeeId": string,
  "shiftId": string,
  "roleId": string,
  "breaks": [
    {
      object (Break)
    }
  ]
}
字段
employeeId

string

正在分配的员工 ID。

shiftId

string

分配给员工的排班 ID。

roleId

string

轮班为员工分配的角色 ID。

breaks[]

object (Break)

此轮班分配的休息列表。

休息时间

员工在换班期间打断工作的时间段。

JSON 表示法
{
  "startDateTime": {
    object (DateTime)
  },
  "durationMinutes": integer
}
字段
startDateTime

object (DateTime)

休息的开始时间。

durationMinutes

integer

广告插播时长(以分钟为单位)。

SolutionStatus

求解器的响应中提供的求解(即时间表)状态。

枚举
SOLUTION_STATUS_UNSPECIFIED 未指定的响应状态。
FEASIBLE 返回的时间表是可行的,但可能不是最佳。
OPTIMAL 返回的时间表是最佳的。
INFEASIBLE 对于给定的约束条件,不存在可行的时间表。如果无法满足优先级为 PRIORITY_MANDATORY 的约束条件的任何子集,求解器可能会返回此值。
NOT_SOLVED 未找到任何时间表。
NOT_SOLVED_DEADLINE_EXCEEDED 在指定的时限内未找到任何时间表。