用户行为分析系列实践 1 - 常规分组统计
目标任务
用户事件表T结构和部分数据示例如下:
Time | UserID | EventType |
2022/6/1 10:20 | 1072755 | Search |
2022/6/1 12:12 | 1078030 | Browse |
2022/6/1 12:36 | 1005093 | Submit |
2022/6/1 13:21 | 1048655 | Login |
2022/6/1 14:46 | 1037824 | Logout |
2022/6/1 15:19 | 1049626 | AddtoCart |
2022/6/1 16:00 | 1009296 | Submit |
2022/6/1 16:39 | 1070713 | Browse |
2022/6/1 17:40 | 1090884 | Search |
T表字段说明:
字段名 | 数据类型 | 字段含义 |
Time | 日期时间 | 事件发生的时间戳,精确到毫秒 |
UserID | 整数 | 用户ID |
EventType | 字符串 | 事件类型 |
计算任务:
统计指定时间段内每种事件类型下的发生次数和发生过该事件的去重用户数
实践技能
1、 使用二进制文件存储替代数据库存储
2、 遍历中使用并行
示例代码
1、使用二进制文件转储数据库的数据
存量数据:从数据库中读出,写入集文件:
A | |
1 | =connect("demo").cursor@x("select * from T") |
2 | =file("T.btx").export@b(A1) |
A1 连接数据库,读取T表的数据,产生游标,@x选项表示读完后自动关闭数据库连接
A2 将A1中的数据写入T.btx集文件中,用@b表示写成二进制文件。
增量数据:如果有新数据要追加到已经生成的集文件中,可以在SQL中用过滤条件筛选出来,用@a选项把数据追加到集文件里。
用时间戳来识别增量数据,每天0点以后,把前一天的增量数据追加到集文件里:
A | |
1 | =connect("demo").cursor@x("select * from T where Time>=? && Time<?",date(now()-1), date(now())) |
2 | =file("T.btx").export@ba(A1) |
A1 通过过滤条件筛选出前一天的数据,产生游标
A2 将A1中的数据通过游标读出追加到T.btx集文件中,@a表示追加,无此选项则是重写
2、针对集文件做分组汇总
设统计时间段为2022年3月15日到2022年6月16日:
A | |
1 | =file("T.btx").cursor@mb() |
2 | >start=date("2022-03-15","yyyy-MM-dd"),end=date("2022-06-16","yyyy-MM-dd") |
3 | =A1.select(Time<=end && Time>=start).groups(EventType; count(1):Num, icount(UserID):iNum) |
A1 对集文件"T.btx"产生游标,@m表示多路游标,用于并行计算,缺省的并行数在集算器的raqsoftconfig.xml中设置,也可以直接写成f.cursor@m(n),这里n表示并行数。一般来说并行数不要超过机器的CPU核数,否则可能更慢。
A2 产生start,end两个变量,用于对时间戳进行过滤,实际使用时这俩变量通过参数传进来
A3 对A1中的游标进行过滤和分组汇总,分组字段是EventType,count(1)是简单计数,icount(UserID)是统计UserID不重复的个数。这里强调一点,不管对游标进行多少次操作,比如多次过滤、排序、分组等等,最后执行的时候都是一次性执行的,即只会取一次数遍历一次,就算出最终结果。
运行结果:
EventType | Num | iNum |
AddtoCart | 1845674 | 175476 |
Browse | 3578901 | 348791 |
Login | 4033000 | 393400 |
Logout | 4033000 | 393400 |
Search | 2947931 | 257539 |
Submit | 867345 | 83375 |
英文版