Springboot:可以根据用户输入通过前端更新 Drools 规则引擎文件 (.drl) 传入约束规则模板设计注意事项

如何解决Springboot:可以根据用户输入通过前端更新 Drools 规则引擎文件 (.drl) 传入约束规则模板设计注意事项

我遵循了 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;

基本上,其逻辑是针对所购商品的每种卡类型的折扣百分比建立规则。

因此向 http://localhost:8080/orders 发出如下的 post 请求

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

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

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

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

Folder structure of Drools Project

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

谢谢 SM

解决方法

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


传入约束

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

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

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

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

{
    "cardType": "HDFC","minimumPrice": 10000,"discount": 10
},{
    "cardType": "ICICI","minimumPrice": 15000,"discount": 8
},{
    "cardType": "DBS","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

(旁注:我清理了你的语法。你的原始规则中有很多不必要的分号和奇怪的空格。)

工作流程基本上如下:

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

规则模板

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

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

  1. 用户在 UI/前端创建约束,指定所需信息(卡类型、最低价格、折扣)。
  2. 用户的约束被发送到服务器。
  3. 服务器将请求重新格式化为表格形式(而不是 JSON 或任何原始格式)。
  4. 服务器使用数据表(第 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

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

Drools 文档非常好,所以我不会过多介绍细节,但您应该能够了解其要点。


设计注意事项

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

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

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

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?