规则引擎设计与实现|青训营笔记

111 阅读2分钟

这是我参与「第五届青训营」笔记创作活动的第5天。

本节课程主要介绍了规则引擎以及编译原理相关的知识。

1.规则引擎

规则引擎将业务决策和服务代码分离开来,如运营同学配置活动或者优惠时,可以通过规则引擎自行配置,不用每次涉及到修改业务代码,实现解耦。另外,活动等配置会随着时间越发复杂,规则越来越多,使用规则引擎可以减少开发的压力,减少代码改动以减少bug。规则引擎灵活高效,已经在业界广泛使用。

应用场景主要有风控对抗、活动策略运营、数据分析和清洗。

规则引擎的工作原理与编译原理相关知识联系紧密。规则引擎工作时,需要预先定义一套规则,输入规则引擎;规则引擎进行语法语义分析,理解表达式;之后运行时输入参数,按照预定义的表达式计算返回结果。

2.编译原理

  • 词法分析:把源代码字符串转化为词法单元
  • 语法分析:在词法分析的基础上,识别表达式的语法结构,构造抽象语法树
  • 抽象语法树:表达式的语法结构用树表示,每个节点是语法单元

image.png

3.课后作业

使用Hertz框架开发一个HTTP服务,支持新增规则、查询规则、删除规则、执行表达式

路由:

通过GET、POST等方法注册路由到实际执行的函数

g.POST("/engine/exp/new", handler.HandleAddExpression)

新增表达式:

先根据文档定义RuleAddRequest结构体,读取参数。之后使用Compiler方法编译,若不通过则报错返回;若通过,尝试插入数据库。

func HandleAddExpression(ctx context.Context, c *app.RequestContext) {
   var req RuleAddRequest
   c.Bind(&req)
   //编译检查
   _, err := Compiler(req.Exp)
   if err != nil {
      BindResp(c, CompileErrCode, err.Error(), map[string]interface{}{"id": 0})
      return
   }
   //插入DB
   exp, err := dal.AddExpression(req.Exp)
   if err != nil {
      BindResp(c, 20002, "AddExpression failed", exp)
      return
   }
   BindResp(c, SuccessCode, SuccessMsg, exp)
}

运行结果

image.png

删除:

实现删除接口时,使用了DELETE方法,取值id的时尝试了几种方法,最后发现使用Param方法可以取到

g.DELETE("/engine/exp/:id", handler.HandleDeleteExpression)
func HandleDeleteExpression(ctx context.Context, c *app.RequestContext) {
   id := c.Param("id")
   ...
}

运行结果

image.png

image.png

执行表达式:

先根据ID查出规则,之后读取参数,执行

读取规则

exp, e := dal.GetExpressionByID(uint(req.ExpId)) 

编译,得到语法树

evaluatedExp, err := Compiler(exp.Exp) 

代入参数,计算

err = evaluatedExp.Eval(params)

取值

resp, _ := evaluatedExp.GetVal()

运行结果

image.png 其余接口略