optaplanner自定义ScoreHolder的实现

时间:2014-12-11 02:31:33

标签: optimization drools optaplanner

我的主要问题是,如果我可以在OptaPlanner中使用ScoreHolder自定义实施drools得分计算?如果是,我怎么做,因为scoreHolder对象被隐式注入全局变量?下面你可以找到详细信息,为什么我想使用ScoreHolder的自定义实现。

我在一个需要优化某些产品价值的应用程序的工作中发现了一个问题。我有设备,并根据预测我计算每个设备的生产。 我使用OptaPlanner,我的规则如下:

when
    $device : Device($deviceId : id)
    $forecast : Forecast(deviceId == $deviceId)
then
    int deviceProduction = $device.calculateProduction($forecast);
    scoreHolder.addSoftConstraintMatch(kcontext, deviceProduction);
end

所以在此之后,软分数将包含整体产量(overallProduction)。我想要的是在软得分中保持整体产量的VALUE。问题是,生产价值不仅仅是整体生产乘以价格。生产限制,超出限制的一切都有负价格。所以我们给出了限价和两个价格:正(positive_price)和负(negative_price)。值计算的模式如下所示:

if( overallProduction <= limit)
    value = positive_price * overallProduction;
else
    value = positive_price * limit + negative_price * (overallProduction - limit);

所以我认为,我不能在单个设备的规则计算生产中包含此值的计算,因为只有在从所有设备收集生产之后,我才能计算出整个生产的这个值。

我唯一的想法是如何处理它,是自定义实现scoreHolder扩展HardSoftScoreHolder。这个自定义ScoreHolder将保持内部,在软疮,整体生产。它将按照开头给出的规则计算。然后,在返回extractScore方法的结果之前,自定义ScoreHolder将计算正确的值。

问题是,如果我可以在drools得分计算中使用我的自定义ScoreHolder?由于全局scoreHolder对象是隐式注入的。

或者,如果还有其他方法可以将整体制作的价值放入分数对象中?

感谢您的帮助和最诚挚的问候,

2 个答案:

答案 0 :(得分:1)

而不是攻击ScoreHolder,我就像Geoffrey De Smet建议的那样,谢谢!

rule "SingleProduction"
    when
        $device : Device($deviceId : id)
        $forecast : Forecast(deviceId == $deviceId)
    then
        int deviceProduction = $device.calculateProduction($forecast);
        insertLogical(new SingleProduction(deviceProduction));
end

rule "ValueOfTotalProduction"
    when
        ProductionLimit( $limit : value )
        PositivePrice( $positivePrice : value )
        NegativePrice( $negativePrice : value )
        Number( $totalProduction : intValue() )
                 from accumulate( SingleProduction( $value : value ),
                              sum( $value ) )
    then
        int productionValue;
        if($totalProduction <= $limit)
            productionValue = $totalProduction * $positivePrice;
        else
            productionValue = $limit * $positivePrice +
                              ($totalProduction - $limit) * $negativePrice;

        scoreHolder.addSoftConstraintMatch(kcontext, productionValue);
end

答案 1 :(得分:0)

攻击ScoreHolder不是这样做的方法(虽然通过创建自定义ScoreDefinition,你可以这样做。)

相反,您的规则可以使用insertLogical()将中间结果作为新事实插入,而不是直接修改ScoreHolder。然后另一个规则匹配该中间结果(可能具有较低的salience)并相应地修改ScoreHolder。有关示例,请参阅护士排班示例。

劳恩的方式也行。