【性能优化】8.5 [多维分析] 标签位维度
8.5 标签位维度
标签维度是指取值只有是与否(或 true/false)两种的枚举维度,比如人员是否结婚、是否上过大学、是否拥有信用卡、…,也称二值维度。标签维度很常见,对客户、事物贴标签是当前数据分析的重要手段。标签维度很少用于分组统计,通常用于切片条件。
现代多维分析的数据集常常会有几百甚至上千个标签维度,如果将这种维度当作普通字段处理,无论是存储还是运算都会造成很多浪费,难以获得高性能。
标签维度只有两种取值,只要一个位就可以存储了。一个 16 位的小整数可以保存 16 个标签,原本要用 16 个字段来存储的信息用一个字段就够了,这种存储方式称为标签位维度。这将大幅度减少存储量也就是硬盘读取量,而且小整数也不影响读取速度。
A |
|
1 |
=file("T.ctx").open().cursor() |
2 |
=file("T_new.ctx).create(…) |
3 |
=n.("tag"/~).group((#-1)\16).("bits@b("/~.concat@c()/"):bits"/#) |
4 |
=A1.new(…,${A3.concat@c()}) |
5 |
=A2.append@i(A4) |
设 n 是标签维度的个数,标签维度命名为 tag1,tag2,…的形式,A3 将生成 new 函数的部分参数,用来将这些常规的布尔标签维度转换成用位表示的数据,每 16 个标签组成成一个小整数,分别命名为 bits1,bits2,…。bits1 就对应了原来的 tag1,tag2,…,tag16,bits2 对应了 tag17,…,tag32,以此类推。这里为简单起见假定 n 是 16 的倍数。A4 中 new 的…部分是其它的字段,照抄出来即可。
现实情况的字段命名和排名方式可能不一样,标签维度的数量也可能不是 16 的倍数,但都可以以此为例改写出变换代码。
标签维度的切片条件通常有多个,将取出这些标签维度值都是 true 的记录,转换成标签位维度的说法,就是选出使这些标签位同时为 1 的记录。这种判断也可以用位运算完成。
A |
|
1 |
=file("T_new.ctx").open() |
2 |
=tags.splits@c().(int(mid(~,4))-1).group@n(~\16+1) |
3 |
=A2.(~.sum(shift(1,~%16-15))) |
4 |
=A3.pselet@a(~>0) |
5 |
=A4.("and(bits"/~/","/A3(~)/"=="/A3(~))) |
6 |
=A1.cursor(…;${A5.concat("&&")}) |
7 |
=A6.groups(…) |
条件 tags 是一个由标签字段名构成的逗号分隔的串,如“tag3,tag8,tag23”即表示要选出这三个标签维度为真的数据。A2 解析出序号并分组,每组对应一个新的标签位维度,A3 计算中出每组对应的标签位维度应该有的值,比如 tag3 和 tag8 会分到一组中,对应 bits1,A3 中计算出来的对应数值为二进制数 0010000100000000(第 3 个和第 8 个为 1),A4 取出其中不为 0 的序号,也就是需要做判断的位维度序号(为 0 的不用判断),再在 A5 把这些值转换成针对标签位维度的条件,比如 tag3,tag8 对应的这一组条件为
and(bits1,8448)==8448
(132 是刚才那个二进制数的十进制)
and 函数是位上的与运算,可以判断出 bits1 的第 3 位和第 8 位是否都是 1,对应到原标签,也就是 tag3 和 tag8 是否都为 true。一次即可以完成两个标签条件的判断。
标签位维度有效减少了存储量,在大多数情况下还可能把多标签的判断合并成一个位维度,对性能提升明显。对于内存的计算,这种可以大幅减少内存的占用以及一定程度减少判断量的方法也很有意义。