如何在报表中实现算法的可挂接需求

在报表项目中,有些报表中部分数据的计算方法会经常改变。例如:某企业员工的实际工资是通过绩效得分计算出的,而绩效的算法可能经常变动,需要在不改动其他代码的情况下用新算法替换旧算法。一般我们都会想到用 Java 来实现计算,从而实现动态可挂接计算模块,但是这种方式可能存在缺乏基础类库、占用多余内存等问题。

这里我们介绍一种可以实现低耦合、热部署的动态挂接算法,使得解决此类问题更具结构性优势,这就是结合集算器使用润乾报表。下图对比了润乾报表实现的可挂接算法和其他报表工具 +java 实现可挂接算法的在系统结构上的差异:

imagepng

可以看出,java 程序必须要编译、打包才能更新,无法实现热部署。而集算脚本是解释执行的,脚本文件同时也是可执行文件,所以可以直接进行替换更新。同时,集算脚本可以和报表模板成对存放,在代码管理上更为清晰、便利。

下面就用员工绩效工资的例子来说明润乾报表的实现方法,并和其他报表工具 +Java 的实现方式做一下比较。

员工绩效工资报表如下:

imagepng

报表格式比较简单,但是计算方法相对复杂,而且经常变动,算法部分需要动态挂接才能满足需求。

具体实现步骤如下:

1、编写集算器脚本

A B C
1 =connect("demo")
2 =A1.query("select p.EMPLOYEEID as empID, p.EVALUATION as score,e.dept as dept, e.NAME as empName,p.BONUS as baseSalary  from performance as p,employee as e where p.EMPLOYEEID=e.EID  and e.gender=?",gender)
3 =A2.derive(PRETAX)
4 =sales=A3.select(DEPT=="Sales")
5 for sales if A5.BASESALARY<2000 >A5.PRETAX=A5.BASESALARY*(1+A5.SCORE/100)
6 else if A5.BASESALARY<4000 >A5.PRETAX=A5.BASESALARY*(1+A5.SCORE*0.9/100)
7 else if A5.BASESALARY<6000 >A5.PRETAX=A5.BASESALARY*(1+A5.SCORE*0.8/100)
8 else >A5.PRETAX=A5.BASESALARY*(1+A5.SCORE*0.6/100)
9 =normal=A3.select(DEPT!="Sales")
10 =A9.run(PRETAX=BASESALARY)
11 =sales|normal
12 =A11.new(EMPNAME,BASESALARY,PRETAX) >A1.close()
13 result A12

A2 单元格有个输入参数 gender,来自于查询页面。A13 单元格是将结果返回给报表页面。A2 到 A12 之间是绩效工资的计算方法,具体算法不是本文重点,这里不详细介绍,只要知道这部分可以随时替换就可以了。

2、配置报表数据集

润乾报表的报表模板可以定义集算器数据集来调用可挂接计算模块:

imagepng

其中,gender 参数是 dynamic.dfx 的输入参数,数据集 ds1 接收 dynamic.dfx 返回的结果集。

可以看到集算器脚本 dynamic.dfx 和报表模板之间的耦合程度非常低。如果要改变绩效工资的计算方法,只需要编写一个新的 dynamic.dfx,替换服务器上原有的 dfx 文件即可。因为 dfx 脚本是解释执行的,所以可以不停机替换,实现真正的热部署。

3、设计报表模板

在润乾报表设计器中像使用普通数据集一样设计报表模板即可。如下图所示:

imagepng

从这个例子可以看出润乾报表实现的可挂接算法,相比普通报表工具 +Java 的实现方式有多方面的优势。

1、dynamic.dfx 可以使用润乾报表提供的多种函数方法:分组、汇总、排序、过滤、关联、唯一值、交集、排名等等。Java 程序员必须手工编写这些基础算法。而将这些基础算法直接实现在业务逻辑中显然是不合理的,因为这会导致每个计算模块重复书写类似的代码,使得计算模块过于庞大、可读性变差。理想的作法是先实现一套基础算法类库,再在计算模块中调用,而应用程序员很难设计出完备性和系统性优秀的基础算法类库,因此常常使代码的耦合性高,稳定性差,最终导致计算模块维护困难。

润乾报表的集算引擎本身就是这样一套精心设计的完备基础类库,经过简单的学习,应用程序员只需要 JAVA 十分之一的代码量就可以实现同样功能的计算模块,开发效率更高。

2、JAVA 代码需要重新编译,部署起来比较麻烦;当可挂接的计算模块较多时,不论是否还要使用它们,这些 Java class/jar 都会占据内存空间而无法释放,对性能有一定的影响。

润乾报表的集算器引擎和脚本文件是分开的,耦合性很低,维护起来更加方便。另外,集算脚本无需编译即可使用,是真正的热部署。脚本程序不会事先加载到内存,而是使用时再加载,计算完立刻释放,不会长期占用内存。