这是我参与「第五届青训营 」笔记创作活动的第2天。
一、本堂课重点内容:
理解规则引擎的组成部分和应用场景,理解规则引擎的核心原理,学习编译原理的相关概念。自主设计一个规则引擎,并且实现一个WEB版的规则引擎。
二、详细知识点介绍:
(1)认识规则引擎
规则引擎是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据业务规则做出业务决策。
规则引擎解决了开发人员重复编码的问题,业务决策与服务本身解耦,提高服务的可维护性,缩短开发路径,提高效率。
规则引擎由三部分组成:数据输入、规则理解、规则执行。
规则引擎的应用场景包括:风控对抗,活动策略运营,数据分析和清洗。
(2)编译原理基本概念
词法分析就是把源代码字符串转换为词法单元的这个过程。 有限自动机就是一个状态机,它的状态数量是有限的。该状态机在任何一个状态,给一个输入,都会得到特定的状态转换。 语法分析就是在词法分析的基础上,识别表达式的语法结构的过程。 抽象语法树可以用来表示表达式的语法结构,每个节点是一个语法单元,每个节点还可以有下级节点。
(3)设计一个规则引擎
设计目标:设计一个规则引擎,支持特定的词法、运算符、数据类型和优先级。并且支持基于以上预定义语法的规则表达式的编译和执行。
先根据规则设计语法树,对抽象语法树进行后续遍历的执行,先执行左子树,得到左节点的值,再执行右子树,得到右节点的值,最后根据根节点的操作符执行得到根节点的值。
类型检查:在一个节点的左右子节点执行完成后,分别校验左右子节点的类型是否符合对应操作符的类型检查预设规则。
三、实践练习例子:
(1)巴克斯范式
<expr> ::= <expr> + <term>
| <expr> - <term>
| <term>
<term> ::= <term> * <factor>
| <term> / <factor>
| <factor>
<factor> ::= ( <expr> )
| Num
(2)规则引擎的实现(生成token)
package token
const NoPos = 0
// Token Represents a single parsed token.
type Token struct {
Kind Kind
Value interface{}
Position int
}
var keywords = map[string]Kind{
"true": BoolLiteral,
"false": BoolLiteral,
}
func LookupOperator(op string) Kind {
if kind, exist := operatorToKind[op]; exist {
return kind
}
return Illegal
}
// Lookup maps an identifier to its keyword token or Identifier (if not a keyword).
func Lookup(ident string) Kind {
if tok, isKeyword := keywords[ident]; isKeyword {
return tok
}
return Identifier
}
四、课后个人总结:
当我们在对复杂的业务进行开发时,程序本身逻辑代码和业务代码互相嵌套、错综复杂,同时维护成本高,可扩展性差。使用规则引擎可以将业务代码和逻辑代码进行解耦,实现快速、低成本的迭代更新。
设计正确的语法树是设计规则引擎的关键,所以应该牢固地掌握语法规则和此法规则以及优先级,才能设计出优秀的语法树。