基于Apache的电商数据仓库(五)
欢迎
你好!这是我历经1个半月的学习(Apache和CDH),做完的一个项目,本次和你们分享一下Apache版。
感谢您的阅读!
第1章~第4章在基于Apache的电商数据仓库(一)
第5章~第5章在基于Apache的电商数据仓库(二)
第6章~第8章在基于Apache的电商数据仓库(三)
第8章~第9章在基于Apache的电商数据仓库(四)
第10章~第12章在基于Apache的电商数据仓库(五)
第13章~第13章在基于Apache的电商数据仓库(六)
第14章~第14章在基于Apache的电商数据仓库(七)
第10章 DWS层搭建
10.1 用户活跃主题
- 10.1.1 每日活跃设备明细
- 建表
create external table dws_uv_detail_day
(
`mid_id` string COMMENT '设备唯一标识',
`user_id` string COMMENT '用户标识',
`version_code` string COMMENT '程序版本号',
`version_name` string COMMENT '程序版本名',
`lang` string COMMENT '系统语言',
`source` string COMMENT '渠道号',
`os` string COMMENT '安卓系统版本',
`area` string COMMENT '区域',
`model` string COMMENT '手机型号',
`brand` string COMMENT '手机品牌',
`sdk_version` string COMMENT 'sdkVersion',
`gmail` string COMMENT 'gmail',
`height_width` string COMMENT '屏幕宽高',
`app_time` string COMMENT '客户端日志产生时的时间',
`network` string COMMENT '网络模式',
`lng` string COMMENT '经度',
`lat` string COMMENT '纬度'
)
partitioned by(dt string)
stored as parquet
location '/warehouse/gmall/dws/dws_uv_detail_day';
- 分析
需求
一、 活跃用户:
① 用户: 每个设备作为一个用户!mid号是用户的相关标识!
②活跃: 打开了应用,称为活跃用户!只要打开了应用,此时会产生启动日志信息!
二、每日活跃设备明细:求每天的活跃设备明细,因此表应该是一个按照日期分区的分区表
明细: 需要把cm字段的所有数据都写入到此表中
相关表
从dwd_start_log启动日志表中取数据
思路
从dwd_start_log中查询数据时,需要根据mid号进行去重,将同一个设备产生的多条明细信息去重后再拼接,一个设备在表中以一行存在
- sql
insert overwrite table gmall.dws_uv_detail_day PARTITION(dt='2021-02-08')
SELECT
mid_id,
concat_ws('|',collect_set(user_id)) user_id,
concat_ws('|',collect_set(version_code)) version_code,
concat_ws('|',collect_set(version_name)) version_name,
concat_ws('|',collect_set(lang)) lang,
concat_ws('|',collect_set(source)) source,
concat_ws('|',collect_set(os)) os,
concat_ws('|',collect_set(area)) area,
concat_ws('|',collect_set(model)) model,
concat_ws('|',collect_set(brand)) brand,
concat_ws('|',collect_set(sdk_version)) sdk_version,
concat_ws('|',collect_set(gmail)) gmail,
concat_ws('|',collect_set(height_width)) height_width,
concat_ws('|',collect_set(app_time)) app_time,
concat_ws('|',collect_set(network)) network,
concat_ws('|',collect_set(lng)) lng,
concat_ws('|',collect_set(lat)) lat
FROM gmall.dwd_start_log
where dt='2021-02-08'
group by mid_id
- 10.1.2 每周活跃设备明细
- 建表
create external table dws_uv_detail_wk(
`mid_id` string COMMENT '设备唯一标识',
`user_id` string COMMENT '用户标识',
`version_code` string COMMENT '程序版本号',
`version_name` string COMMENT '程序版本名',
`lang` string COMMENT '系统语言',
`source` string COMMENT '渠道号',
`os` string COMMENT '安卓系统版本',
`area` string COMMENT '区域',
`model` string COMMENT '手机型号',
`brand` string COMMENT '手机品牌',
`sdk_version` string COMMENT 'sdkVersion',
`gmail` string COMMENT 'gmail',
`height_width` string COMMENT '屏幕宽高',
`app_time` string COMMENT '客户端日志产生时的时间',
`network` string COMMENT '网络模式',
`lng` string COMMENT '经度',
`lat` string COMMENT '纬度',
`monday_date` string COMMENT '周一日期',
`sunday_date` string COMMENT '周日日期'
) COMMENT '活跃用户按周明细'
PARTITIONED BY (`wk_dt` string)
stored as parquet
location '/warehouse/gmall/dws/dws_uv_detail_wk/';
- 分析
需求
周活跃: 在一周中,只要启动一次APP,就算是周活跃用户
相关表
从dws_uv_detail_day表中取数据
思路
一、选取一周的范围,作为过滤的条件;
二、从dws_uv_detail_day中查询数据时,需要根据mid号进行去重,将同一个设备产生的多条明细信息去重后再拼接,一个设备在表中以一行存在;
三、求导入数据当前日期所在的周一和周日
①周一: date_sub(next_day(‘2021-02-08’,‘mo’),7)
date_add(next_day(‘2021-02-08’’,‘mo’),-7)
②周日: date_sub(next_day(‘2021-02-08’’,‘mo’),1)
错误:
date_sub(next_day(‘2021-02-08’’,‘sunday’),7)
因为国外周日为第一天,所以这么查询是上周的周日,不是这周的周日 wk_dt(分区列):
concat(date_sub(next_day(‘2021-02-08’’,‘mo’),7),’-’,date_sub(next_day(‘2021-02-08’’,‘mo’),1))
- sql
insert overwrite table dws_uv_detail_wk partition(wk_dt)
select
mid_id,
concat_ws('|', collect_set(user_id)) user_id,
concat_ws('|', collect_set(version_code)) version_code,
concat_ws('|', collect_set(version_name)) version_name,
concat_ws('|', collect_set(lang)) lang,
concat_ws('|', collect_set(source)) source,
concat_ws('|', collect_set(os)) os,
concat_ws('|', collect_set(area)) area,
concat_ws('|', collect_set(model)) model,
concat_ws('|', collect_set(brand)) brand,
concat_ws('|', collect_set(sdk_version)) sdk_version,
concat_ws('|', collect_set(gmail)) gmail,
concat_ws('|', collect_set(height_width)) height_width,
concat_ws('|', collect_set(app_time)) app_time,
concat_ws('|', collect_set(network)) network,
concat_ws('|', collect_set(lng)) lng,
concat_ws('|', collect_set(lat)) lat,
date_add(next_day('2021-02-08','MO'),-7),
date_add(next_day('2021-02-08','MO'),-1),
concat(date_add( next_day('2021-02-08','MO'),-7), '_' , date_add(next_day('2021-02-08','MO'),-1)
)
from dws_uv_detail_day
where dt>=date_add(next_day('2021-02-08','MO'),-7) and dt<=date_add(next_day('2021-02-08','MO'),-1)
group by mid_id;
- 10.1.3 每月活跃设备明细
- 建表
create external table dws_uv_detail_mn(
`mid_id` string COMMENT '设备唯一标识',
`user_id` string COMMENT '用户标识',
`version_code` string COMMENT '程序版本号',
`version_name` string COMMENT '程序版本名',
`lang` string COMMENT '系统语言',
`source` string COMMENT '渠道号',
`os` string COMMENT '安卓系统版本',
`area` string COMMENT '区域',
`model` string COMMENT '手机型号',
`brand` string COMMENT '手机品牌',
`sdk_version` string COMMENT 'sdkVersion',
`gmail` string COMMENT 'gmail',
`height_width` string COMMENT '屏幕宽高',
`app_time` string COMMENT '客户端日志产生时的时间',
`network` string COMMENT '网络模式',
`lng` string COMMENT '经度',
`lat` string COMMENT '纬度'
) COMMENT '活跃用户按月明细'
PARTITIONED BY (`mn` string)
stored as parquet
location '/warehouse/gmall/dws/dws_uv_detail_mn/';
- 分析
相关表
从dws_uv_detail_day表中取数据
思路
一、选取一月的范围,作为过滤的条件;
二、从dws_uv_detail_day中查询数据时,需要根据mid号进行去重,将同一个设备产生的多条明细信息去重后再拼接,一个设备在表中以一行存在;
- sql
insert overwrite table dws_uv_detail_mn partition(mn)
select
mid_id,
concat_ws('|', collect_set(user_id)) user_id,
concat_ws('|', collect_set(version_code)) version_code,
concat_ws('|', collect_set(version_name)) version_name,
concat_ws('|', collect_set(lang)) lang,
concat_ws('|', collect_set(source)) source,
concat_ws('|', collect_set(os)) os,
concat_ws('|', collect_set(area)) area,
concat_ws('|', collect_set(model)) model,
concat_ws('|', collect_set(brand)) brand,
concat_ws('|', collect_set(sdk_version)) sdk_version,
concat_ws('|', collect_set(gmail)) gmail,
concat_ws('|', collect_set(height_width)) height_width,
concat_ws('|', collect_set(app_time)) app_time,
concat_ws('|', collect_set(network)) network,
concat_ws('|', collect_set(lng)) lng,
concat_ws('|', collect_set(lat)) lat,
date_format('2021-02-08','yyyy-MM')
from dws_uv_detail_day
where date_format(dt,'yyyy-MM') = date_format('2021-02-08','yyyy-MM')
group by mid_id;
- 10.1.4 生成脚本
之前讲过公共脚本,这里不讲了
10.2 用户新增主题
- 10.2.1 每日新增设备明细
- 建表
create external table dws_new_mid_day
(
`mid_id` string COMMENT '设备唯一标识',
`user_id` string COMMENT '用户标识',
`version_code` string COMMENT '程序版本号',
`version_name` string COMMENT '程序版本名',
`lang` string COMMENT '系统语言',
`source` string COMMENT '渠道号',
`os` string COMMENT '安卓系统版本',
`area` string COMMENT '区域',
`model` string COMMENT '手机型号',
`brand` string COMMENT '手机品牌',
`sdk_version` string COMMENT 'sdkVersion',
`gmail` string COMMENT 'gmail',
`height_width` string COMMENT '屏幕宽高',
`app_time` string COMMENT '客户端日志产生时的时间',
`network` string COMMENT '网络模式',
`lng` string COMMENT '经度',
`lat` string COMMENT '纬度',
`create_date` string comment '创建时间'
) COMMENT '每日新增设备信息'
stored as parquet
location '/warehouse/gmall/dws/dws_new_mid_day/';
- 分析
相关表
dws_uv_detail_day(日活表)中查询
dws_new_mid_day(每日新增设备表)
思路
一、dws_uv_detail_day包含今天所有的活跃用户的信息;所有的活跃用户= 今天的新增用户 + 之前的历史用户 ;
二、要向dws_new_mid_day插入的是2021-02-08的新用户,dws_new_mid_day里面已经有了从应用统计-2021-02-07所有的老用户信息;
三、今天的活跃用户-之前的历史用户=今天的新增用户!
- sql
insert into table gmall.dws_new_mid_day
SELECT
t1.*
FROM
(select * from dws_uv_detail_day where dt='2021-02-08') t1
LEFT JOIN gmall.dws_new_mid_day nm
on t1.mid_id=nm.mid_id
WHERE nm.mid_id is null;
- 生成脚本
10.3 用户留存主题
- 10.3.1 每日留存用户明细表
- 建表
create external table dws_user_retention_day
(
`mid_id` string COMMENT '设备唯一标识',
`user_id` string COMMENT '用户标识',
`version_code` string COMMENT '程序版本号',
`version_name` string COMMENT '程序版本名',
`lang` string COMMENT '系统语言',
`source` string COMMENT '渠道号',
`os` string COMMENT '安卓系统版本',
`area` string COMMENT '区域',
`model` string COMMENT '手机型号',
`brand` string COMMENT '手机品牌',
`sdk_version` string COMMENT 'sdkVersion',
`gmail` string COMMENT 'gmail',
`height_width` string COMMENT '屏幕宽高',
`app_time` string COMMENT '客户端日志产生时的时间',
`network` string COMMENT '网络模式',
`lng` string COMMENT '经度',
`lat` string COMMENT '纬度',
`create_date` string comment '设备新增时间',
`retention_day` int comment '截止当前日期留存天数'
) COMMENT '每日用户留存情况'
PARTITIONED BY (`dt` string)
stored as parquet
location '/warehouse/gmall/dws/dws_user_retention_day/';
- 分析
相关表
dws_new_mid_day:每日的新增用户表
dws_uv_detail_day:日活表
思路
一、明细信息:从dws_uv_detail_day(日活表)取
二、create_date: 设备的新增日期(哪一天称为新用户的);从dws_new_mid_day根据mid_id查询;
三、retention_day: 截至到当前日期留存的天数
四、dt(日活数据的日期)=create_date+retention_day
- sql
insert overwrite TABLE dws_user_retention_day PARTITION(dt='2021-02-08')
SELECT
t1.mid_id,
t1.user_id,
t1.version_code,
t1.version_name,
t1.lang,
t1.source,
t1.os,
t1.area,
t1.model,
t1.brand,
t1.sdk_version,
t1.gmail,
t1.height_width,
t1.app_time,
t1.network,
t1.lng,
t1.lat,
t2.create_date,
1 retention_day,
'2021-02-08'
FROM
(SELECT * from gmall.dws_uv_detail_day where dt='2021-02-08') t1
JOIN
(select mid_id,create_date from gmall.dws_new_mid_day where create_date=date_sub('2021-02-08',1)) t2
on t1.mid_id=t2.mid_id
- 10.3.2 求1,2,3,n天的留存明细
- sql
> 使用union all链接多个sql
insert overwrite TABLE dws_user_retention_day PARTITION(dt='2021-02-08')
SELECT
t1.mid_id,
t1.user_id,
t1.version_code,
t1.version_name,
t1.lang,
t1.source,
t1.os,
t1.area,
t1.model,
t1.brand,
t1.sdk_version,
t1.gmail,
t1.height_width,
t1.app_time,
t1.network,
t1.lng,
t1.lat,
t2.create_date,
1 retention_day
FROM
(SELECT * from gmall.dws_uv_detail_day where dt='2021-02-08') t1
JOIN
(select mid_id,create_date from gmall.dws_new_mid_day where create_date=date_sub('2021-02-08',1)) t2
on t1.mid_id=t2.mid_id
UNION all
SELECT
t1.mid_id,
t1.user_id,
t1.version_code,
t1.version_name,
t1.lang,
t1.source,
t1.os,
t1.area,
t1.model,
t1.brand,
t1.sdk_version,
t1.gmail,
t1.height_width,
t1.app_time,
t1.network,
t1.lng,
t1.lat,
t2.create_date,
2 retention_day
FROM
(SELECT * from gmall.dws_uv_detail_day where dt='2021-02-08') t1
JOIN
(select mid_id,create_date from gmall.dws_new_mid_day where create_date=date_sub('2021-02-08',2)) t2
on t1.mid_id=t2.mid_id
UNION all
SELECT
t1.mid_id,
t1.user_id,
t1.version_code,
t1.version_name,
t1.lang,
t1.source,
t1.os,
t1.area,
t1.model,
t1.brand,
t1.sdk_version,
t1.gmail,
t1.height_width,
t1.app_time,
t1.network,
t1.lng,
t1.lat,
t2.create_date,
3 retention_day
FROM
(SELECT * from gmall.dws_uv_detail_day where dt='2021-02-08') t1
JOIN
(select mid_id,create_date from gmall.dws_new_mid_day where create_date=date_sub('2021-02-08',3)) t2
on t1.mid_id=t2.mid_id
- 10.3.3 生成脚本
10.4 每个用户累计访问次数
- 建表
create external table dws_user_total_count_day(
`mid_id` string COMMENT '设备id',
`subtotal` bigint COMMENT '每日登录小计'
)
partitioned by(`dt` string)
row format delimited fields terminated by '\t'
location '/warehouse/gmall/dws/dws_user_total_count_day';
- 分析
需求
向dws_user_total_count_day插入数据
相关表
dwd_start_log(启动日志表)
思路
一、用户每打开一次应用,就会产生一条启动日志;
二、从启动日志表查询,根据用户(mid_id)分组,求每个用户产生的;
三、启动日志的总的数量(count)。
- sql
insert overwrite table dws_user_total_count_day PARTITION(dt='2021-02-08')
SELECT
mid_id,
count(*) subtotal
FROM dwd_start_log
where dt='2021-02-08'
GROUP by mid_id;
- 生成脚本
10.5 新收藏用户数
- 建表
CREATE EXTERNAL TABLE dws_user_action_wide_log(
`mid_id` string COMMENT '设备id',
`goodsid` string COMMENT '商品id',
`display_count` string COMMENT '点击次数',
`praise_count` string COMMENT '点赞次数',
`favorite_count` string COMMENT '收藏次数')
PARTITIONED BY (`dt` string)
stored as parquet
location '/warehouse/gmall/dws/dws_user_action_wide_log/'
TBLPROPERTIES('parquet.compression'='lzo');
- 分析
相关表
dwd_display_log(商品点击表):mid_id(用户),goodsid(商品id)
dwd_favorites_log(收藏表):mid_id(用户),course_id(商品id)
dwd_praise_log(点赞表): mid_id(用户),target_id(商品id)
思路
一、将用户对每个商品的点击次数,点赞次数,收藏次数等信息汇总到一张宽表中!
二、从以上三个表中,先以用户和商品为单位,进行聚合!
三、从以上三个表中取数据,根据mid_id和商品进行关联!将三个表的信息汇总合并!
合并: 常用join,使用join进行连接操作!
在hive中尽量少用join!
这次可以使用union all
- sql
insert overwrite TABLE dws_user_action_wide_log PARTITION(dt='2021-02-08')
select
mid_id,
goodsid,
sum(display_count),
sum(praise_count),
sum(favorite_count)
from
(select
mid_id,goodsid,count(*) display_count,0 praise_count, 0 favorite_count
from dwd_display_log
where dt='2021-02-08'
group by mid_id,goodsid
union all
SELECT
mid_id,target_id goodsid,0 display_count ,count(*) praise_count,0 favorite_count
from dwd_praise_log
where dt='2021-02-08'
group by mid_id,target_id
union all
select
mid_id,course_id goodsid, 0 display_count,0 praise_count, count(*) favorite_count
from dwd_favorites_log
where dt='2021-02-08'
group by mid_id,course_id) tmp
GROUP by mid_id,goodsid
- 生成脚本
第11章 ADS层搭建
11.1 用户活跃主题
- 11.1.1 生成每日,周,月后跃设备数量
- 建表
create external table ads_uv_count(
`dt` string COMMENT '统计日期',
`day_count` bigint COMMENT '当日用户数量',
`wk_count` bigint COMMENT '当周用户数量',
`mn_count` bigint COMMENT '当月用户数量',
`is_weekend` string COMMENT 'Y,N是否是周末,用于得到本周最终结果',
`is_monthend` string COMMENT 'Y,N是否是月末,用于得到本月最终结果'
) COMMENT '活跃设备数'
row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_uv_count/';
- 分析
相关表
dws_uv_detail_day
dws_uv_detail_wk
dws_uv_detail_mn
思路
一、dws_uv_detail_day,使用count(mid_id) 统计 日活跃设备数
二、dws_uv_detail_wk,使用count(mid_id) 统计 周活跃设备数
三、dws_uv_detail_mn,使用count(mid_id) 统计 月活跃设备数
四、is_weekend: 是否是一周的最后一天 if( date_sub(next_day(‘2021-02-08’,‘mo’),1)=‘2021-02-08’,‘Y’,‘N’)
先求当前日期所在的周日: date_sub(next_day(‘2021-02-08’,‘mo’),1)
判断当前日期是否等于当前所在周的周日
五、is_monthend:是否是一月的最后一天 if(last_day(‘2021-02-08’)=‘2021-02-08’,‘Y’,‘N’)
- sql
INSERT into table gmall.ads_uv_count
select
'2021-02-08' dt,
daycount.ct,
wkcount.ct,
mncount.ct,
if(date_add(next_day('2021-02-08','MO'),-1)='2021-02-08','Y','N') ,
if(last_day('2021-02-08')='2021-02-08','Y','N')
from
(
select
'2021-02-08' dt,
count(*) ct
from dws_uv_detail_day
where dt='2021-02-08'
)daycount join
(
select
'2021-02-08' dt,
count (*) ct
from dws_uv_detail_wk
where wk_dt=concat(date_add(next_day('2021-02-08','MO'),-7),'_' ,date_add(next_day('2021-02-08','MO'),-1) )
) wkcount on daycount.dt=wkcount.dt
join
(
select
'2021-02-08' dt,
count (*) ct
from dws_uv_detail_mn
where mn=date_format('2021-02-08','yyyy-MM')
)mncount on daycount.dt=mncount.dt;
- 生成脚本
11.2 用户新增主题
- 11.2.1 统计每日新增设备数
- 建表
create external table ads_new_mid_count
(
`create_date` string comment '创建时间' ,
`new_mid_count` BIGINT comment '新增设备数量'
) COMMENT '每日新增设备信息数量'
row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_new_mid_count/';
- 分析
相关表
从dws_new_mid_day,执行count统计即可
- sql
insert into table ads_new_mid_count
select
create_date,
count(*)
from dws_new_mid_day
where create_date='2021-02-08'
group by create_date;
- 生成脚本
11.3 用户留存主题
- 11.3.1 每日留存用户的数量
- 建表
create external table ads_user_retention_day_count
(
`create_date` string comment '设备新增日期',
`retention_day` int comment '截止当前日期留存天数',
`retention_count` bigint comment '留存数量'
) COMMENT '每日用户留存情况'
row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_user_retention_day_count/';
- 分析
相关表
dws_user_retention_day
思路
create_date: 从dws_user_retention_day查询
retention_day: 从dws_user_retention_day查询
retention_count: 使用count()统计
先根据create_date过滤指定的新增日期日期用户的设备明细!
再根据retention_day分组,之后count()
- sql
insert into table gmall.ads_user_retention_day_count
SELECT
'2021-02-08',
retention_day,
count(*)
FROM gmall.dws_user_retention_day
where create_date='2021-02-08'
group by retention_day;
- 生成脚本
- 11.3.2 留存用户比率
- 建表
create external table ads_user_retention_day_rate
(
`stat_date` string comment '统计日期',
`create_date` string comment '设备新增日期',
`retention_day` int comment '截止当前日期留存天数',
`retention_count` bigint comment '留存数量',
`new_mid_count` bigint comment '当日设备新增数量',
`retention_ratio` decimal(10,2) comment '留存率'
) COMMENT '每日用户留存情况'
row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_user_retention_day_rate/';
- 分析
相关表
ads_user_retention_day_count
ads_new_mid_count
从以上两表取出同一条新增的设备的信息,因此设备的新增日期是关联的字段
思路
stat_date
: 一般是当前要统计数据的当天或后一天。不早于统计数据的日期!
create_date
: 从ads_user_retention_day_count取
retention_day
: 从ads_user_retention_day_count取
retention_count
: 从ads_user_retention_day_count取
new_mid_count
: 从ads_new_mid_count统计当前新增设备的数量
retention_ratio
: retention_count/new_mid_count
- sql
insert into table ads_user_retention_day_rate
SELECT
'2021-02-08',
ur.create_date,
ur.retention_day,
ur.retention_count,
nm.new_mid_count,
cast (ur.retention_count / nm.new_mid_count as decimal(10,2))
FROM
ads_user_retention_day_count ur
JOIN
ads_new_mid_count nm
on ur.create_date=nm.create_date
where date_add(ur.create_date,ur.retention_day)='2021-02-08'
- 生成脚本
11.4 沉默用户数
- 建表
create external table ads_silent_count(
`dt` string COMMENT '统计日期',
`silent_count` bigint COMMENT '沉默设备数'
)
row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_silent_count';
- 分析
需求
沉默用户:只在安装当天启动过,且启动时间是在一周前;
只在安装当天启动过: 沉默用户只会产生的一天的启动日志;
启动时间是在一周前: 沉默用户产生启动日志的时间,必须距离当前的统计时间已经,间隔了7天.
相关表
日活表dws_uv_detail_day(提前针对mid_id进行了合并)
一个mid_id在日活表中一天最多有1条记录
思路
从日活表中取出统计日期之前的所有数据,按照mid_id(用户设备号)分组,统计日活表所有的记录数=1的mid_id;
再判断,记录数=1的mid_id,当天产生的dt是否已经举例当前间隔了7天.
- sql
insert into table ads_silent_count
select
'2021-02-24',
count(*)
from
(select
mid_id
from dws_uv_detail_day
where dt<='2021-02-24'
GROUP by mid_id
HAVING COUNT(mid_id)=1 and min(dt)<date_sub('2021-02-24',7)) tmp
- 生成脚本
11.5 本周回流用户数
- 建表
create external table ads_back_count(
`dt` string COMMENT '统计日期',
`wk_dt` string COMMENT '统计日期所在周',
`wastage_count` bigint COMMENT '回流设备数'
)
row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_back_count';
- 分析
需求
本周回流用户:上周没有使用应用,上周之前使用了应用,本周使用了应用;
本周回流用户=本周日活-本周新增用户-上周日活用户.
相关表
dws_uv_detail_wk: 周活表
dws_new_mid_day: 每日新增用户表
思路
三个结果集做差:
a left join b on a.x=b.x where b.x is null
with
临时表名 as (),
临时表名 as (),
临时表名 as ()
select 语句
- sql
with t1 as
(SELECT
mid_id
FROM dws_uv_detail_wk
where wk_dt=concat(date_sub(next_day('2021-02-24','mo'),7),'-',date_sub(next_day('2021-02-24','mo'),1))),
t2 as
(SELECT
mid_id
from dws_new_mid_day
where create_date BETWEEN date_sub(next_day('2021-02-24','mo'),7) and '2021-02-24'),
t3 as
(SELECT
mid_id
FROM dws_uv_detail_wk
where wk_dt=concat(date_sub(next_day('2021-02-24','mo'),14),'-',date_sub(next_day('2021-02-24','mo'),8)))
insert into table ads_back_count
select
'2021-02-24',
concat(date_sub(next_day('2021-02-24','mo'),7),'-',date_sub(next_day('2021-02-24','mo'),1)),
count(*)
from
t1 left join t2 on t1.mid_id=t2.mid_id
left join t3 on t1.mid_id=t3.mid_id
where t2.mid_id is null and t3.mid_id is null
- 生成脚本
11.6 连续活跃主题
- 11.6.1 近连续三周活跃用户数
- 建表
create external table ads_continuity_wk_count(
`dt` string COMMENT '统计日期,一般用结束周周日日期,如果每天计算一次,可用当天日期',
`wk_dt` string COMMENT '持续时间',
`continuity_count` bigint
)
row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_continuity_wk_count';
- 分析
需求
连续三周后跃用户: 在当前日期之前三周的周活表中,此用户都存在!
周活表特点按照mid_id进行了去重!
因此如果用户,在连续三周的周活中出现,那么就会有3条对应的记录!
相关表
周活表:dws_dv_detail_wk
思路
求当前日期,之前三周的数据。根据mid分组,分组后统计组内记录数量=3,即是连续三周登录的用户
- sql
insert into table ads_continuity_wk_count
select
'2021-02-24',
concat(date_sub(next_day('2021-02-24','mo'),21),'_',date_sub(next_day('2021-02-24','mo'),1)),
count(*)
from
(select
mid_id
from dws_uv_detail_wk
where monday_date BETWEEN date_sub(next_day('2021-02-24','mo'),21)
and '2021-02-24'
- 生成脚本
- 11.6.2 近七天内连续三天活跃用户数
- 建表
create external table ads_continuity_uv_count(
`dt` string COMMENT '统计日期',
`wk_dt` string COMMENT '最近7天日期',
`continuity_count` bigint
) COMMENT '连续活跃设备数'
row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_continuity_uv_count';
- 分析
相关表
日活表: dws_uv_detail_day
思路
取当前日志之前7天的数据;
按照用户mid_id分组,按照日期进行升序排序;
使用rownumber函数,创建一个连续递增的列;
将日期列和rw列,进行做差;
将用户和差值进行分组,组内至少有3条记录,将复合条件的mid_id进行过滤即可;
- sql
insert into TABLE ads_continuity_uv_count
select
'2021-02-24',
concat(date_sub('2021-02-24',7),'-','2021-02-24'),
count(DISTINCT mid_id)
from
(select
mid_id
from
(SELECT
mid_id,dt,ROW_NUMBER() over(PARTITION by mid_id order by dt )rn,
date_sub(dt,ROW_NUMBER() over(PARTITION by mid_id order by dt )) diff
from dws_uv_detail_day
where dt BETWEEN date_sub('2021-02-24',7) and '2021-02-24') tmp
GROUP by mid_id,diff
having count(*)>=3 ) tmp2
- 生成脚本
11.7 各个商品点击次数top3的用户
- 建表
create external table ads_goods_count(
`dt` string COMMENT '统计日期',
`goodsid` string COMMENT '商品',
`user_id` string COMMENT '用户',
`goodsid_user_count` bigint COMMENT '商品用户点击次数'
)
row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_goods_count';
- 分析
相关表
dws_user_action_wide_log
思路
过滤出点击次数>0的用户,取这些用户今天之前的所有数据;
按照商品id和用户id进行分组,统计每个用户对每件商品的累计点击次数;
针对每个商品的每个用户的点击次数,以商品为单位分区,按照用户的点击次数降序排序,求出排名前三的用户!
- sql
insert into table ads_goods_count
select
'2021-02-24', goodsid,mid_id,totalCount
from
(select goodsid,mid_id,totalCount,
RANK() over(PARTITION by goodsid order by totalCount desc )rn
from
(SELECT
goodsid,mid_id,sum(display_count) totalCount
from dws_user_action_wide_log
where dt<='2021-02-24' and display_count>0
GROUP by goodsid,mid_id) t1) t2
where rn<=3
- 生成脚本
11.8 总点击次数最多的10个用户点击的各个的商品次数
- 建表
create external table ads_goods_user_count(
`dt` string COMMENT '统计日期',
`mid_id` string COMMENT '用户id',
`u_ct` string COMMENT '用户总点击次数',
`goodsid` string COMMENT '商品id',
`d_ct` string COMMENT '各个商品点击次数'
)
row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_goods_user_count';
- 分析
相关表
dws_user_action_wide_log
思路
求总点击次数最多的10个用户
再求出此10个用户各自点击的每个商品次数
- sql
insert into TABLE ads_goods_user_count
select
'2021-02-24',
mid_id,
u_ct,
goodsid,
d_ct
from(
select
mid_id,
u_ct,
goodsid,
d_ct,
row_number() over(partition by mid_id order by d_ct desc ) rn
from(
select
dl.mid_id,
u_ct,
dl.goodsid,
count(*) d_ct
from dwd_display_log dl join (
select
mid_id,
count(*) u_ct
from dws_user_action_wide_log
group by mid_id
order by u_ct desc
limit 10
)t1
on dl.mid_id=t1.mid_id
group by dl.mid_id, u_ct, dl.goodsid
) t2
) t3
where rn<=10
- 生成脚本
11.9 月活跃率
- 建表
create external table ads_mn_ratio_count(
`dt` string COMMENT '统计日期',
`mn` string COMMENT '统计月活跃率的月份',
`ratio` string COMMENT '活跃率'
)
row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_mn_ratio_count';
- 分析
需求
月活跃用户与截止到该月累计的用户总和之间的比例
相关表
ads_uv_count: 取月活跃用户
ads_new_mid_count: 取截至到该月所有的用户数
- sql
insert into table ads_mn_ratio_count
select
'2021-02-24',
date_format('2021-02-24','yyyy-MM'),
mn_count/sum_user*100 mn_percent
from
(select count(*) mn_count from dws_uv_detail_mn where mn=date_format('2021-02-24','yyyy-MM')) t1,
(select sum(new_mid_count) sum_user from ads_new_mid_count) t2;
- 生成脚本
11.10 每个用户累计访问次数
- 建表
drop table if exists ads_user_total_count;
create external table ads_user_total_count(
`mid_id` string COMMENT '设备id',
`subtotal` bigint COMMENT '每日登录小计',
`total` bigint COMMENT '登录次数总计'
)
partitioned by(`dt` string)
row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_user_total_count';
- 分析
相关表
dws_user_total_count_day
思路
从dws_user_total_count_day中取出每个用户每天登录的次数,
再取出每个用户之前每天登录的次数的总和
- sql
insert overwrite table ads_user_total_count PARTITION(dt='2021-02-24')
SELECT
t1.mid_id,
t1.subtotal,
t2.total
from
(select mid_id,subtotal
from dws_user_total_count_day
where dt='2021-02-24') t1
JOIN
(select mid_id,sum(subtotal) total
FROM dws_user_total_count_day
where dt<='2021-02-24'
GROUP by mid_id) t2
on t1.mid_id=t2.mid_id
- 生成脚本
第12章 用户行为数仓部分报错总结
- org.apache.tez.dag.api.SessionNotRunning: TezSession has already shutdown
运行Tez时检查到用过多内存而被NodeManager杀死进程问题
关掉虚拟内存检查,修改yarn-site.xml
<property>
<name>yarn.nodemanager.vmem-check-enabled</name>
<value>false</value>
</property>