Skip to content

sreeb228/gisk

Repository files navigation

gisk风控策略引擎

gisk是独立的即插即用的轻量级决策引擎,支持json和yaml格式DSL。支持自定义运算符,自定义函数,自定义动作开放灵活的扩展适用更多的业务场景。

功能列表

  • 基础值
    • 变量
    • 输入值
    • 函数
  • 决策(规则)
  • 决策集
  • 决策流
  • 分流决策流
  • 赋值决策流
  • 评分卡
  • 支持数据类型:number, string, bool, array, map
  • 支持运算符号(支持自定义,覆盖默认运算符):eq, neq, gt, lt, gte, lte, in, notIn, like, notLike
  • 支持函数(支持自定义,函数支持嵌套):内置函数rand、sum
  • 支持决策动作(支持自定义):内置动作 赋值,访问url
  • 支持串行并行执行
  • DSL支持历史版本控制(提供获取接口,实现不同介质DSL储存。内置文件存储)
  • DSL支持json和yaml格式

快速开始

  • 环境准备

    go version go1.2+

  • 安装

go get -u -v gitee.com/sreeb/gisk
  • 基础使用
package main

import (
  "fmt"
  "gitee.com/sreeb/gisk"
)

func main() {
  elementType := gisk.RULES //规则
  rulesKey := "rules1" //规则唯一key
  version := "1" //规则版本

  g := gisk.New() //创建gisk实例
  g.SetDslFormat(gisk.JSON) //设置dsl格式
  err := g.Parse(elementType, rulesKey, version) //解析规则
  if err != nil {
    //错误处理
  }
  //获取所有被初始化的变量值
  variates := g.GetVariates()
  fmt.Println(variates)
}
  • 注册dsl获取接口

dsl接口获取器,可以根据提供的类型和key和版本获取dsl字符串。 dsl接口获取器需要实现gisk.DslGetterInterface接口,返回dsl字符串。

type DslGetterInterface interface {
	GetDsl(elementType ElementType, key string, version string) (string, error)
}

示例:

type fileDslGetter struct {
}

func (getter *fileDslGetter) GetDsl(elementType gisk.ElementType, key string, version string) (string, error) {
	path := "./dsl/" + elementType + "_" + key + "_" + version + ".json"
	bytes, err := os.ReadFile(path)
	if err != nil {
		return "", err
	}
	return  string(bytes), nil
}

func main() {
    //创建gisk实例
    g := gisk.New()
    //设置dsl获取器
    g.SetDslGetter(&fileDslGetter{})
    //...
}
  • 注册比较符

系统实现默认的比较符 eq, neq, gt, lt, gte, lte,in,notIn,like,notLike如果需要自定义比较符,可以调用RegisterOperation方法。自定义比较符优先级高于系统内置的比较符,可以注册和系统同名比较符实现复写。

package main

import (
	"errors"
	"gitee.com/sreeb/gisk"
	"regexp"
)

func main() {
	//自定义正则匹配比较符
	gisk.RegisterOperation("reg", func(left gisk.Value, operator gisk.Operator, right gisk.Value) (result bool, err error) {
		if left.ValueType != gisk.STRING || right.ValueType != gisk.STRING {
			err = errors.New("left and right must be string")
			return
		}
		// 正则表达式匹配
		reg := regexp.MustCompile(right.Value.(string))
		if reg.MatchString(left.Value.(string)) {
			result = true
		}
		return
	})

	g := gisk.New()
	//...
}
  • 注册函数

系统实现默认的函数 randsum,如果需要自定义函数,可以调用RegisterFunction方法。自定义函数优先级高于系统内置的函数,可以注册和系统同名函数实现复写。*

package main

import (
  "gitee.com/sreeb/gisk"
  "github.com/gogf/gf/v2/util/gconv"
)

func main() {
    //注册求和函数
    gisk.RegisterFunc("sum", func(parameters ...gisk.Value) (gisk.Value, error) {
      var v float64
      for _, parameter := range parameters {
        v += gconv.Float64(parameter.Value)
      }
      return gisk.Value{ValueType: gisk.NUMBER, Value: v}, nil
    })
	
    g := gisk.New()
    //...
}

DSL语法

基础值

基础值包含变量,输入值,函数。在dsl中用字符串表示。基础值

变量

表示法:variate_age_1

解释:variate表示为变量类型,age表示变量唯一key(key可以有下划线),1表示变量版本号。

变量DSL:

{
    "key": "age",
    "name": "年龄",
    "desc": "用户年龄",
    "version": "1",
    "value_type": "number",
    "default": 20,
    "is_input": false
}

变量结构体:

type Variate struct {
	Key       string      `json:"key" yaml:"key"`               //唯一标识
	Name      string      `json:"name" yaml:"name"`             //变量名称(前端页面使用,不涉及逻辑)
	Desc      string      `json:"desc" yaml:"desc"`             //描述(前端页面使用,不涉及逻辑)
	Version   string      `json:"version" yaml:"version"`       //版本
	ValueType ValueType   `json:"value_type" yaml:"value_type"` //值类型(number:转成float64, string, bool, array:以,分割转成array, map:json字符串转成map)
	Default   interface{} `json:"default" yaml:"default"`       //默认值
	IsInput   bool        `json:"is_input" yaml:"is_input"`     //是否要从输入值中匹配(true时会从输入值中匹配相同key的值进行赋值)
}

输入值

表示法:input_1_number

解释:input表示为输入值类型,1表示输入值,number表示输入值数据类型。

输入值没有DSL

函数

表示法:func_rand(input_1_number,func_sum(input_10_number,input_20_string))

解释:函数支持嵌套,函数参数只能是基础值。上述表达式解释为:rand(1,sum(10,20)),rand函数两个参数1和sum函数,sum函数两个参数10和20。 注册函数需要实现 type Func func(parameters ...Value) (Value, error)类型。

函数无DSL

规则(决策)

规则是基于多个比较条件通过逻辑运算符进行组合,最终得到一个布尔值。可以根据最终布尔值进行后续动作执行,赋值,访问url,发送消息,连接数据库等等操作。规则支持括号运算,支持串行并行执行

规则dsl

{
  "key": "rule1",   //唯一key
  "name": "用户筛选", //规则名称
  "desc": "用户筛选", //规则描述
  "version": "1",  //规则版本
  "parallel": true, //是否并行执行(并行执行会先并发获取比较条件组所有结果,再用规则表达式进行逻辑运算)
  "compares": {     
    "年龄小于40": {
      "left": "variate_年龄_1", //比较条件左边
      "operator": "lt", //比较条件运算符
      "right": "input_40_number" //比较条件右边
    },
    "性别女": {
      "left": "variate_性别_1",
      "operator": "eq",
      "right": "input_女_string"
    },
    "身高大于等于170": {
      "left": "variate_身高_1",
      "operator": "gte",
      "right": "input_170_number"
    }
  },  //比较条件组
  "expression": "年龄小于40 && (性别女 || 身高大于等于170)", //规则表达式
  "action_true": [
    {
      "action_type": "assignment",  //赋值操作
      "variate": "variate_命中结果_1", //赋值变量
      "value": "input_true_bool" //赋值值
    },
    {
      "action_type": "geturl", //访问url
      "url": "https://xxx.com" //url
    }
  ],  //true执行动作
  "action_false": [
    {
      "action_type": "assignment", //赋值操作
      "variate": "variate_命中结果_1", //赋值变量
      "value": "input_false_bool" //赋值值
    }
  ] //false执行动作
}

上述规则解释为:如果年龄小于40且性别为女或者身高大于等于170,则命中,否则未命中。命中时执行动作:变量命中结果赋值为true时,访问url。未命中时,赋值变量命中结果为false。

规则结构体:

type Rule struct {
	Key         string              `json:"key" yaml:"key"`                //唯一标识
	Name        string              `json:"name" yaml:"name"`              //名称
	Desc        string              `json:"desc" yaml:"desc"`              //描述
	Version     string              `json:"version" yaml:"version"`        //版本
	Parallel    bool                `json:"parallel" yaml:"parallel"`      //是否并发执行
	Compares    map[string]*Compare `json:"compares" yaml:"compares"`      //比较
	Expression  string              `json:"expression"  yaml:"expression"` //计算公式
	ActionTure  []RawMessage        `json:"action_true" yaml:"action_true"` //命中执行动作
	ActionFalse []RawMessage        `json:"action_false" yaml:"action_false"` //未命中执行动作
}
type Compare struct {
  Left     string   `json:"left" yaml:"left"`
  Operator Operator `json:"operator" yaml:"operator"` // 比较符号(可自定义注册)
  Right    string   `json:"right" yaml:"right"`
}

规则集(决策集)

规则集是多个规则的集合,支持串行并行执行和中断。并行模式下规则的先后顺序和中断不生效

规则集dsl:

{
  "key": "ruleset", //唯一key
  "name": "决策集1", //规则集名称
  "desc": "决策集1", //规则集描述
  "version": "1", //规则集版本
  "parallel": false, //是否并行执行(串行执行:顺序执行规则,中断后不执行后续规则。 并行执行:并发执行规则,不考虑顺序和中断)
  "rules": [ 
    {
      "rule_key": "rule1", //规则key
      "rule_version": "1", //规则版本
      "break_mode": "hit_break" //中断模式:hit_break命中中断,miss_break未命中中断。中断表示不执行后续的规则
    },
    {
      "rule_key": "rule2",
      "rule_version": "1",
      "break_mode": "miss_break"
    },
    {
      "rule_key": "rule3",
      "rule_version": "1",
      "break_mode": "miss_break"
    }
  ]//规则集规则
}

规则集结构体:

type Ruleset struct {
	Key      string         `json:"key" yaml:"key"`           //唯一标识
	Name     string         `json:"name" yaml:"name"`         //名称
	Desc     string         `json:"desc" yaml:"desc"`         //描述
	Version  string         `yaml:"version" json:"version"`   //版本
	Parallel bool           `json:"parallel" yaml:"parallel"` //是否并发执行
	Rules    []*rulesetRule `json:"rules" yaml:"rules"`       //规则集规则
}

type rulesetRule struct {
	RuleKey     string    `json:"rule_key" yaml:"rule_key"` //规则key
	RuleVersion string    `json:"rule_version" yaml:"rule_version"` //规则版本
	BreakMode   BreakMode `json:"break_mode" yaml:"break_mode"` //中断模式
}

决策流

决策流支持普通节点,分流节点和动作节点

普通节点

普通节点可以执行一个元素,元素可为规则,规则集等

type generalFlowNode struct {
	NodeKey    string       `json:"node_key" yaml:"node_key"`               //节点key
	NodeType   FlowNodeType `json:"node_type" yaml:"node_type"`             //节点类型
	EleType    ElementType  `json:"element_type" yaml:"element_type"`       //元素类型
	EleKey     string       `json:"element_key" yaml:"element_key"`         //元素key
	EleVersion string       `json:"element_version" yaml:"element_version"` //元素版本
	NextNode   string       `json:"next_node" yaml:"next_node"`             //下一个节点
}

分流节点

分流节点通过比较条件进行分流

type branchFlowNode struct {
	NodeKey  string       `json:"node_key" yaml:"node_key"`   //节点key
	NodeType FlowNodeType `json:"node_type" yaml:"node_type"` //节点类型
	Left     string       `json:"left" yaml:"left"`           //左侧
	Branches []struct {
		Operator Operator `json:"operator" yaml:"operator"`   // 比较符号
		Right    string   `json:"right" yaml:"right"`         // 右侧
		NextNode string   `json:"next_node" yaml:"next_node"` // 下一个节点
	} `json:"branches" yaml:"branches"` // 分支
}

动作节点

动作节点执行动作,公用规则动作,可以自定义

type actionFlowNode struct {
	NodeKey  string       `json:"node_key" yaml:"node_key"`   //节点key
	NodeType FlowNodeType `json:"node_type" yaml:"node_type"` //节点类型
	Actions  []RawMessage `json:"actions" yaml:"actions"`     //动作
	NextNode string       `json:"next_node" yaml:"next_node"` //下一个节点
}

复杂的决策流:

{
    "key": "flow1",
    "name": "普通决策流",
    "desc": "普通决策流",
    "version": "1",
    "nodes": [
        {
            "node_key": "start",
            "node_type": "general_flow_node",
            "element_type": "ruleset",
            "element_key": "ruleset",
            "element_version": "1",
            "next_node": "branch_node"
        },
        {
            "node_key": "branch_node",
            "node_type": "branch_flow_node",
            "left": "func_rand(input_1_number,input_100_number)",
            "branches": [
                {
                    "operator": "lte",
                    "right": "input_20_number",
                    "next_node": ""
                },
                {
                    "operator": "gt",
                    "right": "input_20_number",
                    "next_node": ""
                }
            ]
        },
        {
            "node_key": "branch_node",
            "node_type": "branch_flow_node",
            "left": "func_rand(input_1_number,input_100_number)",
            "branches": [
                {
                    "operator": "lte",
                    "right": "input_20_number",
                    "next_node": "action_flow_node1"
                },
                {
                    "operator": "gt",
                    "right": "input_20_number",
                    "next_node": "action_flow_node2"
                }
            ]
        },
        {
            "node_key": "action_flow_node1",
            "node_type": "action_flow_node",
            "next_node": "",
            "actions": [
                {
                    "action_type": "assignment",
                    "variate": "variate_决策流分流_1",
                    "value": "input_20%_string"
                }
            ]
        },
        {
            "node_key": "action_flow_node2",
            "node_type": "action_flow_node",
            "next_node": "",
            "actions": [
                {
                    "action_type": "assignment",
                    "variate": "variate_决策流分流_1",
                    "value": "input_80%_string"
                }
            ]
        }
    ]
}

解释为: 决策流图