1. 引言

什么是规则引擎

一个业务规则包含一组条件和在此条件下执行的操作,它们表示业务规则应用程序的一段业务逻辑。业务规则通常应该由业务分析人员和策略管理者开发和修改,但有些复杂的业务规则也可以由技术人员使用面向对象的技术语言或脚本来定制。业务规则的理论基础是:设置一个或多个条件,当满足这些条件时会触发一个或多个操作。

规则引擎(rule engine)是指将复杂的业务逻辑抽象成规则,然后使用特定的算法(比如Rete)对规则进行求值等操作。简单点说,规则引擎就是实现复杂业务逻辑的框架。

为什么要用规则引擎

在维护和更新项目的业务逻辑代码时,大家深有体会:

  • 因编码风格的问题,不同人有不同的代码实现,而造成代码理解的困难;
  • 每一次业务逻辑的更改会导致项目的重编译;
  • 为了能实时响应更改,而不得不做服务重启的无缝衔接

从上面的需求出发,规则引擎应满足如下特点:

  • 脚本化,允许用类Python的脚本语言或DSL来描述规则;
  • 动态化,实时动态地加载规则脚本,规则的修改能实时地反馈于服务系统;
  • 快速的执行速度。

2. 实现

已有的开源方案

Drools应该是Java界名头最响、功能最丰富、社区最活跃的开源规则引擎了,目前的版本号为6.5.0.Final。淘宝也开源了自己的一套规则引擎QLExpress,但是似乎在2011年后项目没有再维护了。相较于QLExpress,Drools设计一套类DSL的脚本语言,用起来非常爽。但是在我看来,对于特定场景(比如用户画像),Drools显得过于重量级了,而QLExpress设计的API过于Java化了。

Scala方案

为了做到脚本化与动态化,Scala化的规则引擎将会把规则作为Scala Script独立出来,采用动态编译来加载。第三方Scala库hammurabiscalascriptengine完美地契合了需求。其中,hammurabi是规则引擎的具体实现,scalascriptengine用于对scala文件做动态编译。虽然hammurabi没有wiki,但是DZone上有一篇介绍使用的文章。scalascriptengine的版本号"com.googlecode.scalascriptengine" % "scalascriptengine_2.11" % "1.3.10"

ScalaScriptEngine的API为java.io.File;为了与Spark做集成,我们不得不做接口封装——从HDFS路径得到local File对象。基本思路便是把HDFS目录拷贝到本地的目标路径,然后基于本地路径new File对象:

import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.fs.{FileSystem, Path}
import java.io.File implicit def path2File(hdfsPath: String): File = {
val fs = FileSystem.get(new Configuration)
val dstDir = System.getProperty("java.io.tmpdir") + "/scala-tmp"
val dstPath = new Path(dstDir)
fs.deleteOnExit(dstPath)
fs.copyToLocalFile(new Path(hdfsPath), dstPath)
new File(dstDir)
}

由HDFS路径(作为Scala Script的package根目录)导入规则脚本生成规则集合对象:

import com.googlecode.scalascriptengine.ScalaScriptEngine

def loadRules[T](sourceDir: String, className: String): T = {
val sse = ScalaScriptEngine.onChangeRefresh(sourceDir)
// delete all compiled classes (i.e. from previous runs)
sse.deleteAllClassesInOutputDirectory()
sse.refresh
sse.newInstance[T](className)
}

为了使得规则集合具有类型,而特地定义了RulesTrait:

// RulesTrait.scala
package rule.util import hammurabi.Rule trait RulesTrait {
val rules: Set[Rule]
} // User.scala
case class User(uid: String, apps: Array[String]) {
val tags = mutable.Set.empty[String] override def toString: String = "uid: %s, apps: %s, tags: %s".format(uid, apps.mkString, tags)
}

Scala Script所描述的业务规则集合(用于给用户打标签)如下:

import hammurabi.Rule
import _root_.rule.util.{RulesTrait, User}
import hammurabi.Rule._ class TagRules extends RulesTrait { override val rules: Set[Rule] = Set(
rule("add 母婴 Tag") let {
val u = any(kindOf[User])
when {
u.apps.mkString.matches(".*(孕|宝宝|育儿).*")
} then {
u.tags += "母婴"
}
},
rule("add 大学生 Tag") let {
val u = any(kindOf[User])
when {
u.apps.mkString.matches(".*(四级|六级|大学).*")
} then {
u.tags += "大学生"
}
}
)
} object TagRules {
}

在Spark程序中集成规则引擎:

import rule.util.{RulesTrait, User}

val rulesObj = loadRules[RulesTrait](params.scriptPath, "TagRules")
val ruleEngine = RuleEngine(rulesObj.rules)
val engineBC = sc.broadcast(ruleEngine) val log: RDD[User]
val tagRdd = log.mapPartitions { iter =>
val seq = iter.toSeq
val workingMemory = WorkingMemory(seq)
engineBC.value execOn workingMemory
seq.filter(_.tags.nonEmpty).toIterator
}

3. 参考资料

[1] 李国乐, Java规则引擎与其API(JSR-94).

[2] Ricardo Olivieri, 使用 Drools 规则引擎实现业务逻辑.

Scala化规则引擎的更多相关文章

  1. Flink/CEP/规则引擎/风控

    基于 Apache Flink 和规则引擎的实时风控解决方案 ​ 对一个互联网产品来说,典型的风控场景包括:注册风控.登陆风控.交易风控.活动风控等,而风控的最佳效果是防患于未然,所以事前事中和事后三 ...

  2. Asp.net 面向接口可扩展框架之业务规则引擎扩展组件

    随着面向接口可扩展框架的继续开发,有些功能开发出现了"瓶颈",有太多的东西要写死才好做.但写死的代码扩展性是非常的不好,迷茫中寻找出入... 进而想到我以前开发的好几个项目,都已有 ...

  3. 小明历险记:规则引擎drools教程一

    小明是一家互联网公司的软件工程师,他们公司为了吸引新用户经常会搞活动,小明常常为了做活动加班加点很烦躁,这不今天呀又来了一个活动需求,我们大家一起帮他看看. 小明的烦恼 活动规则是根据用户购买订单的金 ...

  4. 使用CKRule规则引擎处理多变业务

    1, 多变业务 开发系统时,有没有试过下面的情况,如果你试过,那可以考虑一下使用规则引擎了. 序号 问题 举例 1 业务规则来自于一个或多个表格 商店的会员积分表,停车场的计费标准,快递费的计算表,客 ...

  5. 【java规则引擎】之规则引擎解释

    转载:http://www.open-open.com/lib/view/open1417528754230.html 现实生活中,规则无处不在.法律.法规和各种制度均是:对于企业级应用来说,在IT技 ...

  6. Java规则引擎drools:drt动态生成规则并附上具体项目逻辑

    一 整合 由于本人的码云太多太乱了,于是决定一个一个的整合到一个springboot项目里面. 附上自己的项目地址https://github.com/247292980/spring-boot 以整 ...

  7. .NET RulesEngine(规则引擎)

    一次偶然的机会,让我拿出RulesEngine去完成一个业务,对于业务来说主要是完成一个可伸缩性(不确定的类型,以及不确定的条件,条件的变动可能是持续增加修改的)的业务判断.比如说完成一个成就系统,管 ...

  8. 规则引擎深度对比,LiteFlow vs Drools!

    前言 Drools是一款老牌的java规则引擎框架,早在十几年前,我刚工作的时候,曾在一家第三方支付企业工作.在核心的支付路由层面我记得就是用Drools来做的. 难能可贵的是,Drools这个项目在 ...

  9. Atitit.工作流 与 规则引擎

    Atitit.工作流 与 规则引擎 1.1. 应用来说,通常分为三部分:界面.业务逻辑和存储1 1.2. 自定义操作系列1 1.3. 自定义按钮系列2 1.1. 应用来说,通常分为三部分:界面.业务逻 ...

随机推荐

  1. TSQL Identity 用法全解

    Identity是标识值,在SQL Server中,有ID列,ID属性,ID值,ID列的值等术语. Identity属性是指在创建Table时,为列指定的Identity属性,其语法是:column_ ...

  2. 使用CSS3实现一个3D相册

    CSS3系列我已经写过两篇文章,感兴趣的同学可以先看一下CSS3初体验之奇技淫巧,CSS3 3D立方体效果-transform也不过如此 第一篇主要列出了一些常用或经典的CSS3技巧和方法:第二篇是一 ...

  3. 【置顶】CoreCLR系列随笔

    CoreCLR配置系列 在Windows上编译和调试CoreCLR GC探索系列 C++随笔:.NET CoreCLR之GC探索(1) C++随笔:.NET CoreCLR之GC探索(2) C++随笔 ...

  4. python 数据类型 --- 集合

    1. 注意列表和集合的区别 set 列表表现形式: list_1 = [1,3,4];  集合表现形式:set_1= set() list_1 = [1,2,3,4,23,4,2] print(lis ...

  5. JAVA FreeMarker工具类

    FreeMarkerUtil.java package pers.kangxu.datautils.utils; import java.io.File; import java.io.StringW ...

  6. 嵌入式&iOS:回调函数(C)与block(OC)传 参/函数 对比

    C的回调函数: callBack.h 1).声明一个doSomeThingCount函数,参数为一个(无返回值,1个int参数的)函数. void DSTCount(void(*CallBack)(i ...

  7. ORA-00821: Specified value of sga_target 3072M is too small, needs to be at least 12896M

    在测试PlateSpine克隆的数据库服务器时,由于资源有限,克隆过来的数据库服务器只给了9G的内存,结果在测试时,老是会出现OOMkiller导致宕机,即out of memory killer,是 ...

  8. GCC学习(1)之MinGW使用

    GCC学习(1)之MinGW使用 因为后续打算分享一些有关GCC的使用心得的文章,就把此篇当作一个小预热,依此来了解下使用GNU工具链(gcc.gdb.make等)在脱离IDE的情况下如何开发以及涉及 ...

  9. MongoDB基础

    1.概念及特点 说明:由于部分语句中$ 符号无法正常显示,使用¥代表 概念 MongoDB是一个基于文档的分布式的开源的NoSQL数据库,文档的结构为BSON形式,每一个文档都有一个唯一的Object ...

  10. Mono 3.8发布:性能进一步改进,可伸缩性提升

    9月4日,Mono 3.8.0发布了.该版本的运行时带来了一些性能和可伸缩性方面的改进,同时完成了向Windows平台的移植. Mono遵循Gnome和Linux内核的版本编号策略,这意味着3.8是3 ...