你好,游客 登录
背景:
阅读新闻

JWFDv0.96开源工作流引擎设计--节点匹配搜索算法设计说明 - comsci的专栏

[日期:2013-04-12] 来源:  作者: [字体: ]


   JWFDv0.96开源工作流引擎设计

                       --节点匹配搜索算法设计说明

注:这篇文章中所使用的“函数”就是指JAVA语言中的方法


  

 

   作者  comsci        四川.成都        最后修改时间    2013.4.1


算法设计说明   (前两年,我曾经公布过这个算法的简易设计说明,这几个月花时间重新把算法的详细设计说明完成了,方便我们大家研究,现在网上有JWFD开源工作流系统的各个模块的设计说明文档,请阅读代码的时候参考)

只所以要设计这样一个算法,原因是在设计流程引擎的过程中遇到下面的这个问题

    

“在对称条件下带条件选择的汇聚路由问题”: 

   

问题的严格数学语言描述:在任意一个流程图中,存在N个分支点和M个汇聚点,所有汇聚点和分支点的关系有规则对称和不规则对称两种(图1中的A2的拓扑是规则对称,A1,A3是不规则对称),每一个分支点的运行路径数S和它的实际分支路径数W有可能不相同,即S<>W和S==W的情况同时存在,现在的问题是:在规则对称的拓扑结构下(A2),已知分支点的实际运行路径数值S,求图A2中对称汇聚点的实际访问(实际汇聚)数值K 





问题的描述用比较严格的语言使得这个问题更加像数学问题,其实本来就是个数学问题,只不过我没有找到这个问题的所属的数学领域,干脆自己取个名字-叫流程拓扑分析方法

    

该问题的现实描述(现实描述的含义是在实际的开发工作中用比较实际的语言来表述)已知流程分支点的运行路径数值S,求流程图中一个汇聚点的实际访问(实际汇聚)数值,通过获取该数值,使得流程运行控制器(流程引擎)能够准确的控制流程的运转走向,即准确的控制对条件异步汇聚点放行的时机

    

     算法设计思路: 对于标准的对称的流程图而言,一个汇聚点一般来讲是应该对应一个分支点的,也就是说汇聚支路数应该和它前面的分支支路数相吻合(当然,这只是对很规则的对称流程图模型来讲),那么如果在分支节点中如果出现了条件选择公式(或者智能脚本),那么从这个分支节点所分出来的支路,就不一定都会被选中,

     

     简单举例, 我们在分支节点中嵌入了一个条件表达式 

     

     if a>2 

       Then goto PATH A B  (实际运行两条分支)

       else goto PATH A B C(实际运行三条分支)

     if a=其它值

        then ..............(更多的情况)

     

     上述表达式中

     流程节点中嵌入的a值一般是要在流程实际运行过程中才能够获得,因为a的值极有可能来自一个嵌入流程的表单,而这个表单要在流程运行的时候才能够被处理,而处理的结果是实时的传递给流程的,所以从这个方面来讲,通过预先确定a值的方法来回避这个问题是不行的


     如果一个流程图的分支实际上有3条支路,在流程运行过程中,a的数值大于2,符合嵌入的条件,3条支路其中的2条就会运行下去,而另外一条就不会运行,这样一来,在该节点的后驱汇聚点那里,我们就需要知道具体运行下去的支路数到底是几条?     

     

     怎么才能够获取这个支路数呢? 我们在流程运行控制器(流程引擎)中加入一段算法,使得我们很明确的知道一个条件汇聚点的前驱分支点是哪个节点,然后我们通过先计算一次嵌入条件公式,预先知道该前驱分支点具体要走几条支路,然后再把这个支路数值作为参数传递给用于控制条件汇聚点的控制器中,使得汇聚点按照实际运行的支路来判断是否该继续运行到下一个节点去,那么我们按照这个思路设计伪码算法

     

 请参考JE论坛上面大家对这个问题的讨论 http://www.ITeye.com/topic/513430 

节点匹配搜索算法的实质

节点匹配对的概念---寻找与一个流程图中某个汇聚点对称分支点是这个问题的关键所在,我们找的就是那个和该汇聚点直接相关的分支点-这就是节点匹配搜索算法的本质


节点匹配搜索算法的代码结构说明

1: 获取输入汇聚节点的所有前驱汇聚点函数 ,这个函数用于获取该节点前面出现的所有汇聚点 

简单的分支汇聚流程的例子:1节点是分支点,4节点是汇聚点



public java.util.ArrayList RAJN(){}

 这个算法是一个递归+SQL查找算法,传递的参数是字符串参数nodeid,这个参数是调用这个函数的时候需要的输入任意的流程图的一个节点字符串参数 graphid,这个参数是标示这个流程图的ID的参数, 数组参数 java.util.ArrayList  jn  用于存储返回的汇聚节点。。。。

 String visits = stm.return_preStep(nodeid, graphid);

 这个语句是调用一个SQL语句,用于查询输入的nodeid节点的前驱节点

 

 if (!visits.equals("")) {  如果查询出来的前驱节点不为空

      if (stm.return_preSteps(graphid, nodeid().size() > 1) {

       // return_preSteps()函数是返回该节点的所有前驱节点,那么这句判断句的意思是,如果返回该节点的所有前驱节点数量大于1,意味着这个这个节点是一个汇聚点,大家可以形象的思考一下,是不是这样的。。。JWFD系统里面用于判断一个 节点是否是汇聚点或者分支点就是依靠这样的判断句

         jn.add(nodeid);  // 如果判断返回为真,那么把该前驱点加入一个数组

      }

      RAJN(visits, graphid, jn);  递归函数,把该节点的一个前驱节点传递到递归函数中,进行下一轮的查找汇聚点的工作

    }

     return jn;  如果无法返回任何一个前驱节点,那么就把汇聚点集合返回给函数,该函数退出。。。输出一个包含流程图全部汇聚点的数组JN

还需要解决的问题

查找一个流程图的全部汇聚点的算法,目前还无法处理复杂的流程图拓扑结构,要做到对任何流程图对适用,估计是不太容易的,因为我们无法预测用户会设计出一个什么样的流程拓扑结构,单一的线路回溯法将无法获得全部支路的所有前驱节点,如果出现分支嵌套分支的情况,算法就更加复杂。。。。

比如说这样的流程拓扑结构


分支嵌套一个分支,这个拓扑图里面就有2个甚至更多的分支点和汇聚点,依靠上面的这种算法能够及时和正确的查找出所有的汇聚点吗? 而且这种拓扑结构还算是对称的分支结构,如果分支结构不对称,汇聚节点查找算法还有用吗?

还是那个问题,流程图的拓扑结构是无法预测的,但是我们的算法和代码是确定的,怎么用确定的代码去出来无法预测的拓扑结构呢?这个问题就是流程系统设计的核心问题!

-------------------------------------------------------------------------------------------------------------------

2获取输入节点的所有后续分支点函数  

public java.util.ArrayList RASN(){}

这个函数用于获取该节点后面出现的所有分支节点 

传递进入的参数:  

字符串 String nodeid,这个参数是调用这个函数的时候需要的输入任意的流程图的一个节点

字符串 String graphid,这个参数是标示这个流程图的ID的参数

数组参数 ArrayList jnn  用于存储返回的所有分支节点ID

输出结果:

 ArrayList  jnn 一个包含了全部流程分支节点的数组

算法结构:

String visits = stm.return_nextStep(nodeid, graphid);

通过调用数据库SQL-API -stm.return_nextStep(nodeid, graphid)获得输入节点的直接后续节点visits,如果要了解该函数的详细情况,请参考JWFD开源工作流系统设计-API函数说明和二次开发手册

判断该后续节点是否为空   

if (!visits.equals("")){

如果该后续节点不为空,那么调用数据库API-获取该节点全部后续节点列表函数

return_nextSteps(),进行输出值判断

if (stm.return_nextSteps(graphid, nodeid).size() > 1){

如果该节点的后续节点全部列表数量大于1

那么算法就断定该输入节点是一个分支节点,如下图所示


那么执行下列操作

将该输入节点nodeid写入数组JNN中保存 

jnn.add(nodeid); 

}

  判断体结束之后,退出判断体

  开始递归  

  RASN(visits, graphid, jnn)

}

  return jnn;

  通过若干次递归查询,把该输入节点的全部后续分支点都找出来,然后写入jnn数组,最后返回该数组,退出函数。。。

----------------------------------------------------------------------------------------------------------------------

3:对该节点的所有前驱分支点集合和前驱汇聚点集合进行计算,找出该汇聚节点的匹配分支点SSID  


public String RRND(){} 

节点匹配算法的实质是对称集合配对差算法 ,这个算法还需要改进

传递进入的参数:

字符串 String nodeid,这个参数是调用这个函数的时候需要的输入任意的流程图的一个节点

数组参数 ArrayList jns   用于存储所有汇聚节点ID

数组参数 ArrayList jns1  用于存储所有分支节点ID

Int k = jns.size();  定义一个循环控制变量,用汇聚点数组的长度做这个K

String rnodeid = ""  定义一个字符串变量,用作返回值,存储查找到的匹配节点

下面是循环体,通过逐个比较每一个在数组里面的节点,对数组进行增删的操作,最终找到与输入节点相匹配的对应节点

 for (int i = 0; i <= k; i++) { 

 循环体的边界是前面取得的汇聚节点数组的长度

 

      if (!jns.isEmpty() && !jns1.isEmpty()) {       

      如果汇聚节点数组和分支节点数组都非空

           if (nodeid.equals(jns.get(jns.size() - i).toString()))             

            如果本节点等于汇聚节点数组的某一个节点

           rnodeid = jns1.get(i).toString();         

             那么该函数的返回值被赋值为分支节点数组的的某一个节点           }

        jns.remove(jns.size() - i);        

        移去汇聚节点数组中的与参数相等的那一个节点

        jns1.remove(i);       

        移去分支节点数组中的与返回值相等的那个节点

      }

    }

return rnodeid;

该算法模块结束。。。。。。。。。。。。


函数功能:返回输入节点nodeid的匹配节点(与分支点对应的汇聚点)

public String RRN(String nodeid, String graphid) {}

    传递进入的参数:

    String rnode = ""; 函数参数:要返回的匹配节点ID rnode;

    

    定义两个数组JNJNN,一个存储全部分支点,另外一个存储全部汇聚点

    java.util.ArrayList jn = new java.util.ArrayList();

    java.util.ArrayList jnn = new java.util.ArrayList();

    调用判断节点是否是分支点的函数,将nodeid节点存储到JN数组中 

    if (stm.return_nextSteps(graphid, nodeid).size() > 1) {

      jn.add(nodeid);

    }

    

    调用判断节点是否是汇聚点的函数,将nodeid节点存储到JNN数组中

    if (stm.return_preSteps(graphid, nodeid).size() > 1) {

      jnn.add(nodeid);

    }

   

RAJN函数返回流程图所有的汇聚点集合,RASN返回流程图所有的分支点集合,然后RRND函数对这两个集合的元素进行匹配,最终筛选出一个和nodeid节点相匹配的节点rnode

rnode = RRND(nodeid, RAJN(nodeid, graphid, jnn), RASN(nodeid, graphid, jn));

    返回这个匹配节点 

    return rnode;

  }


现在来看这个算法,还有很多地方有需要改进的地方,甚至还存在一些错误,希望朋友们发现有任何地方有问题,帮忙给我指正一下,自己做的东西,有时候自己出于思维的定势,不容易发现错误的地方。。。。。。所以我写这些设计说明文档的一个目的,就是希望有朋友有兴趣看看,能够指出我的算法设计有什么问题。。。。大家一起来做出完善的算法来。。。。。

这篇文档,我写了很长时间,原因是因为在原来的算法里面发现一个错误,大家如果对比JWFDV0.96的代码包就会发现,在RRND算法里面,我对算法的认识和设计存在一个模糊的地方(RRDN函数里面,remove的应该是i还是1,我的认识有模糊的地方),我还没有完全把这个地方弄明白,所以算法设计文档一直都没有写下去。。。。。。。

要有什么改进的话,肯定是把这个算法再写得自动化一些,可以根据一个输入的节点号,返回任意我们希望获得流程拓扑结构的相应节点。。。当然,也可以把算法再简化一些,用C语言来实现,效率会更高一些,我没有做时间和空间复杂度的计算了。。。。懒惰的人啊。。

09年的时候,我写了一篇简单的算法说明,现在把这个算法的详细设计说明公布出来,方便大家查询,也方便我以后改进算法的时候使用,我为人人,人人为我。。。。。










收藏 推荐 打印 | 录入:admin | 阅读:
相关新闻