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. 【组织级项目管理】P2 MSP P3O

    组织级项目管理--有你,有我,有大家 在过去的2年,无论对于企业来讲,还是对于我们个人都有很多大脑的冲击,有几个词大家应该特别耳熟能详:转型,变革,敏捷,互联网+,组织的项目化管理等.就是这些让我们的 ...

  2. C# MVC 5 - 生命周期(应用程序生命周期&请求生命周期)

    本文是根据网上的文章总结的. 1.介绍 本文讨论ASP.Net MVC框架MVC的请求生命周期. MVC有两个生命周期,一为应用程序生命周期,二为请求生命周期. 2.应用程序生命周期 应用程序生命周期 ...

  3. SignalR代理对象异常:Uncaught TypeError: Cannot read property 'client' of undefined 推出的结论

    异常汇总:http://www.cnblogs.com/dunitian/p/4523006.html#signalR 后台创建了一个DntHub的集线器 前台在调用的时候出现了问题(经检查是代理对象 ...

  4. 了解PHP中的Array数组和foreach

    1. 了解数组 PHP 中的数组实际上是一个有序映射.映射是一种把 values 关联到 keys 的类型.详细的解释可参见:PHP.net中的Array数组    . 2.例子:一般的数组 这里,我 ...

  5. Android数据加密之SHA安全散列算法

    前言: 对于SHA安全散列算法,以前没怎么使用过,仅仅是停留在听说过的阶段,今天在看图片缓存框架Glide源码时发现其缓存的Key采用的不是MD5加密算法,而是SHA-256加密算法,这才勾起了我的好 ...

  6. CRL快速开发框架系列教程十三(嵌套查询)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  7. 深入理解javascript的getTime方法

    1.理解getTime getTime() 方法返回一个时间的格林威治时间数值. 可以使用这个方法把一个日期时间赋值给另一个Date 对象. 语法: dateObj.getTime() 参数: 无. ...

  8. Stack Overflow 排错翻译 - Closing AlertDialog.Builder in Android -Android环境中关闭AlertDialog.Builder

    Stack Overflow 排错翻译  - Closing AlertDialog.Builder in Android -Android环境中关闭AlertDialog.Builder 转自:ht ...

  9. Atitit.attilax软件研发与项目管理之道

    Atitit.attilax软件研发与项目管理之道 1. 前言4 2. 鸣谢4 3. Genesis 创世记4 4. 软件发展史4 5. 箴言4 6. 使徒行传 4 7. attilax书 4 8. ...

  10. Mysql - 数据库操作

    之前介绍了数据库的增删改查, 发现忘记了数据库的一些基本操作, 比如建库, 建表, 改表等等. 那这里就来小结一下数据库sql形式的基本操作. 一.库操作 1. 建库 在建库之前, 可能需要看一下, ...