这是我参与「第五届青训营 」伴学笔记创作活动的第 6 天
一、本章重要知识点
1、理解规则引擎的组成部分及应用场景
2、理解规则引擎的核心原理—编译原理的相关概念
3、设计并实现一个规则引擎—YoungEngine
4、结合知识,实现一个Web版规则引擎
二、详细知识介绍
1.认识规则引擎
规则引擎是一种嵌入在应用服务中的组件,可以将灵活多变的业务决策从服务代码中分离出来。通过使用预定义的语义模块来编写业务逻辑规则。在执行时接受数据输入、解释业务规则,并做出决策。规则引擎能大大提高系统的灵活性和扩展性。
- 解决开发人员重复编码的问题
- 业务决策和服务本身解耦,提高服务的可维护性
- 缩短开发路径,提高效率
组成部分
- 数据输入
- 规则理解
- 规则执行
应用场景
- 风控对抗
- 活动策略运营
- 数据分析和清洗
2.编译原理基本概念
介绍编译、词法分析、语法分析、抽象语法树等概念
词法分析
把源码字符串转换为词法单元(Token)的这个过程
语法分析
在词法分析的基础上识别出表达式的语法结构的过程
抽象语法树
表达式抽象语法结构的树状表示,对于一个表达式,抽象语法树一定是唯一确定的
类型检测
验证执行的结果是否为合适的数据类型。 在抽象语法树中,通常会验证某节点的子节点的数据类型是否合法
-
类型综合
根据子表达式的类型构造出父表达式的类型。
-
编译时检查&运行时检查
类型检查可以发生在表达式的编译阶段,即在构造语法树的阶段,也可以发生在执行时的阶段
3.设计一个规则引擎
设计目标:设计一个规则引擎,支持特定的词法、运算符、数据类型和优先级。并且支持基于以上预定义语法的规则表达式的编译和执行
4.规则引擎的实现
使用Hertz框架开发一个HTTP服务,服务使用mysql,支持表达式的增删查改和编译执行。
并实现以下接口
直接表达式执行:
请求参数为待执行的表达式和表达式中参数的值,并输出编译结果
POST api/engine/run- Request
{
"exp": "uid == 12345 && did > 0",
"params": {
"uid": 123456,
"did": 0
}
}
- Response
{
"code": 0,
"message": "success",
"data": { // 执行结果
"result": true
}
}
新增表达式:
新增一条表达式到DB中,并返回表达式在DB中的ID
需要检测表达式是否已经存在,如果已经存在,直接返回表达式的ID
需要检测表达式是否合法(编译是否通过) ,如果编译失败,返回错误码 20001和编译错误
POST api/engine/exp/new- Request
{
"exp": "uid == 12345 && did > 0",
}
- Response
{
"code": 0,
"message": "success",
"data": { // 表达式ID
"id": 1
}
}
// 编译失败时
{
"code": -1,
"message": "compile error: xxxxx", // 编译失败的信息
"data": { // 表达式ID
"id": 0
}
}
查询表达式
查询数据库中所有的表达式
GET api/engine/exp/list- Response
{
"code": 0,
"message": "success",
"data": [
{
"id": 1,
"exp": "uid > 0"
}
]
}
删除表达式
根据ID删除表达式,表达式不存在时返回错误码20002 , 和错误信息
删除成功返回被删除的表达式信息
DELETE api/engine/exp/:id- Response
// 删除成功时
{
"code": 0,
"message": "success",
"data": { // 表达式ID
"id": 1,
"exp": "uid > 0"
}
}
// 删除失败时
{
"code": -1,
"message": "exp id 1 not exist", //查询失败的信息
"data": {}
}
执行表达式
根据表达式的ID,查询出表达式内容,并编译执行。表达式不存在时返回错误码20002 , 和错误信息
POST api/engine/exp/run- Request
{
"exp_id": 1,
"parmas": {
"uid": 123456,
"did": 0
}
}
- Response
{
"code": 0,
"message": "success",
"data": { // 执行结果
"result": true
}
}
// 表达式不存在时
{
"code": -1,
"message": "exp id 1 not exist", //查询失败的信息
"data": {}
}