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

如何合并两个ConstraintStream以实现类似SQL UNION ALL的效果?

目前OptaPlanner的ConstraintStream API 8.28.0.Final及以上版本已提供原生的concat()操作,等价于SQL的UNION ALL,可直接实现多个同类型约束流的合并。如果使用旧版本,也可以通过影子变量方案实现需求。

方案1:使用原生concat方法(推荐,适用于8.28.0及以上版本)

你需要先将已购买牌照的频谱使用权展开为单个元素流,再和现有频谱权流直接合并:

private Constraint computeAggregatedSpectrum(ConstraintFactory factory) {
    // 现有频谱权流:从问题事实集合直接获取所有已有权限
    UniConstraintStream<SpectrumRight> existingRightStream = factory.from(SpectrumRight.class);
    // 已购买牌照的频谱权流:筛选拍下的牌照,展开为单个频谱权元素
    UniConstraintStream<SpectrumRight> purchasedRightStream = factory.from(AuctionLicense.class)
            .filter(AuctionLicense::isBuy)
            // 用flattenLast展开频谱权列表,替代原有的map操作
            .flattenLast(AuctionLicense::getSpectrumRights);

    // concat等价于UNION ALL,直接合并两个同类型流
    return existingRightStream
            .concat(purchasedRightStream)
            .groupBy(toSortedSet())
            .map(MetricsCalculator::computeAggregatedSpectrumMhzPops)
            .reward("聚合频谱指标计算", HardSoftScore.ONE_SOFT);
}

如果需要去重,在concat后追加.groupBy(Function.identity(), countDistinct())或者使用distinct()转换器即可。

提示:如果使用toSortedSet(),需要确保SpectrumRight类实现了Comparable接口,或者传入自定义的比较器。

方案2:影子变量预计算(兼容所有版本,适合复杂合并逻辑)

如果使用旧版本OptaPlanner,或者合并逻辑后续可能扩展,可以通过影子变量预计算合并后的频谱权集合:

第一步:实现变量监听器

监听牌照购买状态的变化,自动更新合并后的频谱权集合:

public class MergedSpectrumRightListener implements VariableListener<AuctionLicense> {
    @Override
    public void beforeVariableChanged(ScoreDirector<?> scoreDirector, AuctionLicense entity) {}

    @Override
    public void afterVariableChanged(ScoreDirector<?> scoreDirector, AuctionLicense entity) {
        SpectrumSolution solution = (SpectrumSolution) scoreDirector.getWorkingSolution();
        SortedSet<SpectrumRight> mergedSet = new TreeSet<>(solution.getExistingPortfolio());
        for (AuctionLicense license : solution.getAuctionLicenses()) {
            if (license.isBuy()) {
                mergedSet.addAll(license.getSpectrumRights());
            }
        }
        // 通知分数计算器集合发生变更
        scoreDirector.beforeProblemPropertyChanged(solution);
        solution.setMergedSpectrumRights(mergedSet);
        scoreDirector.afterProblemPropertyChanged(solution);
    }

    @Override
    public void resetWorkingSolution(ScoreDirector<?> scoreDirector) {}
    @Override
    public void close() {}
}

第二步:在规划解类中配置影子变量

@PlanningSolution
public class SpectrumSolution {
    @ProblemFactCollectionProperty
    private List<SpectrumRight> existingPortfolio;

    @PlanningEntityCollectionProperty
    private List<AuctionLicense> auctionLicenses;

    // 配置影子变量,绑定监听器和触发变量
    @ShadowVariable(
        variableListenerClass = MergedSpectrumRightListener.class,
        sourceEntityClass = AuctionLicense.class,
        sourceVariableName = "buy"
    )
    private SortedSet<SpectrumRight> mergedSpectrumRights;

    // 省略其他属性和getter/setter
}

第三步:编写约束逻辑

直接从预计算的合并集合构造流即可:

private Constraint computeAggregatedSpectrum(ConstraintFactory factory) {
    return factory.from(SpectrumSolution.class)
            .map(SpectrumSolution::getMergedSpectrumRights)
            .map(MetricsCalculator::computeAggregatedSpectrumMhzPops)
            .reward("聚合频谱指标计算", HardSoftScore.ONE_SOFT);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 12:09:03