如何在OptaPlanner约束中获取@PlanningEntity/@PlanningVariable完整列表
解决OptaPlanner航空座位分配中获取全部Passenger实例的约束逻辑实现
在航空座位分配场景里,要基于乘客出价(Bid)奖励最高出价的已分配乘客,核心是在约束逻辑中获取所有已分配的Passenger实例来做全局判断。你之前用groupBy只拿到单个实例,是因为没做全局分组——默认的分组会按实例属性拆分,要获取完整列表,需要把所有目标实例归到同一个全局组里。
具体实现方式(Constraint Streams API)
用OptaPlanner的Constraint Streams API,通过全局分组收集所有已分配乘客,再筛选出最高出价者给予奖励:
import org.optaplanner.core.api.score.stream.Constraint; import org.optaplanner.core.api.score.stream.ConstraintFactory; import org.optaplanner.core.api.score.stream.ConstraintProvider; import java.util.stream.Collectors; public class SeatAssignmentConstraintProvider implements ConstraintProvider { @Override public Constraint[] defineConstraints(ConstraintFactory constraintFactory) { return new Constraint[] { rewardTopBidAssignedPassenger(constraintFactory) }; } private Constraint rewardTopBidAssignedPassenger(ConstraintFactory constraintFactory) { // 1. 筛选所有已分配座位的乘客,全局分组收集为列表 return constraintFactory.forEach(Passenger.class) .filter(passenger -> passenger.getAssignedSeat() != null) // 用固定常量作为分组键,将所有已分配乘客归入同一组 .groupBy(() -> "allAssignedPassengers", Collectors.toList()) // 2. 从全局列表中找出最高出价,筛选出对应乘客 .flatMap((groupKey, assignedPassengers) -> { int maxBid = assignedPassengers.stream() .mapToInt(Passenger::getBid) .max() .orElse(0); return assignedPassengers.stream() .filter(p -> p.getBid() == maxBid); }) // 3. 对最高出价乘客给予奖励分数(这里用Soft分,可根据需求调整分值) .reward("Reward highest bid assigned passenger", HardSoftScore.ofSoft(150)); } }
关键说明
- 全局分组:
groupBy(() -> "allAssignedPassengers", Collectors.toList())是核心——用固定字符串作为分组键,强制所有已分配乘客进入同一个组,这样就能拿到完整的实例列表。 - 筛选逻辑:通过
flatMap从全局列表中提取最高出价的乘客,避免重复判断。 - 分数调整:
HardSoftScore.ofSoft(150)可根据业务需求修改分值,或换成其他分数类型(如SimpleScore)。
另一种简化实现(直接判断单个乘客是否为全局最高)
如果不需要对所有最高出价乘客批量处理,也可以在遍历单个乘客时,通过关联判断确认是否为全局最高出价者:
private Constraint rewardTopBidPassengerSimplified(ConstraintFactory constraintFactory) { return constraintFactory.forEach(Passenger.class) .filter(p -> p.getAssignedSeat() != null) // 关联所有已分配乘客,判断当前乘客的Bid是否是全局最大 .join(Passenger.class, Joiners.equal(p -> true, other -> true), // 全局关联 Joiners.filtering((p, other) -> other.getAssignedSeat() != null), Joiners.filtering((p, other) -> p.getBid() >= other.getBid())) // 确保当前乘客的Bid大于等于所有其他已分配乘客的Bid .groupBy((p, other) -> p, Collectors.counting()) .filter((p, count) -> count == constraintFactory.from(Passenger.class) .filter(other -> other.getAssignedSeat() != null) .count()) .reward("Reward top bid passenger", HardSoftScore.ofSoft(150)); }
这种方式不需要显式收集列表,但逻辑稍复杂,适合场景简单的情况。
内容的提问来源于stack exchange,提问作者P_C
相关产品推荐
相关产品推荐

