离线数仓—DWD层用户域事实表实现
前言
前面完成了流量域5张事务事实表的设计,下面继续进行DWD层用户域事务事实表的设计
一、用户域用户注册事务事实表
1.建表语句
DROP TABLE IF EXISTS dwd_user_register_inc;
CREATE EXTERNAL TABLE dwd_user_register_inc
(
`user_id` STRING COMMENT '用户ID',
`date_id` STRING COMMENT '日期ID',
`create_time` STRING COMMENT '注册时间',
`channel` STRING COMMENT '应用下载渠道',
`province_id` STRING COMMENT '省份id',
`version_code` STRING COMMENT '应用版本',
`mid_id` STRING COMMENT '设备id',
`brand` STRING COMMENT '设备品牌',
`model` STRING COMMENT '设备型号',
`operate_system` STRING COMMENT '设备操作系统'
) COMMENT '用户域用户注册事务事实表'
PARTITIONED BY (`dt` STRING)
STORED AS ORC
LOCATION '/warehouse/gmall/dwd/dwd_user_register_inc/'
TBLPROPERTIES ("orc.compress" = "snappy");
2.首日数据装载
set hive.exec.dynamic.partition.mode=nonstrict;
insert overwrite table dwd_user_register_inc partition(dt)
select
ui.user_id,
date_format(create_time,'yyyy-MM-dd') date_id,
create_time,
channel,
province_id,
version_code,
mid_id,
brand,
model,
operate_system,
date_format(create_time,'yyyy-MM-dd')
from
(
select
data.id user_id,
data.create_time
from ods_user_info_inc
where dt='2020-06-14'
and type='bootstrap-insert'
)ui
left join
(
select
common.ar area_code,
common.ba brand,
common.ch channel,
common.md model,
common.mid mid_id,
common.os operate_system,
common.uid user_id,
common.vc version_code
from ods_log_inc
where dt='2020-06-14'
and page.page_id='register'
and common.uid is not null
)log
on ui.user_id=log.user_id
left join
(
select
id province_id,
area_code
from ods_base_province_full
where dt='2020-06-14'
)bp
on log.area_code=bp.area_code;
首日数据装载语句说明:
1)首日装载时,日志表里的数据只有当天的,而业务数据库里的user_info中可能有多天的注册记录,所以可能会出现某些用户的一些信息为null的情况
2)从日志表中获取user的一些信息时,要选择type='bootstrap-insert’且page.page_id='register’且user_id不为null的信息,因为要的是注册信息,所以首先要拿的页面得是注册页面,然后有些人可能到了注册页面但是没有注册,所以要保证拿到的注册页面的user_id不为null
3.每日数据装载
insert overwrite table dwd_user_register_inc partition(dt='2020-06-15')
select
ui.user_id,
date_format(create_time,'yyyy-MM-dd') date_id,
create_time,
channel,
province_id,
version_code,
mid_id,
brand,
model,
operate_system
from
(
select
data.id user_id,
data.create_time
from ods_user_info_inc
where dt='2020-06-15'
and type='insert'
)ui
left join
(
select
common.ar area_code,
common.ba brand,
common.ch channel,
common.md model,
common.mid mid_id,
common.os operate_system,
common.uid user_id,
common.vc version_code
from ods_log_inc
where dt='2020-06-15'
and page.page_id='register'
and common.uid is not null
)log
on ui.user_id=log.user_id
left join
(
select
id province_id,
area_code
from ods_base_province_full
where dt='2020-06-15'
)bp
on log.area_code=bp.area_code;
二、用户域用户登录事务事实表
1.建表语句
DROP TABLE IF EXISTS dwd_user_login_inc;
CREATE EXTERNAL TABLE dwd_user_login_inc
(
`user_id` STRING COMMENT '用户ID',
`date_id` STRING COMMENT '日期ID',
`login_time` STRING COMMENT '登录时间',
`channel` STRING COMMENT '应用下载渠道',
`province_id` STRING COMMENT '省份id',
`version_code` STRING COMMENT '应用版本',
`mid_id` STRING COMMENT '设备id',
`brand` STRING COMMENT '设备品牌',
`model` STRING COMMENT '设备型号',
`operate_system` STRING COMMENT '设备操作系统'
) COMMENT '用户域用户登录事务事实表'
PARTITIONED BY (`dt` STRING)
STORED AS ORC
LOCATION '/warehouse/gmall/dwd/dwd_user_login_inc/'
TBLPROPERTIES ("orc.compress" = "snappy");
2.数据装载
登录表中的数据全部来自于日志中的数据,而日志里的数据不会存在多天的数据,每天的数据都是每天各自的数据,所以不用区分首日装载还是每日装载。
数据装载语句分析:
1)不能使用启动日志的原因:启动日志只有app端的日志信息,所以不能单独使用启动日志来获取登录数据。
2)如何获取登录数据:
登录数据要根据会话来进行划分,一次会话最多有一个登录操作,总共可能有以下这些情况:
第一种情况:一个人在浏览所有页面的时候从来都没有登录过,一直都处于访客模式,故一次会话中所有的user_id都为null,这种情况也就没有登录操作。
第二种情况:一个人在之前就已经登录过来,这次会话从开始到结束一直都有user_id,这种情况可以获取该次会话的第一条数据作为登录操作的数据。
第三种情况:一个人刚开始没有登录,后来进行了登录,所有这次会话前半部分user_id为null,后半部分user_id不为null,这种情况可以获取第一个user_id不为null的数据作为登录操作的数据。
insert overwrite table dwd_user_login_inc partition(dt='2020-06-14')
select
user_id,
date_format(from_utc_timestamp(ts,'GMT+8'),'yyyy-MM-dd') date_id,
date_format(from_utc_timestamp(ts,'GMT+8'),'yyyy-MM-dd HH:mm:ss') login_time,
channel,
province_id,
version_code,
mid_id,
brand,
model,
operate_system
from
(
select
user_id,
channel,
area_code,
version_code,
mid_id,
brand,
model,
operate_system,
ts
from
(
select
user_id,
channel,
area_code,
version_code,
mid_id,
brand,
model,
operate_system,
ts,
row_number() over (partition by session_id order by ts) rn
from
(
select
user_id,
channel,
area_code,
version_code,
mid_id,
brand,
model,
operate_system,
ts,
concat(mid_id,'-',last_value(session_start_point,true) over(partition by mid_id order by ts)) session_id
from
(
select
common.uid user_id,
common.ch channel,
common.ar area_code,
common.vc version_code,
common.mid mid_id,
common.ba brand,
common.md model,
common.os operate_system,
ts,
if(page.last_page_id is null,ts,null) session_start_point
from ods_log_inc
where dt='2020-06-14'
and page is not null
)t1
)t2
where user_id is not null
)t3
where rn=1
)t4
left join
(
select
id province_id,
area_code
from ods_base_province_full
where dt='2020-06-14'
)bp
on t4.area_code=bp.area_code;