Golang规则引擎 Gengine

image.png

规则引擎

职业做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即可

  1. DataContext:用于注入规则中需要使用的数据或者API。
  2. RuleBuilder:接收DataContext作为参数,并将用户传入的字符串构建出可执行的代码。
  3. Gengine:接收构建好的RuleBuilder,使用不同的模式执行规则。
  4. GenginePool:Gengine 的实例池,提供线程安全的API,以供用户在高QPS下使用。也推荐直接使用GenginePool。

调用流程如下

  1. 创建DataContext,并将规则使用的数据注入。
  2. 使用1中的DataContext作为参数实例化RuleBuilder并构建规则代码。
  3. 创建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

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容