Springboot:Can Drools 规则引擎文件 (.drl) 将根据用户输入通过前端进行更新

Springboot:Can Drools Rule Engine file (.drl) be updated through frontend based on user inputs

我遵循了有关 Drools 的教程并且也实现了相同的教程。我试图了解我可以通过前端更改 .drl 文件中的值的方法。下面是我使用的名为 order.drl.

的 Drools 文件
package KieRule;
import com.example.demo.Order;

rule "HDFC"

when
orderObject : Order(cardType=="HDFC" && price>10000);
then
orderObject.setDiscount(10);
end;

rule "ICICI"

when
orderObject : Order(cardType=="ICICI" && price>15000);
then
orderObject.setDiscount(8);
end;

rule "DBS"

when
orderObject : Order(cardType=="DBS" && price>15000);
then
orderObject.setDiscount(15);
end;

基本上逻辑是建立规则,计算购买商品的每种卡类型的折扣百分比。

所以一个 post 请求到 http://localhost:8080/orders

{
"name":"Mobile",
"cardType":"HDFC",
"price" : 11000
}

在折扣已确定的情况下给出如下输出

{
"name": "Mobile",
"cardType": "HDFC",
"discount": 10,
"price": 11000
}

我创建了 Spring 入门项目,下面是我的文件夹结构

我是否可以将当前的值硬编码在 .drl 文件中,例如从 JSP 或 Reactjs 前端捕获并更新“HDFC”和“价格>10000”?我希望应用程序的管理员用户在需要时更改规则。我见过在 .drl 中使用 $ 符号但无法完全掌握它们的示例。我们可以在 Java 中实现吗?

谢谢 SM

假设您要做的是保持基本结构不变并简单地改变约束,那么两个最简单的解决方案是使用规则模板或将约束本身传递给您的规则输入。


传入约束

这是最简单的解决方案。基本上这个想法是,您的约束值首先是 class 公民,以及您的规则输入。

查看您提供的规则,构成约束条件的两个数据是卡类型和最低价格。这些都有一个结果。我们可以简单地建模:

class OrderConstraints {
  private String cardType;
  private Integer minimumPrice;
  private Integer discount;
  // Getters 
}

您可以将这些传递到 objects 中的规则中,如下所示:

{
    "cardType": "HDFC",
    "minimumPrice": 10000,
    "discount": 10
},
{
    "cardType": "ICICI",
    "minimumPrice": 15000,
    "discount": 8
},
{
    "cardType": "DBS",
    "minimumPrice": 15000,
    "discount": 15
}

现在您的所有用例都可以在一条规则中处理:

rule "Apply order discount"
when
  OrderConstraints( $cardType: cardType, $minimumPrice: minimumPrice, $discount: discount)
  $order: Order( cardType == $cardType, price > $minimumPrice )
then
  $order.setDiscount($discount);
end

(旁注:我清理了你的语法。你的原始规则中有很多不必要的 semi-colons 和位置奇怪的白色 space。)

工作流程基本上如下:

  1. 用户在UI/前端创建约束,指定所需信息(卡类型、最低价格、折扣)。
  2. 用户的约束被发送到服务器并保存到你的持久层(数据库等)
  3. 进行新查询时,将从持久层中读出约束并与规则输入一起传递到规则中。

规则模板

第二种解决方案是使用 rule templates(link 用于 Drools 文档。)基本思想是您提供 table 数据和 DRL 模板, Drools 框架会将数据制作成模板并为您生成 DRL。当您有非常重复的规则(例如您的规则)时,这很有用 - 在其他情况下,您基本上是在应用具有各种不同约束的相同规则。

与其他场景类似,您的工作流程如下:

  1. 用户在UI/前端创建约束,指定所需信息(卡类型、最低价格、折扣。)
  2. 用户的约束被发送到服务器。
  3. 服务器将请求重新格式化为表格形式(而不是 JSON 或任何原始格式)。
  4. 服务器使用数据 table(第 3 步)和模板生成规则。

您的模板可能看起来像这样,假设列标记为“cardType”、“minPrice”和“discount”):

template header
cardType
minPrice
discount

package com.example.template;
import com.example.Order;

template "orderdiscounts"

rule "Apply order discount for @{cardType}"
when
  $order: Order( cardType == "@{cardType}",
                 price > @{minPrice} )
then
  $order.setDiscount(@{discount});
end

end template

格式很漂亮straight-forward。首先是 header,我们按顺序定义列。第一个空行表示 header 的结尾。接下来是包声明和导入,因为它们对于文件来说是静态的。然后是模板。使用 @{ column name } 模式对列值进行插值;请注意,您需要将其用引号括起来作为字符串。

Drools 文档非常好,所以我不会过分详细,但您应该能够了解其中的要点。


设计注意事项

既然你在谈论 React front-end,我假设你正在构建一个现代 Web 应用程序。实施解决方案时,请牢记持久性和数据完整性问题。

如果您将后端应用程序扩展为负载平衡前端的多个实例,您需要确保将用户应用的约束传播到所有实例。此外,如果您应用 更改 ,它们需要实时变为 visible/propagate——您不能让一个节点或集群使用陈旧的约束或值。

虽然从表面上看,规则模板 似乎 是解决此问题的完美 built-in 解决方案,但事实并非如此。规则模板是围绕存储在平面文件中的数据 table 设计的——根据定义,这不是一种非常现代或分布式的方法。如果您的用户更新了节点 A 上的约束,并且更新了节点 A 上的数据 table,您需要确保相同的数据 table file 传播到所有其他节点。此外,如果您启动一个新节点,您将需要设计一种机制,通过该机制它能够获取“当前”数据 table。然后,如果发生灾难性事件,您失去了 所有 个节点怎么办?

“将约束传递到内存中”的解决方案是老式的,但它具有传统持久层支持的优势。如果您使用某种分布式数据源,这可能是您的真实来源。只要您的所有应用程序实例在提交规则时(或使用某些逻辑缓存层)从数据库中查询您的约束,您就无需担心您的实例不同步。如果您丢失了 所有 节点,您的约束将在您的数据源中,以便在您的新应用程序实例启动并需要使用它时使用。缺点当然,您确实需要执行这些数据库查询或缓存读取,这可能会增加延迟。然后您需要将此数据传递到规则中,这将增加您的内存使用量并可能 CPU(具体多少取决于您传递的数据量)。

我已 link 将您引导至 Drools documentation,我强烈建议您阅读它。它很长,但非常值得。这可能是我的 most-accessed 书签,尽管我什至不再每天流口水了。那里记录了其他可用的解决方案——例如,您的用户请求可以生成规则,将它们打包在 kjar 中,并将它们发布到 Maven 存储库,然后您的所有实例都可以下载和使用——但是 正确 适合您用例的解决方案是您需要根据您的要求自行决定的。