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

Timefold中如何基于实体与问题事实集计算扣分规则

问题描述

此前使用OptaPlanner + Drools时,我们通过insertLogical创建包含实体集合与问题事实集合的pointscalculateinstance实例,基于该实例的计算结果确定多个扣分点。相关示例如下:

Drools规则示例

rule "create pointscalculateinstance"
    when 
        $requestList :  ArrayList() from collect  (
        Request ()
        )  
        
        $stockList : ArrayList() from collect (
        Stock()
        )
        
        $taskList :  ArrayList() from collect  (
        Task (machine != null)
        )
    then
        insertLogical(new pointscalculateinstance($requestList,$stockList,$taskList));
        
    end


rule "point1 rule"
    when 
        $pointscalculateinstance : pointscalculateinstance ($point1 : point1)
        eval($point1 > 0)
    then
        scoreHolder.addSoftConstraintMatch(kcontext, $point1); 
    end

rule "point2 rule"
    when 
        $pointscalculateinstance: pointscalculateinstance($point2 : point2)
        eval($point2 > 0)
    then
        scoreHolder.addSoftConstraintMatch(kcontext, $point2); 
    end

rule "point3 rule"
    when 
        $pointscalculateinstance : pointscalculateinstance($point3 : point3)
        eval($point3 > 0)
    then
        scoreHolder.addHardConstraintMatch(kcontext, $point3); 
    end

相关类定义

pointscalculateinstance类

public class pointscalculateinstance{ 

    private ArrayList<Request> requestList;
    private ArrayList<Stock> stockList;
    private ArrayList<Task> taskList;
    private int point1;  
    private int point2;  
    private int point3;  
    private int point4; 
    private int point5; 
    private int point6; 
    private int point7; 
    private int point8; 
    private int point9; 
    private int point10; 
}

Planning(Solution类)

@PlanningSolution
public class Planning{

    
   @PlanningScore
   private HardMediumSoftScore  score;
    
   @PlanningEntityCollectionProperty
   @ValueRangeProvider(id = "taskRange")
   private ArrayList<Task> taskList;
    
    
    @ProblemFactCollectionProperty
    @ValueRangeProvider(id = "machineRange")
    private ArrayList<Machine> machineList;
    
    @ProblemFactCollectionProperty
    private ArrayList<Request> requestList;
    
    @ProblemFactCollectionProperty
    private ArrayList<Stock> stockList;
}

这是一个链式模型,需基于任务列表的链式顺序计算每个方案的库存消耗利用率。重构时想用Timefold的Constraint Stream实现,但如果用group by + tolist()会重复编写大量约束,不是最优方案。请问如何在Timefold中创建含实体集合与问题事实集合参数的实例,基于其计算结果确定多个扣分点?


解决方案

在Timefold的Constraint Stream中,无需像Drools那样插入逻辑对象,可通过聚合所有需要的集合并复用计算逻辑,一次性推导所有扣分点,避免重复编写流程。

步骤1:完善计算类

先遵循Java规范将pointscalculateinstance重命名为PointsCalculateInstance,并补充计算所有扣分点的核心逻辑:

public class PointsCalculateInstance {
    private List<Request> requestList;
    private List<Stock> stockList;
    private List<Task> taskList;
    private int point1;
    private int point2;
    private int point3;
    // ... 其他point字段

    // 构造方法:传入集合后自动计算所有扣分点
    public PointsCalculateInstance(List<Request> requestList, List<Stock> stockList, List<Task> taskList) {
        this.requestList = requestList;
        this.stockList = stockList;
        this.taskList = taskList;
        calculateAllPoints();
    }

    // 核心业务逻辑:按任务链式顺序计算库存消耗利用率,推导所有point值
    private void calculateAllPoints() {
        // 实现你的业务逻辑:比如遍历链式任务、计算库存消耗、赋值point1-point10
        this.point1 = ...;
        this.point2 = ...;
        this.point3 = ...;
        // ... 其他point的计算逻辑
    }

    // Getter方法
    public int getPoint1() { return point1; }
    public int getPoint2() { return point2; }
    public int getPoint3() { return point3; }
    // ... 其他point的Getter
}

步骤2:在Constraint Stream中复用聚合与计算逻辑

在约束提供者类中,提取共享的集合聚合逻辑,所有扣分点约束复用同一计算实例,避免重复执行流程:

public class PlanningConstraintProvider implements ConstraintProvider {
    @Override
    public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
        return new Constraint[] {
            calculatePoint1(constraintFactory),
            calculatePoint2(constraintFactory),
            calculatePoint3(constraintFactory)
            // ... 其他point对应的约束
        };
    }

    // 提取共享的聚合逻辑:生成计算实例的流
    private UniConstraintStream<PointsCalculateInstance> getCalculationInstanceStream(ConstraintFactory factory) {
        return factory.from(Request.class)
                .groupBy(
                        Collectors.toList(),
                        (request) -> factory.from(Stock.class).collect(Collectors.toList()),
                        (request) -> factory.from(Task.class).filter(task -> task.getMachine() != null).collect(Collectors.toList())
                )
                .map((requestList, stockList, taskList) -> new PointsCalculateInstance(requestList, stockList, taskList));
    }

    // Point1:软约束扣分
    private Constraint calculatePoint1(ConstraintFactory factory) {
        return getCalculationInstanceStream(factory)
                .filter(instance -> instance.getPoint1() > 0)
                .penalize("Point1 penalty", HardMediumSoftScore.ONE_SOFT, PointsCalculateInstance::getPoint1);
    }

    // Point2:软约束扣分
    private Constraint calculatePoint2(ConstraintFactory factory) {
        return getCalculationInstanceStream(factory)
                .filter(instance -> instance.getPoint2() > 0)
                .penalize("Point2 penalty", HardMediumSoftScore.ONE_SOFT, PointsCalculateInstance::getPoint2);
    }

    // Point3:硬约束扣分
    private Constraint calculatePoint3(ConstraintFactory factory) {
        return getCalculationInstanceStream(factory)
                .filter(instance -> instance.getPoint3() > 0)
                .penalize("Point3 penalty", HardMediumSoftScore.ONE_HARD, PointsCalculateInstance::getPoint3);
    }

    // ... 其他point对应的约束方法,统一复用getCalculationInstanceStream的逻辑
}

关键说明

  1. 避免重复计算:通过getCalculationInstanceStream方法共享集合聚合与实例计算逻辑,所有约束仅执行一次核心计算流程,兼顾性能与代码简洁性。
  2. 贴合流式编程风格:Timefold Constraint Stream无需插入逻辑对象,直接通过聚合+映射生成计算实例,更符合Java开发习惯。
  3. 满足链式任务需求:在PointsCalculateInstance的calculateAllPoints方法中,可直接按任务链式顺序遍历处理,完全适配库存消耗利用率的计算需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 13:18:10