You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
281 lines
7.0 KiB
281 lines
7.0 KiB
4 years ago
|
# 规则引擎
|
||
|
|
||
|
实现业务和代码的分离,即把业务逻辑抽离,实现规则和系统的解耦。 数据输入-> 业务规则解释 -> 做出业务决策。
|
||
|
|
||
|
适用于复杂、多变的业务场景。
|
||
|
|
||
|
`原先一堆 case 的逻辑,改由规则引擎控制,对频繁修改的业务规则提高修改效率`
|
||
|
|
||
|
### [Drools](https://github.com/kiegroup/drools)
|
||
|
|
||
|
Drools是一个基于Java的**开源**规则引擎。
|
||
|
|
||
|
Drools 是用 Java 语言编写的开放源码规则引擎,使用 Rete 算法对所编写的规则求值。Drools 允许使用声明方式表达业务逻辑。可以使用非 XML 的本地语言编写规则,从而便于学习和理解。并且,还可以将 Java 代码直接嵌入到规则文件中,这令 Drools 的学习更加吸引人。
|
||
|
|
||
|
`ksession-rules.drl`
|
||
|
|
||
|
```yaml
|
||
|
package com.rules
|
||
|
import model.ProtocolType
|
||
|
dialect "java"
|
||
|
|
||
|
rule "jk16"
|
||
|
when
|
||
|
$protocol : ProtocolType(data matches "^1A12.*$" )
|
||
|
then
|
||
|
$protocol.setType("xx燃气表协议");
|
||
|
System.out.println("触发规则1:"+$protocol.getData());
|
||
|
end
|
||
|
|
||
|
rule "jkstd"
|
||
|
no-loop true
|
||
|
lock-on-active true
|
||
|
salience 1
|
||
|
when
|
||
|
$protocol : ProtocolType(data matches "18.*",length == 10)
|
||
|
then
|
||
|
$protocol.setType("xx水表标准协议");
|
||
|
System.out.println("触发规则2:"+$protocol.getData());
|
||
|
end
|
||
|
```
|
||
|
|
||
|
`main.java`
|
||
|
|
||
|
```java
|
||
|
public static void main(String[] args) {
|
||
|
KieServices ks = KieServices.Factory.get();
|
||
|
KieContainer kContainer = ks.getKieClasspathContainer();
|
||
|
KieSession kSession = kContainer.newKieSession("ksession-rules");
|
||
|
|
||
|
ProtocolType pt = new ProtocolType();
|
||
|
pt.setData("1A122312345");
|
||
|
|
||
|
kSession.insert(pt);
|
||
|
kSession.fireAllRules();
|
||
|
kSession.dispose();
|
||
|
System.out.println(pt);
|
||
|
}
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
### Ilog JRules
|
||
|
|
||
|
Ilog Jrules是完整的业务规则管理系统(BRMS),它提供了对整个企业业务规则进行建模、编写、测试、部署和维护所必需的所有工具。
|
||
|
|
||
|
|
||
|
|
||
|
### Easy Rules
|
||
|
|
||
|
[Github](https://github.com/EasyRules/easyrules.git)
|
||
|
|
||
|
+ 轻量级 简单易用的API
|
||
|
+ 基于POJO 注解开发模型
|
||
|
+ 通过高效的抽象来定义业务规则并轻松应用它们
|
||
|
+ 支持创建复合规则
|
||
|
+ 支持通过表达式语句创建规则(MVEL,SpEL,JEXL等)
|
||
|
|
||
|
scala改写官方start:
|
||
|
|
||
|
```scala
|
||
|
object main {
|
||
|
|
||
|
def main(args: Array[String]): Unit = {
|
||
|
println("hello rule engine")
|
||
|
|
||
|
val rule = new MyRule()
|
||
|
rule.bRain = true
|
||
|
val ruleEngine = RulesEngineBuilder.aNewRulesEngine().build()
|
||
|
ruleEngine.registerRule(rule)
|
||
|
|
||
|
ruleEngine.fireRules()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Rule(name = "my rule", description = "test rule")
|
||
|
class MyRule() {
|
||
|
var bRain = false
|
||
|
|
||
|
@Condition
|
||
|
def itRains(): Boolean = {
|
||
|
bRain
|
||
|
}
|
||
|
|
||
|
@Action
|
||
|
def doSomething(): Unit = {
|
||
|
println("it rains")
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
在最新版本中才支持表达式语句创建
|
||
|
|
||
|
下载git代码并mvn install后本地库使用
|
||
|
|
||
|
```xml
|
||
|
<dependencies>
|
||
|
<dependency>
|
||
|
<groupId>org.jeasy</groupId>
|
||
|
<artifactId>easy-rules-core</artifactId>
|
||
|
<version>4.1.1-SNAPSHOT</version>
|
||
|
</dependency>
|
||
|
|
||
|
<dependency>
|
||
|
<groupId>org.jeasy</groupId>
|
||
|
<artifactId>easy-rules-mvel</artifactId>
|
||
|
<version>4.1.1-SNAPSHOT</version>
|
||
|
</dependency>
|
||
|
</dependencies>
|
||
|
```
|
||
|
|
||
|
`weather-rule.yml`
|
||
|
|
||
|
```yml
|
||
|
name: "weather rule"
|
||
|
description: "if it rains then take an umbrella"
|
||
|
condition: "rain == true"
|
||
|
actions:
|
||
|
- "System.out.println(\"It rains, take an umbrella!\");"
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
```scala
|
||
|
def main(args: Array[String]): Unit = {
|
||
|
val ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader)
|
||
|
val source = Source.fromInputStream(getClass.getResourceAsStream("/weather-rule.yml"))
|
||
|
val weatherRule = ruleFactory.createRule(source.bufferedReader())
|
||
|
source.close()
|
||
|
|
||
|
val facts = new Facts()
|
||
|
facts.put("rain", true)
|
||
|
|
||
|
val rules = new Rules()
|
||
|
rules.register(weatherRule)
|
||
|
|
||
|
val rulesEngine = new DefaultRulesEngine()
|
||
|
rulesEngine.fire(rules, facts)
|
||
|
}
|
||
|
```
|
||
|
|
||
|
构想的一个应用场景:
|
||
|
|
||
|
[代码](https://github.com/yinweiwen/easy-rules-scala-example)
|
||
|
|
||
|
根据测点属性或数据,来判断需要执行哪些操作:
|
||
|
|
||
|
```scala
|
||
|
def handle(data: StationData): Unit = {
|
||
|
val facts = new Facts()
|
||
|
facts.put("sensor", BoxData(data))
|
||
|
|
||
|
engine.fire(rules, facts)
|
||
|
}
|
||
|
|
||
|
// 需要把待处理数据进行封装
|
||
|
// like a POJO
|
||
|
case class BoxData(var data: StationData) {
|
||
|
def validate(): Unit = {
|
||
|
data = Validator.handle(data)
|
||
|
}
|
||
|
|
||
|
def analyze(): Unit = {
|
||
|
data = Analyzer.handle(data)
|
||
|
}
|
||
|
|
||
|
def storage(): Unit = {
|
||
|
Storage.handle(data)
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
构造规则:例如温度超过30时执行指定过滤和分析操作。
|
||
|
```yaml
|
||
|
name: "sensor rule"
|
||
|
description: "sensor handle rule"
|
||
|
condition: "sensor.data.v(\"temperature\")>30"
|
||
|
condition: "true"
|
||
|
actions:
|
||
|
- "System.out.println(sensor);"
|
||
|
- "sensor.validate();"
|
||
|
- "sensor.analyze();"
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
### [Node-Red](https://nodered.org/)
|
||
|
|
||
|
__Low-code programming for event-driven applications__
|
||
|
|
||
|
[**概念**](https://nodered.org/docs/user-guide/)
|
||
|
|
||
|
`Node` 节点 、`Flow` 流程 、Workspace 工作区间、Subflow 子流程、Sidebar 侧边栏、Palette调色板、Wire连接线
|
||
|
|
||
|
**安装**
|
||
|
|
||
|
```shell
|
||
|
#windows
|
||
|
npm install --global --production windows-build-tools
|
||
|
|
||
|
npm install -g --unsafe-perm node-red
|
||
|
|
||
|
http://localhost:1880/
|
||
|
```
|
||
|
|
||
|
%user%\\.node-red\settings.js
|
||
|
|
||
|
```js
|
||
|
adminAuth: {
|
||
|
type: "credentials",
|
||
|
users: [{
|
||
|
username: "admin",
|
||
|
password: "$2a$10$DFRjJdlRX/wEw3C.qyEdW.UyOGlPkGv8lbyZnuh6XX/4RVSQS.ZgO", // bcrypt随机带盐加密
|
||
|
permissions: "*" // read write
|
||
|
}],
|
||
|
sessionExpiryTime: 86400,
|
||
|
},
|
||
|
```
|
||
|
|
||
|
First Flow: Inject->Function->Debug
|
||
|
|
||
|
![image-20210616140457382](imgs/规则引擎/image-20210616140457382.png)
|
||
|
|
||
|
Second Flow:
|
||
|
|
||
|
安心云数据处理
|
||
|
|
||
|
|
||
|
|
||
|
安心云的上报流程
|
||
|
|
||
|
![image-20210616160110681](imgs/规则引擎/image-20210616160110681.png)
|
||
|
|
||
|
总结**一般**的推送流程:
|
||
|
|
||
|
Kafka消费ET处理后的测点数据 --> 过滤结构物、监测因素 --> 构造发送消息结构体 --> 网络请求(http/tcp...)
|
||
|
|
||
|
> 通过这种方式可以实现简单的数据上报功能,
|
||
|
>
|
||
|
> 1. 可视化配置,灵活高效
|
||
|
> 2. 可开放作为平台功能的一部分,让有一定开发能力的客户直接使用。
|
||
|
> 3. 可以匹配大多数接入方式场景
|
||
|
>
|
||
|
> 主要存在的缺陷:
|
||
|
>
|
||
|
> 1. 每个项目独立启动一个Kafka-consumer消费者,性能浪费
|
||
|
> 2. 状态数据没法处理(计算变化量等情况)
|
||
|
> 3. “函数”节点中纯js代码不支持Redis/Db等操作
|
||
|
> 4. 自带的HTTP请求node较简单,不支持参数头设置。
|
||
|
> 5. 请求返回校验和日志记录问题
|
||
|
> 6. 不支持的场景:数据库直接写入、webservice接入等
|
||
|
> 7. 自定义node仅支持Node.js语言
|
||
|
|
||
|
综上:只能实现逻辑较为简单的一些上报,可作为平台扩展功能一部分。大多数针对项目的上报,存在后处理逻辑,目前只能通过硬编码的方式实现。
|
||
|
|
||
|
|
||
|
|
||
|
EI 边缘计算
|
||
|
|
||
|
低时延、大带宽、大连接、本地化
|
||
|
|