Drools迭代一个对象列表,对列表中的所有对象,求和该对象某个字段的值

Drools iterate an object list and for all objects in the list, sum up the value of a field of the object

我正在尝试构建一个 drools 规则,其中提供的事实具有用户提供的 int 值。 Fact 也有一个具有预期 int 值的对象列表。我需要检查用户提供的值是否小于各个对象期望值的总和。 这是我的示例事实 class -

public class Order {
    private int orderId;
    private List<OrderItem> orderItems;    
    private int usersIntegrationFee;
}

包含在事实 class 中的 OrderItem class 是 -

public class OrderItem {
    private int orderItemId;
    private Product prod;
}

并且产品 class 是具有 productIntegrationFee 字段的产品 -

public class Product {
    private String mktProdId;
    private String prodName;
    private int productIntegrationFee;
}

我想检查 Order.usersIntegrationFee 是否小于所有 Order.OrderItem.Product.productIntegrationFee 的总和。 有没有办法在流口水中做到这一点?任何帮助将不胜感激。

您需要使用的是名为 accumulate 的 drools 内置实用程序。此实用程序允许您迭代右侧的对象集合,同时 "accumulating" 某种变量值。一些常见用例涉及求和、均值、计数等。基本上,构造循环遍历集合中的每个项目并对每个项目执行一些定义的操作。

虽然您可以定义自己的自定义累积函数,但 Drools 支持多种内置累积函数 -- 其中之一是 sum。这个内置函数是您特定用例所需要的。

accumulate的一般格式是这样的:accumulate( <source pattern>; <functions> [;<constraints>] )。您的规则看起来像这样(伪代码,因为我在这台计算机上没有 Drools;语法应该接近或准确,但可能存在拼写错误。)

rule "Integration fee is less than sum of product fees"
when
  // extract the variables from the Order
  Order( $userFee: usersIntegrationFee,
         $items: orderItems)

  // use the accumulate function to sum up the product fees
  $productFees: Integer( this > $userFee ) from 
                accumulate( OrderItem( $product: prod ) from $items,
                            Product( $fee: productIntegrationFee ) from $product;
                            sum($fee) )
then
  // do something
end

一些注意事项。在单个 accumulate 中,您可以做多种事情 -- 求和、求平均值等等。但是如果你像这里一样只调用一个累加函数,你可以使用我展示的语法(Integer( conditions ) from accumulate( ... )。)如果你有多个函数,你必须直接分配输出(例如 $sum: sum($fee), 等等)

最后还有 accumulate 的第三个可选参数,我已将其省略,因为您的用例非常简单并且不需要它。第三个参数应用过滤(称为 'constraints'),以便累积函数跳过不符合此条件的项目。例如,您可以添加一个约束来忽略像这样的负数 productIntegrationFee 值:$fee > 0.

关于我在此规则中选择的语法的最后说明。由于用例是 "trigger the rule if the usersIntegrationFee is less than the sum,",我将比较直接放在 Integer( ... ) from accumulate 中。当然,您可以单独进行比较,例如 Integer( $productFees > this ) from $userFee 或您喜欢的任何其他比较格式。这种方式看起来最简单。

Drools documentation 有更多关于此实用程序的信息。我已经链接到讨论 'when' 子句中元素的部分;向下滚动一点,直接查看 accumulate 的文档。