You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OptaPlanner:MultiConstraintStream的GroupBy多字段分组用法疑问

OptaPlanner 多字段GroupBy实现:每日作业产出上限约束

问题核心

需要按时间段(日期)和作业类型对活跃作业分组,汇总每日产出并判断是否超过该作业类型的日产出上限。

优化后的完整约束代码

private Constraint maximumDailyOutput(ConstraintFactory constraintFactory) {
    // 限制每种作业类型的每日最大产出量
    return constraintFactory.forEach(TimeSlotOpta.class)
            // 关联当日活跃的作业
            .join(JobOpta.class, 
                  Joiners.filtering((timeSlot, job) -> job.isActive(timeSlot.getDay())))
            // 按【时间段】和【作业类型】分组,同时汇总该组的每日产出总和
            .groupBy(
                // 第一个分组键:时间段(日期)
                (timeSlot, job) -> timeSlot,
                // 第二个分组键:作业类型
                (timeSlot, job) -> job.getJobType(),
                // 聚合函数:汇总该组所有作业的每日产出
                ConstraintCollectors.sum(job -> job.getDailyOutput())
            )
            // 仅对产出超过上限的分组进行惩罚
            .filter((timeSlot, jobType, totalDailyOutput) -> 
                    totalDailyOutput > jobType.getMaximumDailyOutput())
            // 计算惩罚值:超出上限的部分
            .penalize("Maximum daily output exceeded", 
                      HardMediumSoftScore.ONE_HARD,
                      (timeSlot, jobType, totalDailyOutput) -> 
                          totalDailyOutput - jobType.getMaximumDailyOutput());
}

关键细节说明

  1. 移除冗余的JobTypeOpta关联
    原代码中额外join(JobTypeOpta.class)完全没必要,因为JobOpta已经通过getJobType()持有JobTypeOpta引用,直接提取即可,减少了不必要的关联和过滤逻辑,提升约束计算效率。

  2. 多字段GroupBy的正确写法
    OptaPlanner的groupBy支持同时指定多个分组键,配合聚合函数:

    • 前两个参数是分组键提取器,分别提取时间段和作业类型作为分组依据;
    • 第三个参数是聚合函数,这里用ConstraintCollectors.sum()汇总该组所有作业的dailyOutput。
  3. 添加过滤逻辑避免无效惩罚
    在groupBy之后添加filter,只对totalDailyOutput超过jobType.getMaximumDailyOutput()的分组进行惩罚,避免对合规分组产生不必要的计算。

  4. 方法名规范
    修正了原方法名MaximumDailyOuput的拼写错误(应为maximumDailyOutput,符合Java驼峰命名规范)。

内容的提问来源于stack exchange,提问作者Rayamon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 06:01:47