我在我的用例中使用 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();
任何人都可以帮助我理解如何同时激发所有规则和所有事实,以加快性能并获得正确的结果。
你的规则不是做你认为它会做的事。
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
根本不受限制,因此该规则完全有可能会触发多次。)
当您仅使用工作记忆中的一种产品运行时,它“起作用”的原因是因为工作记忆中的一项产品恰好满足所有条件。只有当您开始扩展到多个项目时,才会清楚地发现该规则实际上并未按预期工作。