MapReduce作为一种重要的编程思想,在互联网开发特别是分布式开发中得到了广泛的应用,MES通常是集中式开发系统,但是MapReduce的方法论也可以予以借鉴,本文以三个实际应用的例子来进行探讨。
应用一:动态工艺参数下载
在MES中,动态工艺参数下载是一个很常见的场景,即在生产的过程中,需要从系统下载得到一些动态工艺参数,比如一些工单的属性、BOM中的特殊零件物料号、在某工位测试的次数等。
最简单的应对方法是写一个专门的程序,把所有可能的逻辑都包含进去,这样带来的问题是:
1) 这个程序的逻辑非常复杂。
2) 每次增加工位都需要对程序进行升级,并且升级时可能需要系统停线。
现在我们用MapReduce的方法论对它化繁为简。
首先我们认识到,这个程序的核心是一个函数,输入产品序列号和工位,输出工艺参数,其中工艺参数是若干个工艺变量的组合。而工艺变量的生成方法是:
1) 常数
2) 工单属性
3) 正则表达式
4) 数据库查询
现在我们分别进行Map和Reduce的操作。
1. Map
首先我们建立一个Map表,把所有工艺参数的变量在数据库中进行配置:
2. Reduce
然后我们分两步进行Reduce:
1) 分别得到各个工艺变量的值。
2) 将多个工艺变量的值进行规范处理,并组合得到完整的工艺变量。
其中对于第1步,分别对每一种工艺变量类型定义一个Reduce函数,如:
1) 常数直接从内存中提取Map查询得到的值。
2) 正则表达式则进行运算处理。
3) 对于数据库查询,则运行对应的数据库函数,并配合输入的产品序列号和工位,经过计算得到对应的变量值。
这样处理的好处是:
1. 化繁为简,每一步都是相对独立的操作,减少了系统的耦合性。
2. 每一个工位、每一个工艺参数、每一个工艺变量的定义都是相对独立的。增加新工位不会影响旧工位,更新一个工位的参数不会影响其它工位,尽可能地减少了变量对系统全局的影响。
详细设计可参见我的文章:《浅谈 MES的通用设计之二:工艺参数的下载》
应用二:通过物化视图同步数据
某工厂需要将生产数据从MES同步到维保系统,其中生产数据包括:产品序列号、工单信息、上线时间、上线工位、下线时间、下线工位、关键零件部批次号、关键检测工位检测次数、是否一次性通过等。
常见的做法是通过SQL把原始数据映射到物化视图,然后另建一个SCHEDULED JOB去定期刷新。
但是问题在于,这个SQL的业务逻辑非常复杂,要关联多张表,并且要进行分组统计、递归等较消耗资源的计算。
下面我们看看怎样用MapReduce的方法论来进行简化。
1. Map
首先我们列一个表,看看最终输出字段的计算逻辑。
从上表中我们可以看到要查询很多的历史记录表,而这些表在设计时并没有针对统计进行优化。
下面我们看看怎样在Reduce操作时减少查询的时间。
2. Reduce
首先有一个额外的因素要考虑:数据同步的时机。
场景一:数据同步和MES生产是错开的,比如生产在下午结束,而同步在晚上进行,那么即使同步时消耗了大量的数据库资源也不会对生产造成影响。
场景二:生产和同步同时进行,那么就必须排除同步作业时数据库查询对MES实时生产作业的影响。
下面我们分别针对各字段进行Reduce的优化说明。
1) 产品序列号
由于序列号属性表是一个主表,结构较简单,一般直接查询即可。
针对场景二,如果数据量特别大(比如小型数码产品的生产,一天可能多达近100万的数据量),那么可以这样处理:
a) 建一个新表N,用于存放已下线产品的数据,定义属性:序列号、工单、上线时间、上线工位、下线时间、下线工位、关键检测工位检测次数、是否一次性通过。
b) 在序列号属性表里建一个触发器T,每当状态属性更新为下线时,自动将序列号、工单、上线时间、上线工位、下线时间、下线工位这些数据查询得到后复制到表N。
这样我们就得到了一个数据量较小的表,而且同步所需的许多数据直接查询此表就可以得到。
2) 工单信息
直接从序列号属性表查询就可以得到了。
针对场景二,工单和序列号一起进行复制作业。
3) 上线时间
上线时间需要查询历史记录表,而且需要做一个分组统计的动作,非常消耗资源。
为了简化逻辑,我们可以编写一个查询上线时间的数据库函数FFT,根据序列号检索,得到第一次经过上线工位的历史记录时间。
针对场景一,我们可以直接在查询SQL调用此函数得到输出字段。
针对场景二,我们可以让触发器T调用此函数得到上线时间然后输出到表N。
4) 上线工位
编写一个查询上线工位的数据库函数FFS,根据序列号检索,得到第一次经过上线工位的工位名称。
针对场景一,我们可以直接在查询SQL调用此函数得到输出字段。
针对场景二,我们可以让触发器T调用此函数得到上线工位然后输出到表N。
5) 下线时间
编写一个查询下线时间的数据库函数FLT,根据序列号检索,得到最后一次经过下线工位的历史记录时间。
针对场景一,我们可以直接在查询SQL调用此函数得到输出字段。
针对场景二,触发器T直接更新表N的下线时间属性。
6) 下线工位
编写一个查询下线工位的数据库函数FLS,根据序列号检索,得到最后一次经过下线工位的工位名称。
针对场景一,我们可以直接在查询SQL调用此函数得到输出字段。
针对场景二,触发器T直接更新表N的下线工位属性。
7) 关键零部件批次号
由于BOM存在层级结构,零部件的追溯记录存在一定的递归关系,做递归查询较消耗资源。
但是由于要同步的关键零部件的结构关系是较固定的,因此我们可以编写一个视图VG来复制关键的业务数据。
针对场景二,如果结构特别复杂,我们可以针对每个关键零部件分别编写函数FG1/FG2/FG3来进行数据抽取,然后利用触发器进行调用后复制数据到表N。
8) 关键检测工位检测次数
编写函数FTC来计算检测次数。
针对场景二,利用触发器进行调用后复制数据到表N。
9) 是否一次性通过
编写函数FTT来计算是否一次性通过。
针对场景二,利用触发器进行调用后复制数据到表N。
下表列出了新增的Reduce操作:
然后再辅助以下的操作,以方便将来的维护、调整:
1) 新建一个视图VW,结构和物化视图一致,通过查询表、视图VG,并调用相关的函数,来得到所有需求的数据。
2) 把物化视图的SQL更新为:SELECT * FROM VW; 这样做的好处是,如果需要做一些调整,我们可以直接在视图VW里进行更新,而不需要重新编译物化视图。
3) 新建一个存储过程SPW,用于执行刷新物化视图的操作。
4) 在SCHEDULED JOB里直接调用存储过程SPW,实现定期刷新。
通过以上的Map-Reduce操作,我们就把一个业务逻辑非常复杂的物化视图查询逻辑,转换成许多个业务逻辑相对简单、耦合性弱、查询效率高的数据库操作,简化了逻辑,增强了性能。
应用三:与PLC通讯
在许多工厂,用PLC控制设备,然后通过OPC与MES建立通讯。
OPC是一个广泛使用的工业标准,开发和部署都非常方便,而.NET对OPC的集成支持也非常好。
通常的做法是,在MES服务器上部署一个OPC CLIENT,建立与OPC的通讯,而MES对OPC的读写可直接映射成对PLC的读写操作。
而这样做的缺点是:
1) MES和PLC的耦合性太强,一旦MES停止响应则PLC也无法指导设备工作。
2) MES里集成了很多和PLC握手的控制逻辑,和MES的业务逻辑交织在一起,增强了逻辑的复杂度,降低了问题诊断的效率。
而现在有不少MES商业软件供应商慢慢地把PLC通讯的这一块从MES业务逻辑中分离出来,方法是建立一个通讯的中间层。如Telit公司的deviceWISE能够把PLC数据流转换成J**A消息队列,这样对于应用系统来说,PLC来源的数据和其它来源的数据在经过转换后已经没有了形式上的区别,应用系统只要处理业务逻辑即可。
这里有一个前提,就是所有握手逻辑都在PLC里实现,OPC中间层只转换业务数据。
更进一步地,我们可以建立一个IT PLC,专门处理控制层的逻辑,并且为OPC中间层准备特定格式的数据。这样就形成了设备PLC-IT PLC-OPC-MES服务器这4层结构。
下面举一个汽车装配工厂车辆识别模块的例子。
下图是传统交互式握手的示意:
我们可以看到在MES服务器上需要编写握手的逻辑。
下图是增加IT PLC后,以请求/应答方式进行握手的示意图:
我们用MapReduce的方法论对它进行分析:
我们可以看出,经过MapReduce处理后,在每个层面上的逻辑复杂度都得以减少,更加专注于业务的实现。