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. 在线浏览PDF之PDF.JS (附demo)

    平台之大势何人能挡? 带着你的Net飞奔吧!:http://www.cnblogs.com/dunitian/p/4822808.html#skill 下载地址:http://mozilla.gith ...

  2. PHP之GD函数的使用

    本文讲解常用GD函数的应用 1.一个简单的图像 我们先看一个例子: <?php $w = 200; $h = 200; $img = imagecreatetruecolor($w,$h); $ ...

  3. [EasyUI美化换肤]更换EasyUi图标

    前言 本篇文章主要是记录一些换EasyUI皮肤的过程,备忘.也欢迎美工大神各路UI给点好意见,EasyUI我就不介绍了,自行百度吧..(So..所以别问我是不是响应式..本身EasyUI就不是响应式. ...

  4. 如何用Java类配置Spring MVC(不通过web.xml和XML方式)

    DispatcherServlet是Spring MVC的核心,按照传统方式, 需要把它配置到web.xml中. 我个人比较不喜欢XML配置方式, XML看起来太累, 冗长繁琐. 还好借助于Servl ...

  5. vim的一些常用命令(一)

    先确认在Normal模式下,如不确认,请按几次Esc. :sy on/clear sy表示语法高亮,on是打开.clear是取消. :set go= set表示一般性设置,go是gui option的 ...

  6. QDEZ集训笔记【更新中】

    这是一个绝妙的比喻,如果青岛二中的台阶上每级站一只平度一中的猫,差不多站满了吧 自己的理解 [2016-12-31] [主席树] http://www.cnblogs.com/candy99/p/61 ...

  7. JavaScript

    2015-08-01 16:20 JavaScript使用时需要注意的地方 1.引入JS的位置:最好的做法是把<script>的标签放到HTML文档的最后.</body>标签之 ...

  8. Android Secret Code

    我们很多人应该都做过这样的操作,打开拨号键盘输入*#*#4636#*#*等字符就会弹出一个界面显示手机相关的一些信息,这个功能在Android中被称为android secret code,除了这些系 ...

  9. 设置Fn键 笔记本直接按F1-F12 无须按Fn键 Fn+F12改F12(联想小新300为例)

    最近公司给配的笔记本联想小新300 80RT  i7-6500U 4G内存 500G机械,后加装120G固态+4G内存 这样就感觉还不错了. 在使用这本子的时候,去了Win10,强行装了Win7.无线 ...

  10. Android笔记——Handler Runnable与Thread的区别

    在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类是在java.lang包中定义的.一个类只要继承了Thread类同时覆写了本类中的run() ...