`
何必如此
  • 浏览: 53579 次
社区版块
存档分类
最新评论

规则引擎Visual Rules Solution开发基础教程【连载5】--VisualRules深入了解

阅读更多
VisualRules深入了解


        通过前两篇的简单例子说明以及基础教程的描述,已经可以了解操作VisualRules的基本方法,以及VisualRules可以实现的主要功能。下面就程序员使用过程中,关心的一些深层问题,再此加以详细描述。

一、工作空间、工程、规则组、规则包区别

        工作空间下可以包含工程。工作空间只是一个定义文件。
        工程下可以包含规则组和规则包。工程是一个目录。
        规则组下可以包含规则组和规则包。规则组只是一个工程中的一个分类。
        规则包是一个完整的规则定义文件,所有的规则配置信息全在这个文件中,包括对象库配置信息以及规则定义信息。
        规则包也可以单独打开,单独打开后,就可以进行测试编译等工作。


二、对象库能传入的参数

        目前对象库中有几类参数:
        1.传入数据
                传入数据会在规则包执行前,定义成对应类型的变量。在规则包执行时,从外部缓冲区中取得和变量名称一样的对象,然后赋值给此变量。在规则包执行完毕后,在回传给外部的缓冲区。
        2.临时数据
                只在规则包执行前进行定义。
        3.外部调用
                直接在规则执行是调用。
        4.常量
                直接在生成的代码中定义。
        5.数据库对象
                只在规则包执行前进行定义。
        6.表格数据
                在规则包执行前进行定义。如果表格数据定义了保存数据的设置,则从对象库的定义中读取这些数据,传入到表格中。如果没有定义,则从外部传入的缓冲区中,取得同类型的对象,赋值到该表格中。在规则包执行完后,再更新到缓冲区中。
        7.Excel对象
                在规则包执行前进行定义。在规则包中,从缓冲区中将传入的Excel文件,读取到该对象中。执行过程中,直接对Excel文件进行了处理。
        8.SOAP对象
                在规则包执行前进行定义。
        9.XML对象
                在规则包执行前进行定义。根据XML对象的设置,如果设置成从外部传入,规则包执行时,先从缓冲区中读取该对象,然后赋值给该对象。如果设置成从文件中读取,则从指定的文件中读取。XML对象,会在规则包执行后,传回给缓冲区。
        10.数据树结构
                在规则包执行前进行定义。在规则包执行时,会先判断缓冲区中是否存在该名称的对象,如果有则赋值给该对象。在规则包执行完后,传回给缓冲区。

三、规则的处理机制

        规则是一个完整的逻辑单元,其基本结构是具有条件以及满足条件之后动作。这是规则引擎理论中最基本的判断单元。其基本结构就是这种 if then else的结构。具体的理论不在这里描述,VisualRules在处理这种基本结构时,为了用户操作更加简便,加入了更多的功能结构。规则除了支持基本的如果、那么、否则的基本结构之外,还支持初始化动作、否则如果、否则如果动作以及异常处理动作。
        初始化动作,可以在条件判断前,先做一些操作。对于某些应用来说,不用分开两个规则都加以定义。否则如果和否则如果动作,是用于定义不满足条件后,再进行条件判断的操作。对于某些雷同的处理,采用决策表定义又不太方便的情况下,就可以采用这种方式来进行定义。否则如果就是 else if的操作。
        在某些条件满足时,如果一个动作不能很好的表达完整,而是需要一连串的规则处理,则可以定义成规则集,并在规则集中设定条件。将此条件满足之后的操作,用多个规则来进行表达,并且添加到规则集下面。
        这样就可以实现子规则的操作,控制了规则流转。另外但规则集下面执行规则,如果只要满足一个条件,其他的条件就无需执行这样的情况时,则可以将规则集下面的规则,依次定义为互斥规则。这样当其中一个规则满足条件时,就会跳过后面规则的执行。
        如果有些规则,是需要循环进行执行的。则可以将规则集设置成循环类规则集,并且在规则集中定义循环的初始化、满足条件和步骤等操作。利用循环类规则,可以实现循环的操作。


四、内存表格的处理机制

        内存表格是VisualRules为了加快批量数据的处理方式,而实现的一种技术。一般数据大家都是通过复合SQL语句,从数据库中查询对应的结果集。这种方式比较简单,但是会极大的增加数据库的负担,使得执行速度很慢。同时有些批量的数据,也不适合放到数据库中进行存储,因为其结构有可能会发生变化。而数据库表其字段结构是不能轻易发生变化的。
        为了能够更快速的操作批量数据,VisualRules在规则引擎中实现了内存表格类,并且支持在规则配置器中,对其结构定义,并且在规则中对其进行操作。
        内存表格的基本结构是由列信息和表格数据组成的。列信息定义了表格的每一列的类型和名称,类似于数据库表的字段信息。表格数据是用 Object[][]这种二维数组的方式存储的结构,其中先将每一行数据存储在一个Object[]中,然后在将这些行存储在大的Object[]中。在操作内存表格时,基本分类两种类型操作。一种是批量操作,一种是逐行操作。
        批量操作是通过一个方法,对内存表格中所有的数据进行整体操作。包括导入数据、追加数据、更新数据、汇总数据等。这些又分为以下几种功能:


        1.从数据库表或者查询结果集中初始化数据
        这种方式会批量的删除掉内存表格中原先的数据,转而根据传入的数据库表或者查询结果集的数据,添加到内存表格中。追加数据时,一般根据字段的显示名以及表格列的显示名,来对应的更新数据。
        2.根据SQL语句直接初始化数据
        为了最大限度的提高导入从数据库导入数据的速度,可以直接通过SQL语句来初始化数据,这种方式不用再生成结果集。其数据是根据字段的名称和表格列的名称,来对应更新数据。
        3.根据数据库表和查询结果集来更新表格中数据
        根据数据库表和查询结果集,取得结果集中每一条记录,首先按照字段显示名和表格列的显示名对应的原则,找到在表格中对应的匹配的行,然后将对应的列按照记录中的值更新。
        4.根据数据库表和查询结果集追加计算表格中数据
        根据传入的数据库表或者查询结果集的数据,添加到内存表格中。追加数据时,一般根据字段的显示名以及表格列的显示名,来对应的更新数据。
        5.将计算表格的数据汇总
        将计算表格的数据汇总后,可以生成一个新的计算表格。所以汇总时需要制定汇总列、分组列和条件列。其中汇总列就是最后生成的新的计算表格中具有的列。这种方式非常类似于SQL查询语句。汇总列就是 select 后的字段,分组列就是 group by 后的字段,条件列就是where 后的各种条件设置。
        这里要说明的是,条件列不能像SQL一样使用括号,因此在这里的约定中,如果有 and和or的多个条件间的设置。 or的优先级比and的优先级要大,这一点和我们一般理解的不大一样,要特别注意。
        汇总后生成了新的表格后,这个表格必须作为参数传递到下面的根据表格导入数据的方法中,才能将数据保存下来。否则新生成的表格是无法访问的。

        6.将表格中的数据全部导入到当前表格中
可以将一个表格数据全部导入到当前表格中,这个方法一般会和上面的汇总方法联合使用,以便实现将汇总的表格保存下来。
        7.根据表格更新当前表格,需要指定更新列和匹配列
        根据表格来更新当前表格。这个方法一般和上面的汇总方法联合使用,以便直接根据汇总结果,来更新此表格的数据。
        8.根据设定关系将表格中的数据,导入到当前表格中
        设定了两个表格之间列的对应关系,按照这种对应关系,将此表格数据导入到当前表格中。分为追加导入和初始化导入,这是两个不同的方法。
        9.根据设定关系将表格中的数据,更新到当前表格中
        设定了两个表格之间列的对应关系,按照这种对应关系,找到匹配的列,然后将对应列的信息进行更新。
        逐行操作的原理是在计算表格内部,有个光标在设定当前指向那一行,光标可以逐行移动,或者直接跳转到某一行。只有光标移动到具体的行上时,才可以直接访问列的值。此次访问到的列的值就是光标所在行该列的值,可以直接对其进行存取操作。逐行操作的方法具有以下一些:

        (1)beforeFirst
                将光标放到第一行之前,这是需要依次逐行操作之前的动作。
        (2)next
                当光标放到下一行上,如果下一行有数据,则会返回正确。
        (3)first
                将光标放到第一行上,如果第一行有数据,则返回正确,否则返回错误。
        (4)last
                将光标放到最后一行,如果最后一行有数据,则返回正确,否则返回错误。
        (5)previous
                将光标放到上一行上,如果上一行有数据,则返回正确,否则返回错误。
        (6)afterLast
                将光标放到最后一行之前,这是需要依次从最后逐行向前操作之前的动作。
        (7)gotoRow
                直接跳到指定行上,如果该行有数据,则返回正确,否则返回错误。
        (8)getRows
        返回所有数据行的个数
        (9)getCurrentRow
                得到当前光标所在的行号。
        (10)insert
                在当前位置之后添加一行。添加之后,光标会制定到当前新添加的行。如果光标在第一行之前,则增加到第一行之前。
        (11)delete
                将光标当前指向的行删除。同时光标会指向其上一行。因此删除之后,仍然可以保证next操作的正常执行。


五、规则的内置循环操作

        对于一些需要逐行访问的对象,为了简化操作,可以设置规则的内置循环操作。当将规则设置成对某个对象进行内置循环时,首先会执行该对象的beforeFirst方法,然后循环执行next方法,并且在循环内部调用规则的执行。
        目前支持的循环对象包括内存表格对象以及数据树中的多节点对象。这两类对象都具有beforeFirst方法以及next方法。并且都是根据next之后,根据属性或列访问其内部值的。
        如果规则集设置了内置循环之后,那么规则集包含的所有的规则,也会包含在内置循环的next中。如果内置循环的规则集下面又有规则集或者规则其是内置循环的,那么就会在其里面在进行循环操作。
        在设置内置循环时,一定要注意其处理逻辑,轻易不要对表格进行insert和delete等操作。防止出现非法调用的事情发生。


六、Null对象的处理

        在实际的规则包运行时,如果数据为空,则容易出现nullException这种异常错误。一旦出现这种异常错误,规则包会终止运行,并且会说明发生异常的规则或者规则集。Null异常需要尽可能的避免。目前VisualRules的规则包执行时,已经进行以下的操作来规避这类错误:
        1.所有的常规类型定义都会进行初始化
        像String类型,会初始化为””;list类型,会初始化为 new ArrayList(0);map类型,会初始化为 new Hashmap(0)
但是date、datetime、time这些类型,初始化还是为null的。因此尽可能采用规则引擎提供的日期操作方法,而不要直接使用date类型自带的java方法。
        2.自带的判断方法等兼容null
        在规则的定义中的判断,比如String的等于、包含等等方法、以及日期等的方法。都是兼容null类型的。会将null定义为空。如果日期是null,则其表述的意思在规则包的属性中加以定义。
        另外注意,数据库的查询结果集,其读取的数据可能会有null的数据产生,因此要特别注意从数据库提取的数据的null的数据的发生。


七、数据库单表操作的功能

        VisualRules中对数据库的单表操作非常方便,基本的增加、删除、修改、替换、查询等功能很简便。以下描述这几种方法的实现原理:
        1.增加操作:
        对单表的增加,规则引擎是根据设置的值,生成一个insert的语句。因此在添加的时候,只需要设置需要赋值的字段的值。然后执行insert方法,就会自动生成一个insert语句,进行执行。执行后会返回添加的个数。
        2.删除操作
        对单表的删除,规则引擎也是根据设置的值,生成一个delete的语句。返回删除记录数。
        3.修改操作
        根据已经设置的值,首先规则引擎会根据该表的主键信息,生成update操作中的where部分,然后在根据其他字段设置的值,生成update部分。最后生成完成的update语句,进行执行。返回修改记录数。
        4.替换操作
        首先根据主键和其他字段的赋值信息,生成update语句进行执行,如果执行返回的修改记录数等于0,则再生成insert语句,进行执行。其效果就是如果存在记录则更新,不存在则添加记录。
        5.查询操作
        根据字段赋值的情况,将赋值的值生成where条件部分。然后生成一个select语句,其查询字段为所有该对象设置的字段信息,where部分就是赋值部分。然后通过执行select语句,来生成查询结果集。
        数据库表操作时,有几个技巧。一个是表的主键信息是自动从数据库表中取的,但是有时如果想批量更新数据,那么可以将这边设置的表的主键信息做一下调整,那么这样得到的update语句就是一个批量更新的语句。注意update语句只能生成这边设定的主键。
        在根据单表生成查询语句时,这种操作一般会希望简单的取某条记录的数据。但有些大数据的字段,会影响访问速度,因此可以在这里将其从结构中删除。这样在查询数据时,就不会查询这些暂时不需要取的字段。
        字段的类型,也可以做一些设置。某些值,在数据库中存储的是字符串,但是实际描述的意思可能是数值,因此可以将字段的类型定义成数值型。这样就便于取值间的操作。但是这个只在逐行取值是有用的,当设置成直接导出结果集时,是直接将数据库得到的原始类型,直接输出的,这样可以保证数据不会因为格式转化发生异常。


八、自定义查询的设置

        自定义查询是可以直接根据select语句,生成结果集。该结果集的类型可以分为以下四种:
        1.查询后既缓存全部结果集
        这是缺省的结果集读取方式,在执行完select语句之后,会根据resultset结果集,循环执行next,并且将记录存放在一个list中,保存起来。之后再访问此查询结果集时,就直接读取list了。这种方式可以最快的释放和数据库的连接。
        2.查询后逐条访问时缓存结果集
        这种方式在第一次执行完select语句之后,不会缓存结果值,之后当开始next时,才依次将字段以list的形式保存下来。一旦访问过一次之后,第二次再访问时,就是直接去list中的值了。
        3.不缓存结果集,也不支持后退
        这种方式是最快的读取数据库的方式,同时读取的值仍然存储在resultset中,对其操作都是对next的操作。由于前两种比较消耗内存,因此这种方式是能显著提高查询性能的功能。
        4.不缓存结果集且支持后退
        这种方式和上一种方式类似,只是查询的类型是支持游标的。因此在getRows时可以得到正确的值。
        同时为了使查询可以支持分页,因为分页在数据库级别的话,对于大数据量结果集的查询是非常有效果的。这种方式一般根据数据库的不同,会有所不同,比如一般的数据库,会先执行一个count(*),取得了总记录数。然后如果是Mysql,则执行 limt,如果是Oracle,则执行rownumber方法,如果是SQL Server,则使用top。取得指定页数的结果集。
        在自定义查询中有两个方法:
        设置该月工资表的排序字段为{arg1},方向为{arg2}
        设置该月工资表分页页码为{arg1},每页数为{arg2}
        这两个方法就用于设置查询排序以及分页读取数据的操作。
        如果设置了分页之后,那么取总个数,需要根据getCount方法来得到。


九、数据库表本地内存缓存

        数据库访问一直是提高性能的一个重要考虑,如何使得数据库访问的次数更少,是系统优化的主要方式。因此对于一些变更不大频繁的表,可以通过本地内存缓存的方式,来加快系统的执行。
        将表的结果集类型设置成“本地缓存表数据”,这样就能在访问此表时,系统会同时更新本地内存的表。其他通过单表进行查询时,就会以这个本地内存为主来进行执行了。


十、数据库表结构更新

        当数据库表结构发生变更时,很多时候不一定了解究竟在那些地方应用了这些表结构,因此需要有系统自动来识别那些应用的数据库操作会发生异常。
        点击工程中的所有表操作,然后点击更新按钮,系统会自动将该工程中所有的sql查询以及表访问一遍。如果发现查询SQL语句无法执行,或者表的字段已经和数据库中的实际字段信息不匹配,会以红色的标记来说明这些对象已经有问题。因此建议进行修改。
        双击这个需要修改的数据库对象,会直接转到该对象的修改界面。如果是表,则直接点击右键,选择“和数据库同步”就行了,系统会自动根据数据库实际来进行更新。如果是查询,则需要手工修改SQL语句。


十一、规则执行轨迹的原理

        通过规则配置器来设置后台处理逻辑,由于全部采用配置方式实现,因此不能像代码一样可以在编辑器中进行调试跟踪。当发生错误时,为了能够查看到究竟在哪一步出现了问题,因此就需要查看规则的执行轨迹以及执行结果。
        规则的执行轨迹,是对系统的传入传出变量以及临时变量的记录,在每个规则执行时,如果这个规则的初始化动作或者满足条件动作,或者不满足条件动作执行时,系统会将规则执行前的变量的情况记录下来,然后在规则执行完毕后,在记录这些变量改变之后的值。
        这样可以知道规则改变了那些变量,以及那些变量的值发生了变更。
        同时还可以以更加简便的方式,单独对某一步的执行,进行拍照操作。
1
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics