第一个与规则匹配的输入完成后,剩余的输入将被忽略

问题描述 投票:0回答:1

我在我的用例中使用 Drools 规则引擎,我必须根据多个属性确定产品的所有者。我创建了一套规则。

我有大约 1000 个输入产品和大约 50 条规则。我正在使用 drool 规则引擎使用 50 条规则来映射每个产品的所有者。必须对每个产品应用所有 50 条规则才能确定所有者。

这是我的规则的示例


rule "create drool rule from input values with rule id - rule_1"
    salience 110
    activation-group "product-owner-assignment-rules-group"
    when
        $product: Product()
        Product(productName == "Jigsaw")
        Product(productType == "Resistor")
        Product(productManufacturerName == "Corp.Inc")
    then
        $product.setOwnerName("Mr.X");
        $product.setRuleId("rule_1");
    end

我的 Drools 规则执行器看起来像这样

public void executeRules(@NonNull final List<Rule> droolRules, @NonNull final List<Product> productOwners) {
        final KnowledgeBuilder knowledgeBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        for (final String rule : droolRules) {
            knowledgeBuilder.add(ResourceFactory.newByteArrayResource(rule.getBytes(Charset.forName(StandardCharsets.UTF_8.name()))),
                    ResourceType.DRL);
        }
        if (knowledgeBuilder.hasErrors()) {
            String errorMessage = "Encountered errors while building rules into the Knowledge Builder:\n" + knowledgeBuilder.getErrors();
            log.error(errorMessage);
            throw new RuntimeException(errorMessage);
        }
        final InternalKnowledgeBase knowledgeBase = KnowledgeBaseFactory.newKnowledgeBase();
        knowledgeBase.addPackages(knowledgeBuilder.getKnowledgePackages());

        final StatelessKieSession kieSession = knowledgeBase.newStatelessKieSession();
        productOwners.forEach(productOwnerValue -> {
            kieSession.execute(productOwnerValue);
        });
}

如果我规则每个 Product 对象的 StatelessKieSession ,那么这工作得很好。但在循环每个产品时会造成性能影响。

如果我想同时执行所有事实和规则,规则引擎只会用第一个规则匹配的 RHS 更新最后一个事实。


final KieSession kieSession1 = knowledgeBase.newKieSession();
        productOwners.forEach(productOwnerValue -> {
            kieSession.insert(productOwnerValue);
        });
 kieSession1.fireAllRules();

任何人都可以帮助我理解如何同时激发所有规则和所有事实,以加快性能并获得正确的结果。

drools optaplanner drools-fusion drools-flow
1个回答
0
投票

你的规则不是做你认为它会做的事。

rule "create drool rule from input values with rule id - rule_1"
    salience 110
    activation-group "product-owner-assignment-rules-group"
    when
        $product: Product()
        Product(productName == "Jigsaw")
        Product(productType == "Resistor")
        Product(productManufacturerName == "Corp.Inc")
    then
        $product.setOwnerName("Mr.X");
        $product.setRuleId("rule_1");
    end

您想要查找名称为“Jigsaw”、类型为“电阻器”、制造商为“Corp.Inc”的单个产品。然后您想要使用所有者名称和规则 ID 更新该单个产品。

你的规则实际上做的是检查是否存在名为 Jigsaw 的产品;电阻器类型的产品;以及制造商 Corp.Inc. 的产品。没有一种产品具有所有 3 个属性(尽管它可能会找到满足该条件的产品,但这不是规则定义方式的要求。)。它还将所有者名称和规则 ID 分配给工作内存中的随机产品,不一定是与您检查的属性相匹配的任何产品。

您的规则应该是这样的:

rule "rule_1 - fixed"
when
  $product: Product( productName == "Jigsaw",
                     productType == "Resistor",
                     productManufacturerName == "Corp.Inc" )
then
  $product.setOwnerName("Mr.X");
  $product.setRuleId("rule_1");
end

“when”子句中的每个语句都是单独评估的。所以你的规则正在做的是这样的:

$product: Product()

首先,识别工作记忆中的一个产品,并将其分配给变量

$product
。此处没有指定条件,因此它将匹配内存中存在的任何产品。

Product( productName == "Jigsaw" )

在工作记忆中查找产品名称为“Jigsaw”的产品。由于此调用的结果未分配给变量,因此相当于仅检查具有此名称的产品是否存在。

Product( productType == "Resistor" )

同样,查找类型为“电阻器”的产品。这也是一个存在性检查。无法保证它找到的内容与被识别为名称为“Jigsaw”的内容相同,也不一定与分配给变量

$product
的内容相同。

Product( productManufacturerName == "Corp.Inc" )

查找制造商为“Corp.Inc”的产品。还需要进行存在性检查,并且不需要与前面提到的其他语句有任何关系。

这实际上意味着什么?考虑这些项目:

[
  { productName: "Jigsaw", productType: "Resistor", productManufacturerName: "Acme.Inc" },
  { productName: "Jigsaw", productType: "Resistor", productManufacturerName: "FooBar.Ltd" },
  { productName: "Thingy", productType: "Widget", productManufacturerName: "Corp.Inc" }
]

这些输入都不满足您的所有条件,但您编写的规则仍会触发,因为至少有一个产品单独满足每个条件。哪一个是

$product
取决于很多因素,包括顺序以及这些对象的序列化方式。 (此外,由于
$product
根本不受限制,因此该规则完全有可能会触发多次。)

当您仅使用工作记忆中的一种产品运行时,它“起作用”的原因是因为工作记忆中的一项产品恰好满足所有条件。只有当您开始扩展到多个项目时,才会清楚地发现该规则实际上并未按预期工作。

© www.soinside.com 2019 - 2024. All rights reserved.