如何通过.map()与Join将约束流基数提升至5?技术实现咨询
解决方案
针对你的问题,我们可以通过封装上下文数据、完善关联逻辑来解决,具体修改如下:
1. 定义上下文封装类(Java 16+ 用Record,低版本用带Getter的POJO)
先把需要传递的多维度数据封装成一个对象,方便下游统一提取:
// 放在当前类内部或单独创建类,低版本替换为普通POJO private record RuleE015Context(RuleSetting ruleSetting, Employee employee, Integer weekNo, Long totalDuration) {}
2. 填充.map()函数
将groupBy过滤后的四个参数打包到上下文对象中,向下游传递:
.map((ruleSetting, employee, weekNo, totalDuration) -> new RuleE015Context(ruleSetting, employee, weekNo, totalDuration))
3. 修正join(ForeignerType.class)的关联逻辑
必须添加匹配条件,确保基于员工的外籍类型关联正确的ForeignerType,避免无效的笛卡尔积:
.join(ForeignerType.class, (context) -> context.employee().getForeignerType(), (foreignerType) -> foreignerType.getForeignerType())
4. 在penalizeConfigurable中提取数据并应用基数提升规则
此时第一个参数是我们封装的上下文对象,直接从中提取所需数据,同时将基数提升至5:
.penalizeConfigurable((context, foreignerType) -> { RuleSetting ruleSetting = context.ruleSetting(); Employee employee = context.employee(); Long totalDuration = context.totalDuration(); // 计算惩罚值,乘以5实现基数提升 double ratio = (double) totalDuration / employee.getContracts().getMaxMinutesPerWeek(); double penalty = Math.abs(ratio) * Math.abs(ruleSetting.getWeight()) * 5; return penalty.intValue(); })
5. 调整indictWith的参数
同样从上下文对象中提取数据生成EmployeeScoreKeyItems:
.indictWith((context, foreignerType) -> { RuleE015Context ctx = (RuleE015Context) context; EmployeeScoreKeyItems res = new EmployeeScoreKeyItems( EmployeeScoreKeyItems.KeyType.BY_WEEK, ctx.ruleSetting().getRuleName(), ctx.employee().getEmployeeId(), null, null, ctx.weekNo(), null ); return List.of(res); })
完整修改后的代码
// 上下文封装类 private record RuleE015Context(RuleSetting ruleSetting, Employee employee, Integer weekNo, Long totalDuration) {} return constraintFactory.forEach(RuleSetting.class) .filter(ruleSetting -> ruleSetting.getRuleName().equals("E015") && ruleSetting.getIsActive()) .join(Shift.class) .join(ForeignerType.class) .filter((ruleSetting, shift, foreignerType) -> shift.getEmployee().getForeignerType() != null && foreignerType.getForeignerType().equals(shift.getEmployee().getForeignerType()) && shift.getWeekNo() != null) .groupBy((ruleSetting, shift, foreignerType) -> ruleSetting, (ruleSetting, shift, foreignerType) -> shift.getEmployee(), (ruleSetting, shift, foreignerType) -> shift.getWeekNo(), ConstraintCollectors.sumLong((ruleSetting, shift, foreignerType) -> shift.getWorkMinutes())) .filter((ruleSetting, employee, weekNo, totalDuration) -> totalDuration > employee.getContracts().getMaxMinutesPerWeek()) // 封装上下文传递数据 .map((ruleSetting, employee, weekNo, totalDuration) -> new RuleE015Context(ruleSetting, employee, weekNo, totalDuration)) // 正确关联ForeignerType .join(ForeignerType.class, (context) -> context.employee().getForeignerType(), (foreignerType) -> foreignerType.getForeignerType()) // 计算惩罚值并提升基数至5 .penalizeConfigurable((context, foreignerType) -> { RuleSetting ruleSetting = context.ruleSetting(); Employee employee = context.employee(); Long totalDuration = context.totalDuration(); double ratio = (double) totalDuration / employee.getContracts().getMaxMinutesPerWeek(); double penalty = Math.abs(ratio) * Math.abs(ruleSetting.getWeight()) * 5; return penalty.intValue(); }) // 生成惩罚标识 .indictWith((context, foreignerType) -> { RuleE015Context ctx = (RuleE015Context) context; EmployeeScoreKeyItems res = new EmployeeScoreKeyItems( EmployeeScoreKeyItems.KeyType.BY_WEEK, ctx.ruleSetting().getRuleName(), ctx.employee().getEmployeeId(), null, null, ctx.weekNo(), null ); return List.of(res); }) .asConstraint("E015");
关键说明
- 用
RuleE015Context统一封装所有需要传递的数据,解决下游无法获取上游多参数的问题 join时添加关联条件,避免无意义的笛卡尔积,提升规则执行效率- 在
penalizeConfigurable中通过上下文对象直接获取所需数据,乘以5实现基数提升要求
内容的提问来源于stack exchange,提问作者I. Ahmed
相关产品推荐
相关产品推荐

