前言
最近公司在搞技术创新,老板把一群程序员拉到山上,锁在酒店会议室里憋了一晚总结出来几条意见,其中之一就是之所以每次产品改需求我们都会苦哈哈的加班写bug,主要不是因为产品今天提的需求,昨天就该上线,而是因为我们没有一种无需硬编码就能修改系统逻辑的方法。大家一致同意改变命运的关键在于开发一个可视化的规则编辑和执行引擎。我一听这不就是我N年前搞过的决策树吗,虽然具体需求拔高了许多,但现成的代码改吧,改吧就能用啊。于是把代码拉出来,一通操作猛如虎之后,搞定。
本文将简单介绍一下决策树,以及如何利用可视化编辑器创建决策树模型并在应用中加以使用。想要升职加薪,又想减少秀发流失率的程序员,和希望在工具的逼格上PK掉隔壁开发小组的dev leader适合阅读本文。
决策树定义
决策树是一种树形结构,其中每个内部节点表示一个属性上的测试,每个分支代表一个测试输出,每个叶节点代表一种类别。它是一种简单但是广泛使用的分类器。可以高效的对未知的数据进行分类。例如:
决策树有两大优点:
决策树模型可以读性好,具有描述性,有助于人工分析
效率高,决策树只需要一次构建,反复使用,每一次预测的最大计算次数不超过决策树的深度。
决策树适用场景
决策树主要用于核心的判断和分类逻辑。是否用决策树代替硬编码的if-else或者switch语句,可以参考以下几个判断标准:
1. 判断逻辑是否相对独立,在判断中是否主要是分类判断,不大涉及到计算过程
2. 判断逻辑是否会经常调整,比如是否依赖于节假日,市场或政策的变动,例如优惠规则等。如果是常识,或者基本固定的技术层面的判断或校验,则无需使用决策树
3. 影响判断的因素是否较多,比如大于等于3个因素,每个因素有2个或以上的分类判断
4. 判断逻辑是否是重要的业务需求,比如业务需求描述了明确的分类算法等
如果上述问题的答案中是的较多,建议使用决策树。
如果没有趁手的工具,光知道决策树的概念并没有什么用。接下来我就为大家介绍一款与IDE集成的,非常方便好用的可视化决策树编辑器xDecision。
XDecision简介
xDecision是一套包括编辑器和引擎在内的决策树工具。其中编辑器可以以插件形式安装到流行的IDE中,目前支持Eclipse和IDEA。研发人员通过编辑器在IDE里面创建决策树模型,再在应用中使用引擎对事实做判断以获取决策。
项目地址:
https://github.com/hejiehui/xDecision
安装编辑器插件
Eclipse编辑器插件
如果要安装Eclipse版本,请下载xDecision Eclipse插件
在Eclipse里面按照时记得选型按照下图勾选:
IDEA编辑器插件
如果安装IDEA版本,请下载xDecision IDEA插件:
在File->Settings->Plugins->Install plugin from disk里面选择下载好的插件,安装重启即可
获取xDecision引擎依赖
引擎是标准maven项目。项目地址在:
下载后即可编译打包
快速体验
如果希望快速体验决策树的魅力,可以直接下载样例工程:
在IDE里面双击src/main/resources下的
即可在编辑器中打开对应模型
创建决策树
决策树编辑器的使用真的超简单。
在Eclipse中安装插件后,在New菜单里面可以看到New Decision Tree Wizard创建向导。
在IDEA插件安装好后可以看到Xross Decision Model菜单
点击后输入文件名即可创建一个空白的决策树模型。Eclipse版本的编辑器需要配合Properties View,既属性窗口,可以在windows菜单找到并打开。IDEA版本的编辑器会自动显示,无需用户处理。
缺省模型
xDecision相关概念
点击编辑器的空白处,即可选中决策树模型本身,在对应的Properties里面,你可以看到有Configure,Decisions和Factor。
这些就是构建决策树的基本元素。我们先不管Configure里面的内容,先来看看Decisions和Factor。
Decisions
以字符串表示的所有可以通过决策树的路径到达的decision。在编辑器中如果选择的话,会以暗绿色显示在节点上。
Factor
用于决策判断的事实依据,可以看做是变量或属性。每个Factor按照创建顺序自动赋予一个递增的id。每个事实包括name属性和其取值范围的枚举集合 Factor X value [0,N]。Name会显示在节点的顶端,代表本节点基于那个事实进行判断。Value会作为连接该节点和子节点的边的选项,代表当事实为何值的时候,选择这条路径。
预定义值
为了方便大家使用,新决策树模型预先创建了3个factor,每个两个取值,和6个decision作为初始数据。你可以在Properties窗口对这些预定义的数据做修改并里面反映到图上。
创建节点
下面的操作以IDEA作为代表,Eclipse的操作基本相同
点击
按钮,再点击编辑器空白处,即可创建一个新节点。点击节点,在属性窗口的Factor栏可以选择该节点判断所需的事实。如果该节点同时对应一个可以到达的决策,则可在Decision栏选择对应decision
关联节点
点击
进入关联节点模式,依次点击父节点和子节点,将在两节点之间产生一个连线代表关联关系,点击该连接可以选择父节点factor中的一个取值作为判断依据
重复上面的步骤,创建所需节点并建立连接,从而最终形成一个决策树。
增加事实和决策
如果情况复杂,缺省的factor和decision不够用,可以随时增加新的。右键调出弹出菜单或者点击
这两个工具按钮(Eclipse只有菜单,没有这两个工具按钮),输入factor或decision的名字即可创建。
自动布局
如果觉得决策树布局不美观,编辑器上方提供了自动布局的工具按钮,横竖,间隔都可以随意调整,即使是我等手残党也可以一键搞定
自定义功能
缺省情况下,factor和decision都是字符串,在大多数场景里面够用了。但有时候希望最终获取的decision是个自定义对象,比如实现了某个接口的,可以做方法调用的实例;或者希望对factor的判断可以基于表达式,这时候就是xDecision插件登场的时候了。还记得之前我们暂时放下的Configure配置吗?在这里可以设置用户自定义的扩展。具体不在这里细说,有兴趣可以参考:
验证决策树
生成出来的决策树到底灵不灵是大家最关心的问题。点击
可以自动帮你生成基于当前决策树的测试代码。代码包含完整的类定义,提供类名,获取决策树模型的逻辑,和对每个可到达的decision的factor构建和调用的逻辑。你可以新建一个java类文件将代码手工copy进去,为项目添加xDecision依赖后,按照标准的junit的方式去运行。这个测试代码同时可以作为学习xDecision用法的例子。
例如我们为刚才创建的决策树生成的测试代码长这样:
其中关键代码就是:
tree = XDecisionTreeFactory.create("D:/test/com.xrosstools.xunit.sample/src/main/resources/xdecision_demo.xdecision");
//Verify tree
MapFacts test;
test = new MapFacts();
test.set("factor0", "value1");
assertEquals("decision2", tree.get(test));
可以直观的看到使用决策树能大幅简化代码,从此和if-else say bye-bye!
样例工程里面的测试代码也是通过这个功能生产的,其中:
SampleTest.java是原始代码没有修改,
ExpressionTest.java利用了扩展,在生成的代码基础上简化了factor的赋值
总结
只要是做过几年开发的人都知道,软件系统在上线的那一刻,才真正开始自己的生命周期。接下来会是无尽的修改和优化。这其中最麻烦的就是理解现有逻辑并加以修改。当年我写if-else简直快写吐了,碰到生产问题时面对一大坨自己或别人写的分支简直欲哭无泪。
使用决策树可以大幅简化代码,因为没有代码开发工作,也就没有代码风格,严谨度等人的因素造成的各种问题。如果将模型存储在配置中心,还可以方便的做到热部署,做到实时生效,节约大量测试和发布时间。
这个工具安装快捷,使用直观,简单培训即可上手,作为通用的模型,产品也可以看懂并参与讨论,让甩锅更困难。非常适合公司作为研发规范推广。
想象一下,当产品又双叒提了一个变更的时候,你拉风的点开决策树模型,一棵精致的决策树刷的闪在大家眼前,你懒懒的抬起手,随便划拉几下鼠标就搞定了变更需求,再实时部署到测试或者生产环境,立马生效。你回头看了一眼目瞪口呆的产品和旁边团队leader羡慕嫉妒恨的眼神,嘴角露出了难以察觉的微笑
参考资料
作者介绍
赫杰辉,信也科技基础组件部门主管、架构研究员、信也 DAS 产品负责人、布道师。图形化构建工具集 x-series 的作者。曾主持开发携程开源数据库访问框架 DAL。对应用开发效率提升和分布式数据库访问机制有多年的深入研究
如果对决策树或其他可视化开发工具感兴趣,可以加入QQ群获取进一步信息