用户行为分析系列实践 12 – 使用虚表
目标任务
用户事件表T结构和部分数据示例如下:
Time |
UserID |
EventType |
OS |
Browser |
ProductID |
… |
f1 |
f2 |
f3 |
f4 |
f5 |
… |
2022/6/1 10:20 |
1072755 |
Search |
Android |
IE |
100001 |
… |
true |
false |
false |
true |
false |
… |
2022/6/1 12:12 |
1078030 |
Browse |
IOS |
Safari |
100002 |
… |
false |
false |
true |
true |
true |
… |
2022/6/1 12:36 |
1005093 |
Submit |
Android |
Chrome |
100003 |
… |
true |
true |
true |
false |
false |
… |
2022/6/1 13:21 |
1048655 |
Login |
Windows |
Chrome |
… |
false |
false |
true |
true |
true |
… |
|
2022/6/1 14:46 |
1037824 |
Logout |
Android |
Edge |
… |
false |
false |
false |
true |
true |
… |
|
2022/6/1 15:19 |
1049626 |
AddtoCart |
Windows |
Edge |
100004 |
… |
true |
true |
false |
true |
false |
… |
2022/6/1 16:00 |
1009296 |
Submit |
IOS |
Firefox |
100005 |
… |
false |
true |
false |
false |
true |
… |
2022/6/1 16:39 |
1070713 |
Browse |
IOS |
Sogou |
100006 |
… |
true |
true |
true |
false |
false |
… |
2022/6/1 17:40 |
1090884 |
Search |
Windows |
IE |
100007 |
… |
true |
false |
true |
true |
false |
… |
T表字段说明:
字段名 |
数据类型 |
字段含义 |
Time |
日期时间 |
事件发生的时间戳,精确到毫秒 |
UserID |
字符串 |
用户ID |
EventType |
字符串 |
事件类型,取值为Login,Browse,Search,AddtoCart,Submit,Logout |
OS |
字符串 |
操作系统,取值为Android,IOS,Windows, ,Unknown |
Browser |
字符串 |
浏览器,取值为IE,Safari,Edge,Firefox,Chrome,Sogou,Unknown |
ProductID |
字符串 |
产品ID,取值为产品维表中的ProductID字段 |
… |
字符串 |
更多其它取值为枚举值的字段 |
f1 |
布尔值 |
是否异地发生,取值为真和假 |
f2 |
布尔值 |
是否惯用设备,取值为真和假 |
f3 |
布尔值 |
是否惯用浏览器,取值为真和假 |
f4 |
布尔值 |
是否是手机,取值为真和假 |
f5 |
布尔值 |
是否首次操作,取值为真和假 |
… |
布尔值 |
更多其它取值为真和假的字段 |
根据前面的章节(https://c.raqsoft.com.cn/article/1657716176800)介绍,把枚举字段和标签字段转换为对应的序号和位,转换后的用户事件组表T.ctx结构和部分数据示例如下:
Time |
UserID |
EventType |
OS |
Browser |
ProductID |
… |
b1 |
… |
2022/6/1 10:20 |
1072755 |
3 |
1 |
1 |
100001 |
… |
36864 |
… |
2022/6/1 12:12 |
1078030 |
2 |
2 |
2 |
100002 |
… |
14336 |
… |
2022/6/1 12:36 |
1005093 |
5 |
1 |
5 |
100003 |
… |
57344 |
… |
2022/6/1 13:21 |
1048655 |
1 |
3 |
5 |
… |
14336 |
… |
|
2022/6/1 14:46 |
1037824 |
6 |
1 |
3 |
… |
6144 |
… |
|
2022/6/1 15:19 |
1049626 |
4 |
3 |
3 |
100004 |
… |
53248 |
… |
2022/6/1 16:00 |
1009296 |
5 |
2 |
4 |
100005 |
… |
18432 |
… |
2022/6/1 16:39 |
1070713 |
2 |
2 |
6 |
100006 |
… |
57344 |
… |
2022/6/1 17:40 |
1090884 |
3 |
3 |
1 |
100007 |
… |
45056 |
… |
转换后的T表字段说明:
字段名 |
数据类型 |
字段含义 |
Time |
日期时间 |
事件发生的时间戳,精确到毫秒 |
UserID |
字符串 |
用户ID |
EventType |
整数 |
事件类型,取值为枚举序列中的序号 |
OS |
整数 |
操作系统,取值为枚举序列中的序号 |
Browser |
整数 |
浏览器,取值为枚举序列中的序号 |
ProductID |
字符串 |
商品ID,取值为维表中的ProductID字段 |
… |
… |
… |
b1 |
整数 |
整数字段,用位存储二值字段,其中的前五位分别对应是否异地发生,是否惯用设备,是否惯用浏览器,是否是手机,是否首次操作 |
… |
… |
… |
EventType枚举序列的序号和对应的文字说明:
1 Login
2 Browse
3 Search
4 AddtoCart
5 Submit
6 Logout
OS枚举序列的序号和对应的文字说明:
1 Android
2 IOS
3 Windows
4 Unknown
Browser枚举序列的序号和对应的文字说明:
1 IE
2 Safari
3 Edge
4 Firefox
5 Chrome
6 Sogou
7 Unknown
维表Product:
ProductName |
Unit |
Price |
ProductType |
|
100001 |
Apple |
Pound |
5.5 |
Fruits |
100002 |
Tissue |
Packs |
16 |
Home&Personalcare |
100003 |
Beef |
Pound |
35 |
Meat |
100004 |
Wine |
Bottles |
120 |
Beverage |
100005 |
Pork |
Pound |
25 |
Meat |
100006 |
Bread |
Packs |
10 |
Bakery |
100007 |
Juice |
Bottles |
6 |
Beverage |
… |
… |
… |
… |
… |
维表Product字段说明:
字段名 |
数据类型 |
字段含义 |
ProductID |
字符串 |
产品ID |
ProductName |
字符串 |
产品名称 |
Unit |
字符串 |
销售单位 |
Price |
数值 |
单价 |
ProductType |
整数 |
产品类别 |
表间关系说明图:
计算任务:
统计指定时间段内,产品类别为Home&Personalcare,本地使用安卓/苹果手机,使用Safari/ Edge/ Chrome,且非首次操作的用户,每个月在每种事件类型下的发生次数,以及去重用户数。
实践技能
关于虚表的相关知识可参考:
使用虚表实现计算列和外键的预定义,以及枚举维度和标签维度的简化书写:
1、 定义计算列Month,计算当前事件发生时间所在的月份
2、 定义EventTypeName、OSName、BrowserName伪字段,存储这些字段的序号和名称的对应关系
3、 在ProductID字段上定义和对应维表的外键关联关系
4、 在b1上定义每一位代表的字段名
定义完虚表后,可以利用虚表实现数据转储以及汇总统计,将极大地减少统计代码量。
示例代码
1、 定义虚表
A |
|
1 |
=T("Product.btx").keys@i(ProductID) |
2 |
=file("T.ctx").create(#Time,UserID,EventType,OS,Browser,ProductID,……,b1,……) |
3 |
=A2.close() |
4 |
=[{file:"T.ctx", column:[ {name:"Month",exp:"month@y(Time)"}, {name:"EventType",pseudo:"EventTypeName",enum:["Login","Browse","Search","AddtoCart","Submit","Logout"]}, {name:"OS",pseudo:"OSName",enum:["Android","IOS","Windows","Unknown"]}, {name:"Browser",pseudo:"BrowserName",enum:["IE","Safari","Edge","Firefox","Chrome","Sogou","Unknown"]}, {name:"b1",bits:["f1","f2","f3","f4","f5",…….]}, {name:"ProductID",dim:A1}] }] |
5 |
=pseudo(A4) |
A1 读入维表Product并设置主键和索引
A2 创建序号化及位维转化后的组表结构,写入空文件T.ctx(后续利用虚表直接将数据库的数据追加到此文件,不用再写序号和位的转换代码)
A3 关闭组表
A4 在组表T.ctx的基础上定义虚表:
{name:"Month",exp:"month@y(Time)"}定义计算列,列名Month,表达式month@y(Time)
{name:"EventType", pseudo:"EventTypeName", enum:[ "Login", "Browse", "Search", "AddtoCart", "Submit", "Logout"]}定义EventType字段值和枚举序列的对应关系,将对应的名称用伪字段EventTypeName表示
{name:"OS",pseudo:"OSName",enum:["Android","IOS","Windows","Unknown"]}定义OS字段值和枚举序列的对应关系,将对应的名称用伪字段OSName表示
{name:"Browser",pseudo:"BrowserName",enum:["IE","Safari","Edge","Firefox","Chrome","Sogou","Unknown"]}定义Browser字段值和枚举序列的对应关系,将对应的名称用伪字段BrowserName表示
{name:"b1",bits:["f1","f2","f3","f4","f5",…….]}定义位维度b1中每一位代表的字段名
{name:"ProductID",dim:A1}在字段ProductID上定义和维表A1的关联关系
A5 生成虚表
可以将虚表的定义串保存起来,后续每次使用时直接读取,进一步减少代码量。
2、 利用虚表进行数据的转储,SPL会自动根据虚表定义,将数据转换成对应的序号和位,存入T表中
A |
|
… |
/前面定义虚表的代码 |
6 |
=connect("demo").cursor@x("select * from T order by Time") |
7 |
=A5.append@i(A6) |
A6 连接数据库,读取T表数据并产生游标
A7 将游标数据读出追加到虚表中
3、 利用虚表做统计
A |
|
… |
/前面定义虚表的代码 |
6 |
>start=date("2022-03-15","yyyy-MM-dd"),end=date("2022-06-16","yyyy-MM-dd") |
7 |
=A5.select(Time>=start && Time<=end && ProductID.ProductType=="Home&Personalcare"&& ["Safari","Edge","Chrome"].pos(BrowserName) && ["Android","IOS"].pos(OSName) && ! f1 && f4 && !f5).groups(Month,EventTypeName; count(1):Num, icount(UserID):iNum) |
A7 利用虚表做汇总统计,其上定义的伪字段可以当成普通字段使用,不必再考虑存储和计算机制,将虚表当成简单的普通表即可
运行结果:
Month |
EventTypeName |
Num |
iNum |
202203 |
AddtoCart |
307603 |
29252 |
202203 |
Browse |
596492 |
58140 |
202203 |
Login |
672163 |
65569 |
202203 |
Logout |
672163 |
65569 |
202203 |
Search |
491317 |
42919 |
202203 |
Submit |
144552 |
13901 |
202204 |
AddtoCart |
615222 |
58484 |
202204 |
Browse |
1192970 |
116265 |
202204 |
Login |
1344323 |
131123 |
202204 |
Logout |
1344323 |
131123 |
202204 |
Search |
982637 |
85843 |
202204 |
Submit |
289112 |
27799 |
202205 |
AddtoCart |
615214 |
58484 |
202205 |
Browse |
1192976 |
116262 |
202205 |
Login |
1344339 |
131133 |
202205 |
Logout |
1344339 |
131133 |
202205 |
Search |
982633 |
85848 |
202205 |
Submit |
289108 |
27788 |
202206 |
AddtoCart |
307635 |
29256 |
202206 |
Browse |
596463 |
58124 |
202206 |
Login |
672175 |
65575 |
202206 |
Logout |
672175 |
65575 |
202206 |
Search |
491344 |
42929 |
202206 |
Submit |
144573 |
13887 |
英文版