[基础工具]离线数据立方体构建工具

来源:互联网 发布:社交网络无字幕版 编辑:程序博客网 时间:2024/06/05 18:08

1. 背景

在数据的实际使用过程中,我们经常需要进行多维度的组合汇总,做一个数据立方体。常见的方法是在各个维度下进行group by,建立多个任务,这样不利于代码查看和维护,同时也浪费开发时间。

数据立方体与OLAP:http://webdataanalysis.net/web-data-warehouse/data-cube-and-olap/

2. 数据立方体

业务场景

有一张数据表的结构如下

字段名 字段类型 注释 fserver_ip string 服务器ip finterface string 服务接口名 ferror_code string 错误码 fcall_num int 接口调用次数 fcall_time int 接口调用耗时

现在有一系列的查询需求

  1. 查看服务器ip、服务接口名、指定错误码下的接口调用次数、接口调用总耗时;
  2. 查看服务器ip下所有的接口调用次数、接口调用总耗时;
  3. 查看错误码下所有的接口调用次数、接口调用总耗时;
  4. 查看服务器ip、错误码下所有的接口调用次数、接口调用总耗时;

……

上面各种查询需求,都是针对不同维度进行组合统计的,用最笨的办法,可能需要写一堆group by xxx,但通过建立数据立方体,就可以在对某个(些)维度进行汇总统计时进行上卷等操作。

问题简化

建立数据立方体之前,先要明确需要处理哪些维度、指标。下面是一个数据立方体


维度 指标 排列组合 fserver_ip finterface ferror_code sum(fcall_num) sum(fcall_time) 不组合(明细)




维度1组合 ✔️

维度2组合
✔️


维度3组合

✔️

维度12组合 ✔️ ✔️


维度13组合 ✔️
✔️

维度23组合
✔️ ✔️

维度123组合 ✔️ ✔️ ✔️

问题分析

实际上对于每个维度而言,是“组合”与“不组合”两种可能,因此 M 个维度对应的组合数是 2M(或从排列组合角度,维度的组合数 = C0M+C1M+C2M+...+CMM=2M

3. 构建数据立方体

本文将使用hive streaming + python构建数据立方体

Hive Tranform方式的官方文档:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Transform

img_001

如上图,hive streaming方式实际上是将hive sql查询的记录,逐条传递给jar/python等进行处理。构建数据立方体的过程,是需要对每条明细数据处理2M 次来生成各种维度组合,处理过程如下

img_002

3.1. Python代码

cube.py

def binary_reflect_gray_code(n):    """    生成n位的二进制反格雷码, 即n个元素的全组合    :param n:    :return:    """    if n == 1:        return ["0", "1"]    L1 = binary_reflect_gray_code(n-1)    L2 = copy.deepcopy(L1)    L2.reverse()    L1 = ["0" + l for l in L1]    L2 = ["1" + l for l in L2]    L = L1 + L2    return Lif __name__ == "__main__":    not_group_set = []    if len(sys.argv) < 4:        print 'Error! Not Enough Params.'        print 'Usage: python cube.py <field_num> <dimension_num> <> <not_group_set>'        sys.exit(1)    elif len(sys.argv) > 4:        _, field_cnt, dimension_cnt, split_sign = sys.argv[0:4]        not_group_set = sys.argv[4:]    elif len(sys.argv) == 4:        _, field_cnt, dimension_cnt, split_sign = sys.argv[0:4]    combination_list = binary_reflect_gray_code(dimension_cnt)    for line in sys.stdin:        kv = line.replace('\n', '').split('\t')        for combination in combination_list:            if combination not in not_group_set:                for item in range(int(field_cnt)):                    if item < int(dimension_cnt):                        if combination[item] == '0':                            print '%s\t' % (kv[item]),                        else:                            print '%s\t' % (split_sign),                    else:                        print '%s\t' % (kv[item]),                print

3.2. 参数说明

参数 是否必传 样例 注释 参数1 √ 5 指的是传入TRANSFORM的列数 参数2 √ 3 指的是前几列是维度,故而需要把维度放在前面 参数3 √ all 指的是汇总列替代的值,比如all 参数4-n 选填 00 01 10 指的是不需要维度汇总的组合,支持多个组合。比如不需要第一列汇总,则写10和11(两位数字表示维度数为2,其中第一位1表示按第一个维度汇总,比如指定了10,则表示过滤按第一列汇总的数据)

3.3. 使用说明

1) 新建文件cube.sql,添加如下HQL脚本

add file cube.py;select  fserver_ip,  finterface,  ferr_code,  sum(fcall_num) as fcall_num,  sum(fcall_time) as fcall_timefrom (  from dp_monitor.t_monitor_acc  select TRANSFORM(fserver_ip, finterface, ferr_code, fcall_num, fcall_time)  using 'python cube.py 5 3 all' as  fserver_ip, finterface, ferr_code, fcall_num, fcall_time where fdate = '2017-10-16') tmpgroup by fserver_ip, finterface, ferr_codeorder by fserver_ip, finterface, ferr_code;

2) 使用hive命令行执行HQL脚本

hive -f cube.sql

3.4. 如何进行本地测试

本地导出数据进行测试:

hive -e "select fserver_ip, finterface, ferr_code, fcall_num, fcall_time from dp_monitor.t_monitor_acc where fdate = '2017-10-16' limit 100" > a.txtcat a.txt | python cube.py 5 3 all

3.5. 性能效率

假设:

  • 维度数 = M(0 < M < 102),脚本会先生成 M 位的二进制组合,M 位的二进制组合共有 2M 个;
  • 表数据 = N(0 < N < 1010),脚本会逐条数据进行处理,每条数据会处理 2M 次;

时间复杂度为:

O(N2M)

原创粉丝点击