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

89 阅读3分钟

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

规则引擎:可降低复杂业务逻辑组件复杂性、降低应用程序的维护和可扩展性成本的组件,嵌入在应用程序中,可以根据数据输入解释业务规则,并作出业务决策。

特点:规则简单容易配置。

优点:解决开发人员重复编码的问题,提高服务的可维护性,缩短开发路径,提高效率。

规则引擎组成部分:数据输入,规则执行,规则执行。

数据输入:支持接受使用预定义的语义编写的规则作为策略集,可以接受业务的数据作为执行过程中的参数。

规则理解:能够按照预定义正确理解业务规则所表达的语义。

规则执行:根据执行时的输入参数对策略集中的规则进行正确的解释。

应用场景:风控对抗,活动策略运营,数据分析和清洗。

编译过程:理解、执行、输入输出。

理解:词法分析、语法分析。

执行:抽象语法树。(抽象语法树唯一确定)

输入输出:参数注入、类型检查。

词法分析:把源代码字符串转换为词法单元。

有限自动机:状态数量有限的状态机,基于输入字符都能做一个确定的状态转换。

语法分析:在词法分析的基础上识别表达式的语法结构。

抽象语法树:用树来表示表达式的语法结构,每个节点是一个语法单元,节点可以有下级节点。

上下文无关语法:语言句子无需考虑上下文可以判断正确性,能用巴科斯范式表示。

产生式:一个表达式可以由另外已知类型的表达式或符号推导产生。

递归下降算法:自顶向下构造语法树。

类型检查:查看是否可能存在无法判断类型的节点以及是否能够造出合法的语法树。

类型综合:就是根据子表达式类型造出父表达式的类型。

编译运行时检查:在构造语法树阶段或在执行时输入参数阶段进行类型检查。

设计规则引擎目标:设计一个规则引擎,支持特定词法、运算符、数据类型、优先级,基于预定义编译运行。

词法:参数、布尔值、字符串、十进制整数、十进制浮点数、运算符、默认优先级。

词法分析

expr:logOr EOF;

logOr:logOr '||' logAnd|logAnd;

logAnd:logAnd'&&'logNot|logNot;

logNot:'!'logNot|cmp;

cmp:cmp'>'add|cmp'>='add|cmp'<'add|cmp'<='add|cmp'=='add|cmp'!='add|add;

add:add'+'mul|add'-'mmul|mul;

mul:mul'*'pri|mul'/'pri|mul'%'pri|pri;

pri:BooleanLiteral|IntegerLiteral|FloatLiteral|StringLiteral|Identifier|'('expr)';

优先级处理

type precedence struct{

validSymbols []Symbol

nextPrecedence *precedence

planner planner

}

语法树结构:一元运算符(左子树空),二元运算符(左右子树都有内容),括号(左子树空,有子树为括号内的抽象树)。

语法树执行:对抽象语法树进行后序遍历。

go编译期的优先级是在parseBinaryExpr中通过token的Precedence函数给出的int值判断优先级大小做优先级解析的,为了保证左结合,在递归调用时会对前一个优先级+1

启动DB:docker-compse up

运行项目:go run main.go

比较流行的规则引擎:derulers,govaluate(*)

万能解析器lex&yacc

实际项目中一般不会实时编译