数据仓库实践杂谈(十八)——关于报表

[目录]

  • 第一章:概述
  • 第二章:整体数据分层
  • 第三章:整体实现框架
  • 第四章:元数据
  • 第五章:ETL
  • 第六章:数据校验
  • 第七章:数据标准化
  • 第八章:去重
  • 第九章:增量/全量
  • 第十章:拉链处理
  • 第十一章:分布式处理增量
  • 第十二章:列式存储
  • 第十三章:逻辑数据模型(数仓模型)
  • 第十四章:数据模型参考
  • 第十五章:维模型
  • 第十六章:渐变维
  • 第十七章:数据回滚
  • 第十八章:关于报表
  • 第十九章:数据挖掘

数据仓库实践杂谈(十八)——关于报表

报表绝对是让人痛苦的东西。格式复杂、需求多变,没事就增加几个。虽然说起报表感觉很老土,但确实是需求量最大的一个东西。貌似做报表多的人,基本上都会做一个自己的工具,至少也会做一个引擎,按照自己的理解用一种结构化加动态的方式去定义所需要的报表,可以灵活的选择所需要的数据,设计展现样式生成报表。

当年有幸开始给银行做报表,一不小心做了很多年,也算是总结出一套报表处理的机制。

结合前面谈到的数据分层的机制,会发现,不管基于哪一层,都有做报表的需求。

数据仓库实践杂谈(十八)——关于报表_第1张图片

可以看出ETL数据处理的路径并不是一条直线往下走这么简单。更说明从基准的数据做报表的话,需要数据库和报表工具相结合。
报表定义的核心要素包括:

数据源的定义

良好的报表工具应该支持多个、多种数据库,而在实际应用中,还增加了直接读excel,通过url拿数据;到了大数据时代,当然要增加HIVE、SPARK等数据源了。

数据字典映射定义

数据保存的时候基本上各种分类、状态等都是以内部代码形式保存的,实际上在交互式的报表中,这种内部代码也是有用的——可以用于关联下一个报表的参数等;但在报表展示的时候需要呈现其含义,如代码01对应含义为“正常”类贷款。一般有两种做法:

  • 数据表中每个分类字段都带有分类含义字段,如贷款状态代码F1和贷款状态说明F2两个字段,生成报表的时候,两个字段都需要拿出来,隐藏F1,显示F2。
  • 数据表中只需要保存F1,单独定义一个映射集合,在展现报表的时候用这个集合来替换。

无论如何,别用SQL在数据库中联查,你会想死的。

数据定义

确定报表展示需要的数据已经对数据的加工。为啥要专门做一个报表处理引擎或者服务呢,主要就是认为数据库里面存放的结构和最终展现的报表是存在差异的,而且可能还很大差异;因此需要从数据库中拿出“粗加工”过的数据,到报表服务中进行“精加工”,数据定义应该包括:

  • 取数逻辑,一般可以用SQL,每一个取数逻辑定义出一个表格;可以支持多个表格;
  • 数据声明,如果数据需要“精加工”的话,就得对数据进行声明,比如数据类型,是否作为表头,使用字典映射集合替换等;
  • 数据加工:可以提供相应的函数,实现比如表格合并、转置、分组、调平,可以支持脚本自定义处理逻辑;

样式及样式模板

简单的样式可以通过形式化来定义,比如对齐方向,颜色,字体字号等;复杂展现样式可以通过模板来实现,有很多很好的基于HTML的模板实现,数据按照特定的格式输出(比如JSON)可以渲染出需要的布局和样式。某些特殊的样式,跟数据相关,比如大于某值用红色等,则可以用脚本来实现。

数据结构

为了实现数据的灵活处理和展现,设计了一套数据结构用以保存/加工通过SQL等手段从数据库提取出来的数据。这个数据结构的核心是一个表格Sheet,起特点是基于十字链表+数组索引。

Sheet结构如下:

数据仓库实践杂谈(十八)——关于报表_第2张图片
数据主体由一组Cell对象组成,Cell对象指向其上下左右四个方向的Cell,形成十字链表。这样,从任意一个Cell,都可以快速访问上一行、下一行、前一个、后一个的Cell。首行与首列增加一个数组/List作为行/列的索引。这样设计有几个原因:

  • 基于整行(合计/分组合计)和整列(函数/四则运算等)在数据库用SQL计算非常高效方便,充分利用SQL的能力在数据库事先做计算量大的工作是好的习惯;
  • “相邻”计算在报表层面很多,比如,把邻近的Cell(上下左右)合并,还有对某行或某列进行逐个对比,插入一行/一列平均起来操作比对数组操作效率高,表格的转置只需要更换行列索引等。

综合起来看由于考虑的是已经从数据库中拿出来到内存的数据,本质上就不能当做数据库中那种行列分明的模式(一行一个数组或者一列一个数组),而应该等同对待,毕竟这种精细化的处理,对行的处理和对列的处理几率同样大。

数据坐标

要处理数据,就需要一套坐标来定义需要处理的对象。经过考察,决定利用Excel的A1坐标体系,能便捷的定义一个点、一行、一列或者一个矩阵区域。比如:

  • 表示点:A1表示(0,0),B2表示(1,1),列标识和行标识直接连接在一起表示一个点;
  • 表示列:单独使用字母表示一列,如A表示第一列,B表示第二列,两个字母中间用冒号连接,如A:B表示第一和第二列组成的区域;
  • 表示行:单独使用数字表示一行,如1表示第一行,在坐标系中,则是0行,两个数字中间用冒号连接,如1:2表示第一和第二行组成的区域;
  • 表示区域:用两个点坐标,中间用冒号连接,表示左上角和右下角所确定的矩形区域;
  • 自动符号%:%作为自动符号,当处在列的位置的时候,表示最后一列的序号,当处在行的位置的时候,表示最后一行的序号,如A1:%%表示从(0,0)点到整个表格右下角的区域,包含整个表格的所有单元格。

样式集合

前面提到过样式是有可能跟数据关联的。比如通过计算值大于多少用红色,小于多少用绿色。计算出来的颜色属性需要保存起来。

数据仓库实践杂谈(十八)——关于报表_第3张图片

简而言之,就是具备此类样式属性的Cell一般不会很多,因此不需要每个Cell都带一个样式集合,而统一放到一个样式集合中,省点空间,也保持数据对象的纯洁性。

总结

其实这个报表设计是很多年前做的。后来发现了某报表厂家开始推出的时候,也用了类似的数据结构,让我还挺欣慰。报表确实想用一个形式化的标准来表达,确实挺难的。针对定义把数据跑出来,其实倒是简单了。但确实也经历了一些有意思的事情。比如当年在人民银行的一个统计系统,跑了一个月之后,客户跟我反馈说经常报内存溢出。过去看看,发现他们的服务器内存太小了,GC来不及释放。而且当时我对最后的报表结果做了序列化放在一个数组里面,导致虽然有内存,但没有足够大的连续内容。只好给改成了一个链表数组,分段输出,才解决了。之后就没关于内存的事情找我了。

未完待续。

上一篇:数据仓库实践杂谈(十七)——数据回滚

上一篇:数据仓库实践杂谈(十九)——数据挖掘

你可能感兴趣的:(数据仓库实践,数据库,大数据,java,链表,数据分析)