OptaPlanner背景

  在上一篇里喷了不少水,这一篇准备放点干货;其实也没办法完全干,因为很多预备知道在交待一下。好了,说一下关于OptaPlanner的背景、应用兼容性及其原理。

这一篇先说一下OptaPlanner是何方神圣,再看看它适用于哪种平台(.NET能用吗?老旧系统能用吗?),再从原理上探究一下,它是如何帮我们把一个看上去几乎不可能实现的工作,努力做到比经验丰富的老师傅更好的。下一篇我将会讲解OptaPlanner相关的基本概念,并教大家它的examples(示例)运行起来(这些examples可是好东西喔,并且非常丰富)。

  顾名思义,叫什么planner的,它肯定是用来plan东西的东东,就是把一堆东西(数据)扔进去,再教它一些规则(Drools脚本或Java写的算分程序),然后它就运用它的数学头脑,把这些东东按要求把它初始化好,并努力找到一个相对最优的方案;如果数据不是太多,那它就能找到一个绝对最优方案了,因为它以把所有情况都篇历。例如:你有一堆任务需要确定分配到哪些机台,需要计算每个任务什么时候开始处理(也就是明细的生产计划了);用OptaPlanner跑完之后,就会给出一个方案,这个方案包含了每个任务应该放在哪个机台,应该在什么时候开始。又例如:在医院等单位进行医护人员排班时,把各个医护人员的专长,每个人员的作息信息,每个科室需要的专业技能等信息放进去,OptaPlanner就能给你找出一个排班方案出来,可以满足各科室对特殊专业人员的需求,也可以满足各人员尽量不超时工作的方案。

  那么问题来了,OptaPlanner到底是一个什么鬼东西?它有这么牛?真能这样,我们做排产的老师傅不是要失业了吗?其实不然,它只是按我们设计的规则来找尽量好的方案,而这些规则好不好直接影响到方案的优劣,所以如果OptaPlanner成功应用了,并不是替代了老师傅们,而是把老师傅解放出来,让他们去重新思考并制定更佳的规则,并通过OptaPlanner来验证并实现这些方案。

  E文好的同学可以直接进它的官网(http://www.optaplanner.org), 学成了记得分享呀。先说一下这OptaPlanner的来头,它本来是一个名叫Geoffrey De Smet的大牛自己写的,后来他就把它贡献给了JBoss基金会(这里省去了N年的曲折离奇, N >= 10),并成为KIE项目组中OptaPlanner项目的负责人。所以OptaPlanner是基于Apache2.0开源协议的,对商业友好,就是说你想用就尽管用,有问题还可以在他们的讨论组上求助。关于这位超级大牛的个信息及OptaPlanner的详情,可从以下链接看到,其实这位大牛给OptaPlanner录制了很多讲解OptaPlanner的视频,只不过它只放在Youtube上,大家要看的自己想办法上去搜OptaPlanner了,提醒一下各位,Gerffrey这牛不是英美或其它以英语为母语国家的人(好像是比利时还是荷兰人),它的口语乡单比较重,听起来挺吃力的,还没字幕。而且讲的都是各个示例和一些比较高级的应用,去看视频之前最好还是打一下基础,要不然基本上看不懂(没基础就算讲中文也听不懂吧?)。

  Geoffrey De Smet在GitHub上的主页:https://github.com/ge0ffrey(还有StackOverflow上也有他老人家不少对OptaPlanner问题的解答,大家可以搜搜)
OptaPlanner的背景介绍:http://www.oschina.net/news/75942/a-decade-of-optaplanner (这是开源中国社区翻译Geoffrey老人家的文章,原著E文版在这:http://www.optaplanner.org/blog/2016/08/07/ADecadeOfOptaPlanner.html)

  OptaPlanner其实是一个很好的排程引擎(更贴切地说它是一个规划引擎,下面就称规划引擎吧,因为它不光用于排产上),耐何在国内使用的人十分少,所以中文资料几乎没有,国内有几个比较出名的APS产品,不知道其排程核心用的是什么,不过如果是自主开发APS系统的话,OptaPlanner是一个好的引擎,毕竟并不是所有企业都能找到一堆数学专家对组合优化问题进行研究的。而OptaPlanner资料非常丰富,它的项目组还能提供很好的技术支持(免费的仅限于讨论组答疑,付费的就没试过了),而且使用起来也方便、容易。但目前我观察的情况来看,还只有比较多国外的同行们及相关的技术网站在研究讨论。我也是奉公司之命开发生产排程方面的系统,才硬着头皮去啃它的。又耐何我的体育老师不给力,教的E文也不怎么样,虽然是把基本的东西看懂了,但很多更深层的东西其实还没有完全摸透的(到目前为止我还遇到一个Score Corruption的问题还在研究)。所以有赖大家一起学习之后的分享了。在应用OptaPlanner的过程中,我也遇到一些问题,一开始有些小白问题,后来又遇到一些跟系统实情相关的难题,我也曾经在讨论组上向Geoffrey他老人家请教,老实说,他还是一个比较有耐心,非常nice的人,一点都不嫌我这类小白烦,从原理开始给我讲解出错的原因,应该如何改,这个要猛赞一下。

  接下来我就发挥程序狗的看家本领Ctrl + C -> Ctrl + V, 中间还去逛了一次百度翻译(没办法,体育老师呀).
OptaPlanner是一个约束求解器。它优化了企业资源计划的使用情况,如车辆调度、员工排班、云优化、任务分配、任务调度、Bin Packing等等。每个组织都面临这样的调度难题:分配一组有限的受限资源(员工、资产、时间和金钱)来提供产品或服务。OptaPlanner提供了更有效的计划,提高服务质量并降低成本。OptaPlanner是一个轻量级的、可嵌入的规划引擎。它令普通的java程序员有效地解决优化问题。它还与其他JVM语言兼容(如 Kotlin 与 Scala)。约束适用普通的域对象,可以重用现有代码。没有必要把它们作为数学方程来输入。在引擎盖之下,OptaPlanner结合先进的优化的启发式和共通启发式演算法(如禁忌搜索、模拟退火和延迟接受),非常高效地进行分数计算。OptaPlanner是开放源代码的软件,Apache软件许可下发布。它是用100%的纯java™,运行在任何JVM在Maven的中央存储库也可用。

  好了按上述的官方描述我们可以大概知道,它就是一个用来解一些规划问题的引擎,而规划问题几乎都可以被视作NPC问题,关于什么是NPC问题呢?这里还喷点水,让大家对NPC问题有个大概的概念,如果不是研究数据的,了解一下就可以了。大家可以看一下这位牛人写的关于NPC问题的文章(http://www.matrix67.com/blog/archives/105),概括来说,就是一些没有办法使用确定性算法来得到结果的问题,而对于这类问题,又分为NP问题和NPC问题,但都只能通过遍历的办法才能找到。对于NP问题和NPC问题,我有以下理解,也不知道对不对,大牛看到不对的帮忙指正一下:

  NP问题:一种无法通过确定性算法直接获得解,但对获得的解是可验证的,例如:结合上一篇文章提到的生产排程问题,如果老板只要求做出一个可行的生产计划,也就是只需要一个可以执行的生产排程就可以了。成本、效率什么的都不管;那么这就是一个NP问题。因为要做出这个计划,你也是没有直接的、确定的方法或算法来做的;更多的是靠经验、对实际情况的有限掌握、对来情况的预判和感觉。但是做出来的计划是可以验证的。也就是说车间拿着这个计划是真的可能执行的,而不会出现物料不到位、产品分配到了错误的机台上等违反硬约束问题的, 那么只要不违反这些硬性约束,就认为这是一个可行的计划。所以做一个可行计划,可以被视作是NP问题。

  NPC问题:则是那种不旦无法通过确定性算法获得解,对所得的解,也没有一个确定的办法去验证的问题。还是上面的生产排程问题,如果老板要求做一个所有情况下除了可行,还要成本最低、效率最高的计划。那么:1. 计划员也只是靠经验、预判、对数据有有限掌握做出一个计划来,计划是否可行是可能验证的(也就是NP问题),但这个计划是否成本最低、效率最高,那就没办法验证了,除非你把所有可能的计划都列出来(这个就不是确定性算法了,因为并不是所有情况你都能把所有情况都列出来)。事实上,现实世界遇到的问题,光靠人类,即便通过超级计算机,也是不太可能把所有情况都遍历完的,例如一个计划有1000个任务,就算忽略任务的所有其它考虑因素,就是1000个任务无任务要求,随便自由地排列,也就是1000个数的排列问题了,有多少种情况?是1000的阶乘!(有兴趣的同学自己回顾一下高中的排列公式)再考虑每个任务的各种属性,及每个属性的可能取值范围,那么组合下来,通常是天文数字了。

  所以,OptaPlanner在排程领域的作用就是帮人们对问题的可能性进行“遍历”,为什么我把遍历引起来呢?因为如果仅仅是无序地遍历,对所有情况一个一个试,那OptaPlanner就没啥作用了,我们可以通过自己编写程序,就能设计出遍历所有组合情况的代码来(能不能跑完那是另外一回事)。OptaPlanner强大之处在于,他是有方法地去遍历的,它引入了禁忌搜索,模拟退火等算法,力求在固定的时间内,找到比傻傻地遍历更好的组合方案出来。事实上也证明它这些算法是有效的。

OptaPlanner的作用、构架和应用兼容性

  关于OptaPlanner开源包,大家可以上官网看看,我在这里也只做个大概的介绍,毕竟我也是新手呀。其实OptaPlanner现在已经加入KIE Project Group,作为KIE的一个子项目,关于KIE可以看看Redhat的一个项目群,包括了OptaPlanner(就是本系列文章的主角),Drools(规则引擎,国内已有很多相关的资料,我就不再熬述了,OptaPlanner是需要结合Drools来使用的,所以这个系列的文章里也会有些内容涉及Drools,但不会太深入),另外一个就是jBMP了,是一个流程定制的平台。

作用

  OptaPlanner用官方的描述就是可以帮你规划出一个用更少的资源做更多更好事情的规划引擎。如下图列出它可以做的工作领域(这仅仅是OptaPalnner的Example里有的示例,其实所有关于规则的问题,属于NPC的问题,只要你能把它抽象并建模成OptaPlanner可识别的模型,你就可以用OptaPlanner来解决):车辆调度、工作排程、设备排程,Bin Packing(就是用袋子装石头那个问题啦)及员工排班。

构架和应用兼容性


  
那么应用OptaPlanner需要什么条件呢?其实作为一个轻量的、可嵌入的规则引擎,兼容性肯定是人家设计时的考虑重点之一,所以它完全是一个纯Java环境的软件,只要你的系统有Java8以上的运行环境(7.6版本要求的是Java8),遵循 Apache Software License 2.0就可以使用了。在我的工作中,我把它运行于Windows, 云端的Unbuntu.凡是一般Java程序能运行的环境,只需你一个jar命令,就可以运行你内嵌了OptaPlanner的程序了。这里有一个官方关于OptaPlanner兼容性的图:

  那么有人就问了,现在很多企业用的都是Microsoft平台或其它老旧平台技术(有什么办法呢.NET就是多人才),是不是OptaPlanner与我的项目就无缘了?其实不然,因为OptaPlanner本身是一个引擎,是基于Java技术的,你通过它来实现你自己的规划引擎程序的时候,必然也是需要Java写的。但这个规划程序是一个服务程序,它不像普通的Web程序,需要频繁跟用户交互,事实上它的所有运行过程中涉及的数据都是需要基于内存的,在此过程是不能进行IO的(并不是说OptaPlanner引擎不允许这么做,而是我们设计的时候就不应该这么做),至于为什么,是码农都懂,一个对CPU高度依赖的程序,你还要它去做I/O,是不是有点那个?所以通常情况下,它是一次性把需要规则及数据都装入内存,完成后再输出。基于上述原则我们就可以把写好的规划引擎程序(Java包)放在一台相对独立的服务器上去运行,再以服务的形成为其它客户端系统提供规划服务。那你的客户端系统是用Web还是 C++来写,是你自己的事了。

原理

  那么OptaPlanner是通过什么方法,高效地帮我们在尽量短的时间内,找到更佳的方案呢?还记得上一任篇老农提到,我们做排程的时候,通常有两种约束条件,分别是不可违反的硬约束,如果一个计划违反了硬约束,那这个计划就是不可行的,例如:生产计划中,把产品固定工序的加工次序调乱了,又或者把产品分配到错误的机台上生产(这些约束条件都是业务上你们自己定义的),那么OptaPlanner就把它定义为违反了硬约束。另一类就是软约束,就是那种可以违反,但违反得越多,就会影响越大(影响包括成本、效率、质量等),所得结果方案的质量越差;违反这种约束,OptaPlanner就把它定义为违反了软约束。OptaPlanner就是对这两类约束进行打分,硬约束对应的是硬分数,软约束对应的是软分数。那么得分越高,就表示对应方案的质量越高。在计算这些约束分数的过程中,OptaPlanner会保持优先优化硬分数、然后在硬分数最优的基础上,再去优化软分数的原则,来寻找最佳方案。例如:两个方案A、B对比,方案A的硬分数比方案B的硬分数高1分,方案B的软分数比方案A的软高出10万分。那么OptaPlanner最后还是认为方案A更佳。也就相当于我们写SQL脚本时,order by子句中前后两个字段的关系了,靠前的字段排序比靠后的字段更优先。

思考题:

  既然硬约束是不能违反的,那OptaPlanner当然要保证找出来的方案绝对是不违反硬约束的,这个大家觉得在所有情况下都成立吗?就是OptaPlanner必然给你找到一个绝对不违反硬约束的方案吗? - 显示不是,大家自己思考一下。

这一篇我们先介绍一下OptaPlanner的背景、使用情景和原理。下一篇我们就开始实质的了解它的应用。

另外,若对此文(或本系列任何内容)感兴趣,欢迎转载,但请尊重艰辛劳动,注明出处。为谢!