yinweiwen
4 years ago
3 changed files with 280 additions and 0 deletions
After Width: | Height: | Size: 8.2 KiB |
After Width: | Height: | Size: 30 KiB |
@ -0,0 +1,280 @@ |
|||
# 规则引擎 |
|||
|
|||
实现业务和代码的分离,即把业务逻辑抽离,实现规则和系统的解耦。 数据输入-> 业务规则解释 -> 做出业务决策。 |
|||
|
|||
适用于复杂、多变的业务场景。 |
|||
|
|||
`原先一堆 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 边缘计算 |
|||
|
|||
低时延、大带宽、大连接、本地化 |
|||
|
Loading…
Reference in new issue