规则引擎
职业做Java开发电商行业的,对Drools库肯定不陌生,一些商品的价格计算规则、优惠券等模块大量的重复性低效代码就是由这个库抽离出来,在后台实时配置的。
用一段代码示例来解释一下规则引擎是干嘛的
// price 商品价格
// vipLevel vip等级
func ProducePrice(price float64, vipLevel int) float64 {
discount := 1.0
if vipLevel >= 1 && vipLevel <= 5 {
discount = 0.9
}
if vipLevel >= 6 && vipLevel <= 8 {
discount = 0.8
}
if vipLevel >= 9 && vipLevel <= 12 {
discount = 0.7
}
return price * discount
}
一件商品的打折幅度,随着vip等级而变化,如果需要修改打折规则,即便把等级数字提取到变量中,但这个if语句规则还是改变不了
这类固定代码,抽离到模板中,控制、逻辑运算、判断语句,包括一些常量值,能够在另外一处进行修改控制,然后代码实时生效
另外还有种业务场景用的比较多,风控评估,如一个人的数十种信用维度按照固定逻辑取值,计算出其信用借贷分值,这里面的每一条信用维度规则修改都需要进行代码的编写发布
Gengine 一个伪代码演示
gengine是一款基于golang和AST(抽象语法树)开发的规则引擎
这个AST库很强大,经常看到go/ast
go/parser
go/token
这三个标准库搭配使用,读取文件的go代码,生成go代码
一个实际编码案例
type User struct {
Name string
Age int64
Male bool
}
func (u *User) GetNum(i int64) int64 {
return i
}
func (u *User) Print(s string) {
fmt.Println(s)
}
func (u *User) Say() {
fmt.Println("hello world")
}
我们使用 Gengine 框架,自定义一个规则
const rule1 = `
rule "name test" "i can" salience 0
begin
if 7 == User.GetNum(7) {
User.Age = User.GetNum(89767) + 10000000
User.Print("6666")
} else {
User.Name = "yyyy"
}
end
`
从上面的规则内容可看出,Gengine引擎实际上是将rule规则,最终转化成了go代码去执行,通过读取外部的rule规则,能够让其想解释语言一样实时执行(这里面涉及代码动态加载技术了,例如标准库的plugin)
规则说明
const rule = `
rule "rulename" "rule-description" salience 10
begin
//规则体
end`
● rulename:规则名,必须唯一。多个同名的规则编译后会只剩下一个。
● rule-description:规则描述,非必须。
● salience:关键字,后跟数字表示优先级,数字越大优先级越高。
● begin 和 end 包裹的就是规则体,规则的具体逻辑在这里编写。
规则体支持基本的数据类型,与go语言的基本类型一致。对于运算,规则体支持基本的算术四则运算,逻辑运算,比较运算。语法基本和go一样。[nil 除外]
实际代码应用
Gengine实现了高度封装,使用时只需要关心几个重点API即可
- DataContext:用于注入规则中需要使用的数据或者API。
- RuleBuilder:接收DataContext作为参数,并将用户传入的字符串构建出可执行的代码。
- Gengine:接收构建好的RuleBuilder,使用不同的模式执行规则。
- GenginePool:Gengine 的实例池,提供线程安全的API,以供用户在高QPS下使用。也推荐直接使用GenginePool。
调用流程如下
- 创建DataContext,并将规则使用的数据注入。
- 使用1中的DataContext作为参数实例化RuleBuilder并构建规则代码。
- 创建Gengine,按照模式执行2构建的规则代码。
需要注意的是,如果你的请求量很大且用于生产,需要关心内存,那么你需要进一步了解Gengine的几种执行模式,详情见官方文档,里面还有很多的语法糖操作规则
文档地址 https://github.com/bilibili/gengine/wiki
这个代码仓库演示了真实使用 Gengine 应用场景 https://github.com/wodouliyoutang/Gengine-app
扩展
Gengine 目前已停止维护,再推荐两个功能更加强大的类库包
github.com/yuin/gopher-lua
github.com/expr-lang/expr