电商数据仓库开发之用户行为数据数仓开发-实现需求一

(一)数据仓库介绍

数据仓库分为 4 层: ods 层、 dwd 层、 dws 层、 app 层。

  • ODS层:原始数据层,数据源中的数据,采集过来之后,原样保存。
  • DWD层:明细数据层:这一层是对ODS层的数据进行清洗,解决一些数据质量问题和数据的完整度
    问题。
  • DWS层:这一层是对DWD层的数据进行轻度聚合汇总,生成一系列的中间表,提升公共指标的复用性,减少重复加工,并且构建出来一些宽表,用于提供后续的业务查询。
  • APP层:根据业务需要,由前面三层的数据统计而出的结果,可以直接提供查询展现,一般会把APP层的数据导出到MySQL中供线上系统使用,提供报表展示、数据监控及其它功能。也有公司把这层称为DM层。虽然名字不一样,但是性质是一样的。

(二)用户行为数据数仓开发

(1)ods层开发

  1. 在 hive中创建数据库 ods_mall。
    hive (default)> create database ods_mall;

  2. 在 ods_mall 中需要创建以下针对用户行为数据的表

ods_user_active 用户主动活跃表(act=1)
ods_click_good   点击商品表(act=2)
ods_good_item  商品详情页表 (act=3)
ods_good_list 商品列表页表(act=4)
ods_app_close APP 崩溃数据表 (act=5)

注意:

  • 由于在构建数据仓库的时候我们会创建多个数据库,所以在创建以及使用表的时候最好都在表名前面带上对应的数据库名称,否则可能会出现一些不必要的问题,可能会把 ods层的表建到dwd 层。
  • 考虑到SQL 重跑的情况,需要在 SQL 语句中添加 if not exists :
  • hive 中可以用 string, date, timestamp表示日期时间, date用yyyy-MM-dd :的形式表示, timestamp用:yyyy-MM-dd hh:mm:ss 的形式表示, string可以表示 和 string yyyy-MM-dd和 yyy-MM-dd hh:mm:ss表示。
    这三种格式之间可以互相转换,不过在用的时候建议格式统一, 可以表示另外两种格 String式,并且也支持日期的大小比较,所以在这里针对时间统一使用 表示。
  1. 创建ods层的表

表名 :ods_user_active
( json 存储原始的 格式的用户主动活跃数据)

建表语句:

create external table if not exists ods_mall.ods_user_active(
    log    string
)partitioned by (dt string)
 row format delimited
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/ods/user_action/';

alter table ods_mall.ods_user_active add  if not exists partition(dt='20260101') location '20260101/1';

表名 :ods_click_good

create external table if not exists ods_mall.ods_click_good(
    log    string
)partitioned by (dt string)
 row format delimited
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/ods/user_action/';
 
alter table ods_mall.ods_click_good add  if not exists partition(dt='20260101') location '20260101/2';

表名:ods_good_item

create external table if not exists ods_mall.ods_good_item(
    log    string
)partitioned by (dt string)
 row format delimited
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/ods/user_action/';

alter table ods_mall.ods_good_item add  if not exists partition(dt='20260101') location '20260101/3';

表名:ods_good_list

create external table if not exists ods_mall.ods_good_list(
    log    string
)partitioned by (dt string)
 row format delimited
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/ods/user_action/';
 
alter table ods_mall.ods_good_list add  if not exists partition(dt='20260101') location '20260101/4';

表名:ods_app_close

create external table if not exists ods_mall.ods_app_close(
    log    string
)partitioned by (dt string)
 row format delimited
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/ods/user_action/';

alter table ods_mall.ods_app_close add  if not exists partition(dt='20260101') location '20260101/5';
  1. 针对 ods 层抽取脚本
    表初始化脚本 初始化执行一次
    ods_mall_init_table.sh
#!/bin/bash
# ods层数据库和表初始化脚本,只需要执行一次

hive -e "
create database if not exists ods_mall;

create external table if not exists ods_mall.ods_user_active(
    log    string
)partitioned by (dt string)
 row format delimited
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/ods/user_action/';

 
create external table if not exists ods_mall.ods_click_good(
    log    string
)partitioned by (dt string)
 row format delimited
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/ods/user_action/';
 
 
create external table if not exists ods_mall.ods_good_item(
    log    string
)partitioned by (dt string)
 row format delimited
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/ods/user_action/';

 
create external table if not exists ods_mall.ods_good_list(
    log    string
)partitioned by (dt string)
 row format delimited
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/ods/user_action/';


create external table if not exists ods_mall.ods_app_close(
    log    string
)partitioned by (dt string)
 row format delimited
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/ods/user_action/';
"

添加分区数据脚本 每天执行一次
add_partition.sh:这个脚本是通用的,所有添加分区的地方都可以使用。

#!/bin/bash
# 给外部分区表添加分区
# 接收三个参数
#1:表名
#2:分区字段dt的值:格式20260101
#3:分区路径(相对路径或者绝对路径都可以)

if [ $# != 3 ]
then
echo "参数异常:add_partition.sh <tabkle_name> <dt> <path>"
exit 100
fi

table_name=$1
dt=$2
path=$3

hive -e "
alter table ${table_name} add  if not exists partition(dt='${dt}') location '${path}';
"

ods_mall_add_partition.sh

#!/bin/bash
# 给ods层的表添加分区,这个脚本后期每天执行一次
# 每天凌晨,添加昨天的分区,添加完分区之后,再执行后面的计算脚本

# 默认获取昨天的日期,也支持传参指定一个日期
if [ "z$1" = "z" ]
then
dt=`date +%Y%m%d --date="1 days ago"`
else
dt=$1
fi

#alter table ods_mall.ods_user_active add  if not exists partition(dt='20260101') location '20260101/1';
#alter table ods_mall.ods_click_good add  if not exists partition(dt='20260101') location '20260101/2';
#alter table ods_mall.ods_good_item add  if not exists partition(dt='20260101') location '20260101/3';
#alter table ods_mall.ods_good_list add  if not exists partition(dt='20260101') location '20260101/4';
#alter table ods_mall.ods_app_close add  if not exists partition(dt='20260101') location '20260101/5';
sh add_partition.sh ods_mall.ods_user_active ${dt} ${dt}/1
sh add_partition.sh ods_mall.ods_click_good ${dt} ${dt}/2
sh add_partition.sh ods_mall.ods_good_item ${dt} ${dt}/3
sh add_partition.sh ods_mall.ods_good_list ${dt} ${dt}/4
sh add_partition.sh ods_mall.ods_app_close ${dt} ${dt}/5

(2)dwd层开发

针对 ods层表中的数据进行清洗,参考数据清洗规则,按照实际情况对数据进行清洗
注意:如果清洗规则使用 SQL 可以实现,那么就使用 SQL 实现数据清洗,如果清洗的规则使用 SQL 实现起来非常麻烦,或者使用 SQL 压根无法实现,此时就可以考虑需要使用MapReduce 代码或者 Spark 代码对数据进行清洗了。
由于我们这里采集的数据还是比较规整的,可以使用 SQL 实现,所以我们就直接使用 SQL实现数据清洗了。

  1. 在 hive 中创建数据库 dwd_mall
    hive (default)> create database dwd_mall;

  2. 创建 dwd 层的表
    注意:

  • 原始 json数据中的用户 id字段名称为 uid,但是在商品订单数据中用户 id字段名称为 user_id ,这块需要注意一下,在实际工作中会有这种情况,客户端数据和服务端数据的个别字段名称不一致,所以我们在使用的时候最好是统一一下,后期使用起来比较方便,所以在这里我会通过 uid 解析数据,解析之后,给字段起别名为 user_id 。
  • hive 中的 只能解析yyyy-MM-dd HH:MM:SS 格式的数据,所以针对这里面的acttime 字段我们使用 bigint 类型
  • 为了考虑到SQL 重跑的情况,在使用 insert into table的时候最好改为 insert overwrite ,否则 重复执行的时候会重复写入数据.
  1. dwd_user_active( 存储解析清洗之后的用户主动活跃数据,对数据进行去重,并 且 过 滤 掉xaid为 空的数据 )
create external table if not exists dwd_mall.dwd_user_active(
    user_id    bigint,
    xaid    string,
    platform    tinyint,
    ver    string,
    vercode    string,
    net    bigint,
    brand    string,
    model    string,
    display    string,
    osver    string,
    acttime    bigint,
    ad_status    tinyint,
    loading_time    bigint
)partitioned by(dt string) 
 row format delimited  
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/dwd/user_active/';
 

insert overwrite table dwd_mall.dwd_user_active partition(dt='20260101')  select
get_json_object(log,'$.uid') as user_id,
get_json_object(log,'$.xaid') as xaid,
get_json_object(log,'$.platform') as platform,
get_json_object(log,'$.ver') as ver,
get_json_object(log,'$.vercode') as vercode,
get_json_object(log,'$.net') as net,
get_json_object(log,'$.brand') as brand,
get_json_object(log,'$.model') as model,
get_json_object(log,'$.display') as display,
get_json_object(log,'$.osver') as osver,
get_json_object(log,'$.acttime') as acttime,
get_json_object(log,'$.ad_status') as ad_status,
get_json_object(log,'$.loading_time') as loading_time
from 
(
select log from ods_mall.ods_user_active where dt = '20260101' group by log
) as tmp
where get_json_object(log,'$.xaid') !='';

  1. 创建dwd_click_good
create external table if not exists dwd_mall.dwd_click_good(
    user_id    bigint,
    xaid    string,
    platform    tinyint,
    ver    string,
    vercode    string,
    net    bigint,
    brand    string,
    model    string,
    display    string,
    osver    string,
    acttime    bigint,
    goods_id    bigint,
    location    tinyint
)partitioned by(dt string) 
 row format delimited  
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/dwd/click_good/';

insert overwrite table dwd_mall.dwd_click_good partition(dt='20260101')  select 
get_json_object(log,'$.uid') as user_id,
get_json_object(log,'$.xaid') as xaid,
get_json_object(log,'$.platform') as platform,
get_json_object(log,'$.ver') as ver,
get_json_object(log,'$.vercode') as vercode,
get_json_object(log,'$.net') as net,
get_json_object(log,'$.brand') as brand,
get_json_object(log,'$.model') as model,
get_json_object(log,'$.display') as display,
get_json_object(log,'$.osver') as osver,
get_json_object(log,'$.acttime') as acttime,
get_json_object(log,'$.goods_id') as goods_id,
get_json_object(log,'$.location') as location
from
(
select log from ods_mall.ods_click_good where dt = '20260101' group by log
) as tmp
where get_json_object(log,'$.xaid') !='';

  1. 创建dwd_good_item
create external table if not exists dwd_mall.dwd_good_item(
    user_id    bigint,
    xaid    string,
    platform    tinyint,
    ver    string,
    vercode    string,
    net    bigint,
    brand    string,
    model    string,
    display    string,
    osver    string,
    acttime    bigint,
    goods_id    bigint,
    stay_time    bigint,
	loading_time    bigint
)partitioned by(dt string) 
 row format delimited  
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/dwd/good_item/';

insert overwrite table dwd_mall.dwd_good_item partition(dt='20260101') select 
get_json_object(log,'$.uid') as user_id,
get_json_object(log,'$.xaid') as xaid,
get_json_object(log,'$.platform') as platform,
get_json_object(log,'$.ver') as ver,
get_json_object(log,'$.vercode') as vercode,
get_json_object(log,'$.net') as net,
get_json_object(log,'$.brand') as brand,
get_json_object(log,'$.model') as model,
get_json_object(log,'$.display') as display,
get_json_object(log,'$.osver') as osver,
get_json_object(log,'$.acttime') as acttime,
get_json_object(log,'$.goods_id') as goods_id,
get_json_object(log,'$.stay_time') as stay_time,
get_json_object(log,'$.loading_time') as loading_time
from
(
select log from ods_mall.ods_good_item where dt = '20260101' group by log
) as tmp
where get_json_object(log,'$.xaid') !='';

  1. 创建dwd_good_list
create external table if not exists dwd_mall.dwd_good_list(
    user_id    bigint,
    xaid    string,
    platform    tinyint,
    ver    string,
    vercode    string,
    net    bigint,
    brand    string,
    model    string,
    display    string,
    osver    string,
    acttime    bigint,
    loading_time    bigint,
    loading_type    tinyint,
	goods_num    tinyint
)partitioned by(dt string) 
 row format delimited  
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/dwd/good_list/';

insert overwrite table dwd_mall.dwd_good_list partition(dt='20260101') select 
get_json_object(log,'$.uid') as user_id,
get_json_object(log,'$.xaid') as xaid,
get_json_object(log,'$.platform') as platform,
get_json_object(log,'$.ver') as ver,
get_json_object(log,'$.vercode') as vercode,
get_json_object(log,'$.net') as net,
get_json_object(log,'$.brand') as brand,
get_json_object(log,'$.model') as model,
get_json_object(log,'$.display') as display,
get_json_object(log,'$.osver') as osver,
get_json_object(log,'$.acttime') as acttime,
get_json_object(log,'$.loading_time') as loading_time,
get_json_object(log,'$.loading_type') as loading_type,
get_json_object(log,'$.goods_num') as goods_num
from
(
select log from ods_mall.ods_good_list where dt = '20260101' group by log
) as tmp
where get_json_object(log,'$.xaid') !='';

5)创建dwd_app_close

create external table if not exists dwd_mall.dwd_app_close(
    user_id    bigint,
    xaid    string,
    platform    tinyint,
    ver    string,
    vercode    string,
    net    bigint,
    brand    string,
    model    string,
    display    string,
    osver    string,
    acttime    bigint
)partitioned by(dt string) 
 row format delimited  
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/dwd/app_close/';


insert overwrite table dwd_mall.dwd_app_close partition(dt='20260101') select 
get_json_object(log,'$.uid') as user_id,
get_json_object(log,'$.xaid') as xaid,
get_json_object(log,'$.platform') as platform,
get_json_object(log,'$.ver') as ver,
get_json_object(log,'$.vercode') as vercode,
get_json_object(log,'$.net') as net,
get_json_object(log,'$.brand') as brand,
get_json_object(log,'$.model') as model,
get_json_object(log,'$.display') as display,
get_json_object(log,'$.osver') as osver,
get_json_object(log,'$.acttime') as acttime
from
(
select log from ods_mall.ods_app_close where dt = '20260101' group by log
) as tmp
where get_json_object(log,'$.xaid') !='';
  1. 针对 dwd 层抽取脚本
  • 表初始化脚本 初始化执行一次
    dwd_mall_init_table.sh
 #!/bin/bash
# dwd层数据库和表初始化脚本,只需要执行一次即可

hive -e "
create database if not exists dwd_mall;

create external table if not exists dwd_mall.dwd_user_active(
    user_id    bigint,
    xaid    string,
    platform    tinyint,
    ver    string,
    vercode    string,
    net    bigint,
    brand    string,
    model    string,
    display    string,
    osver    string,
    acttime    bigint,
    ad_status    tinyint,
    loading_time    bigint
)partitioned by(dt string) 
 row format delimited  
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/dwd/user_active/';

create external table if not exists dwd_mall.dwd_click_good(
    user_id    bigint,
    xaid    string,
    platform    tinyint,
    ver    string,
    vercode    string,
    net    bigint,
    brand    string,
    model    string,
    display    string,
    osver    string,
    acttime    bigint,
    goods_id    bigint,
    location    tinyint
)partitioned by(dt string) 
 row format delimited  
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/dwd/click_good/';


create external table if not exists dwd_mall.dwd_good_item(
    user_id    bigint,
    xaid    string,
    platform    tinyint,
    ver    string,
    vercode    string,
    net    bigint,
    brand    string,
    model    string,
    display    string,
    osver    string,
    acttime    bigint,
    goods_id    bigint,
    stay_time    bigint,
	loading_time    bigint
)partitioned by(dt string) 
 row format delimited  
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/dwd/good_item/';


create external table if not exists dwd_mall.dwd_good_list(
    user_id    bigint,
    xaid    string,
    platform    tinyint,
    ver    string,
    vercode    string,
    net    bigint,
    brand    string,
    model    string,
    display    string,
    osver    string,
    acttime    bigint,
    loading_time    bigint,
    loading_type    tinyint,
	goods_num    tinyint
)partitioned by(dt string) 
 row format delimited  
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/dwd/good_list/';


create external table if not exists dwd_mall.dwd_app_close(
    user_id    bigint,
    xaid    string,
    platform    tinyint,
    ver    string,
    vercode    string,
    net    bigint,
    brand    string,
    model    string,
    display    string,
    osver    string,
    acttime    bigint
)partitioned by(dt string) 
 row format delimited  
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/dwd/app_close/';
"
  • 添加分区数据脚本 每天执行一次
    dwd_mall_add_partition.sh
  #!/bin/bash
# 基于ods层的表进行清洗,将清洗之后的数据添加到dwd层对应表的对应分区中
# 每天凌晨执行一次

# 默认获取昨天的日期,也支持传参指定一个日期
if [ "z$1" = "z" ]
then
dt=`date +%Y%m%d --date="1 days ago"`
else
dt=$1
fi

hive -e "
insert overwrite table dwd_mall.dwd_user_active partition(dt='${dt}')  select
get_json_object(log,'$.uid') as user_id,
get_json_object(log,'$.xaid') as xaid,
get_json_object(log,'$.platform') as platform,
get_json_object(log,'$.ver') as ver,
get_json_object(log,'$.vercode') as vercode,
get_json_object(log,'$.net') as net,
get_json_object(log,'$.brand') as brand,
get_json_object(log,'$.model') as model,
get_json_object(log,'$.display') as display,
get_json_object(log,'$.osver') as osver,
get_json_object(log,'$.acttime') as acttime,
get_json_object(log,'$.ad_status') as ad_status,
get_json_object(log,'$.loading_time') as loading_time
from 
(
select log from ods_mall.ods_user_active where dt = '${dt}' group by log
) as tmp
where get_json_object(log,'$.xaid') !='';


insert overwrite table dwd_mall.dwd_click_good partition(dt='${dt}')  select 
get_json_object(log,'$.uid') as user_id,
get_json_object(log,'$.xaid') as xaid,
get_json_object(log,'$.platform') as platform,
get_json_object(log,'$.ver') as ver,
get_json_object(log,'$.vercode') as vercode,
get_json_object(log,'$.net') as net,
get_json_object(log,'$.brand') as brand,
get_json_object(log,'$.model') as model,
get_json_object(log,'$.display') as display,
get_json_object(log,'$.osver') as osver,
get_json_object(log,'$.acttime') as acttime,
get_json_object(log,'$.goods_id') as goods_id,
get_json_object(log,'$.location') as location
from
(
select log from ods_mall.ods_click_good where dt = '${dt}' group by log
) as tmp
where get_json_object(log,'$.xaid') !='';


insert overwrite table dwd_mall.dwd_good_item partition(dt='${dt}') select 
get_json_object(log,'$.uid') as user_id,
get_json_object(log,'$.xaid') as xaid,
get_json_object(log,'$.platform') as platform,
get_json_object(log,'$.ver') as ver,
get_json_object(log,'$.vercode') as vercode,
get_json_object(log,'$.net') as net,
get_json_object(log,'$.brand') as brand,
get_json_object(log,'$.model') as model,
get_json_object(log,'$.display') as display,
get_json_object(log,'$.osver') as osver,
get_json_object(log,'$.acttime') as acttime,
get_json_object(log,'$.goods_id') as goods_id,
get_json_object(log,'$.stay_time') as stay_time,
get_json_object(log,'$.loading_time') as loading_time
from
(
select log from ods_mall.ods_good_item where dt = '${dt}' group by log
) as tmp
where get_json_object(log,'$.xaid') !='';



insert overwrite table dwd_mall.dwd_good_list partition(dt='${dt}') select 
get_json_object(log,'$.uid') as user_id,
get_json_object(log,'$.xaid') as xaid,
get_json_object(log,'$.platform') as platform,
get_json_object(log,'$.ver') as ver,
get_json_object(log,'$.vercode') as vercode,
get_json_object(log,'$.net') as net,
get_json_object(log,'$.brand') as brand,
get_json_object(log,'$.model') as model,
get_json_object(log,'$.display') as display,
get_json_object(log,'$.osver') as osver,
get_json_object(log,'$.acttime') as acttime,
get_json_object(log,'$.loading_time') as loading_time,
get_json_object(log,'$.loading_type') as loading_type,
get_json_object(log,'$.goods_num') as goods_num
from
(
select log from ods_mall.ods_good_list where dt = '${dt}' group by log
) as tmp
where get_json_object(log,'$.xaid') !='';


insert overwrite table dwd_mall.dwd_app_close partition(dt='${dt}') select 
get_json_object(log,'$.uid') as user_id,
get_json_object(log,'$.xaid') as xaid,
get_json_object(log,'$.platform') as platform,
get_json_object(log,'$.ver') as ver,
get_json_object(log,'$.vercode') as vercode,
get_json_object(log,'$.net') as net,
get_json_object(log,'$.brand') as brand,
get_json_object(log,'$.model') as model,
get_json_object(log,'$.display') as display,
get_json_object(log,'$.osver') as osver,
get_json_object(log,'$.acttime') as acttime
from
(
select log from ods_mall.ods_app_close where dt = '${dt}' group by log
) as tmp
where get_json_object(log,'$.xaid') !='';
"

(三)需求分析

前面的两层中的表和需求一般没什么关系,就是把已有的数据接入进来,然后对数据进行清洗处理。但是后面的 dws 层和 app 层是和业务有关联的,所以在构建这两层中的表的时候,我们需要根据一些典型的业务场景来进行分析,在根据具体业务建表的时候尽可能把表设计的更加通用,可以满足后期一些类似业务需求

就是说我们在基于业务构建表的时候,不要直接一个 SQL搞定,可以把一些复杂的 SQL基于一些维度进行拆分,拆分出来一些中间表,再基于这些中间表统计最终的结果。这样这个中间表里面的数据,我们后期针对一些类似的业务需求还是可以服用的。

  • 需求一:每日新增用户相关指标
  • 需求二:每日活跃用户相关指标
  • 需求三:用户 7日流失 push提醒
  • 需求四:每日启动 App 次数相关指标
  • 需求五:操作系统活跃用户相关指标
  • 需求六: APP 崩溃相关指标

使用数据:从 2026-02-01 到 2026-02-28 的数据

(1)需求一: 每日新增用户相关指标

在统计新增用户时,用户是以设备标识字段来判断的,每一个设备都有一个唯一设备 (xaid )码,因为会存在用户不登录的情况,以及多人共用一个账号的情况,所以根据用户进行 id统计是不准确的。
新增用户是指第一次安装 app并且使用的用户,后期卸载之后再使用就不算新用户了。
这个新增用户其实也可以称为新增设备,一个设备对应一个用户。
1:每日新增用户量
2:每日新增用户量的日环比和周同比

1)先详细分析第1 个指标
每日新增用户量 在实际工作中通过这个指标可以衡量我们产品的用户增长速度,如果每日新增用户量一直是上升的,说明我们的产品势头正好,如果在一段时间内增速减缓或者下降,这个时候需要考虑如何获取新用户。

通过前面分析,新增用户是指第一次安装并且使用 的用户,咱们有一个埋点会上报 APP用户打开 这个行为,所以计算新增用户量就使用这一份数据 。
ods 层的表名为:ods_user_active
dwd 层的表名为:dwd_user_active

(2)实现需求一

(1)实现思路如下:

1:我们基于清洗之后的打开 上报的数据创建一个历史表,这个表里面包含的有 字 app xaid段,针对每天的数据基于 进行去重 xaid
2 2026 02 1 app :如果我们要计算 2026年 02月1 日的新增用户量的话,就拿这一天上报的打开 的数据,和前面的历史表进行 left join,使用 xaid进行关联,关联不上的数据则为新增数据。

(1) dws_user_active_history xaid :第一步会产生一个历史表: ,这个表中有一个 字段
dws_user_active_history
xaid
a1
b1
c1
d1

(2) app :第二步会产生一个临时表,表里面包含的是那一天上报的打开 的数据
dws_user_active_20260201_tmp
xaid
a1
b1
x1
y1
z1

(3) left join :对这两个表进行
dws_user_active_20260201_tmp.xaid dws_user_active_history.xaid
a1 a1
b1 b1
x1 null
y1 null
z1 null
此时,dws_user_active_history.xaid null 为 的数据条数即为当日新增用户数

3 dws_user_new_item :将计算出来的每日新增用户信息保存到表 dws_user_new_item表中,这个表按照天作为分区,便于后期其它需求使用这个表.

4 dws_user_new_item :基于 dws_user_new_item对数据进行聚合计算,将计算出来的新增用户数量保存到结果表 中。 app_user_new_count中。

(2)接下来是第 个指标,每日新增用户量的日环比和周同比

  • 同比一般是指本期统计数据和往年的同时期的统计数据比较,例如 2026 年 2月和 2025年 2月相比较;这个统计周期也可以是按月或者周
  • 环比一般是指本期统计数据和上一期的统计数据作比较,例如2026 年2 月和 2026 年 1月 相比较;这个统计周期也可以是按周或者日

在实际工作中通过同比和环比是可以衡量某一个指标的变化速度,供产品经理做一些决策的时候使用。

日环比 =(本期的数据 - 上一期的数据)/ 上一期的数据
日环比中的时间单位是 天
周同比 = (本期的数据 - 上一期的数据 )/ 上一期的数据
周同比中的时间单位是周 (7天 )

实现思路
直接基于 进行统计即可,可以统计出来某一天的日环比和周同比 app_user_new_count
生成一个新表 app_user_new_count_ratio
里面包含日期、新增用户量、日环比、周同比

总结:
针对前面对需求的分析,我们最终在 dws层需要创建三个表
dws_user_active_20260201_tmp

dws_user_new_item

dws_user_active_history
在 app 层需要创建两个表
app_user_new_count

app_user_new_count_ratio

3) 建表

  1. dws层
create table if not exists dws_mall.dws_user_active_20260201_tmp(
    xaid    string,
	times   int
);

insert overwrite table dws_mall.dws_user_active_20260201_tmp select
xaid,
count(*) as times
from dwd_mall.dwd_user_active
where dt = '20260201'
group by xaid;


create external table if not exists dws_mall.dws_user_active_history(
    xaid    string,
	times   int
)partitioned by(dt string)
 row format delimited  
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/dws/user_active_history';
 
 
create external table if not exists dws_mall.dws_user_new_item(
    xaid    string
)partitioned by(dt string)
 row format delimited  
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/dws/user_new_item';
 
 
insert overwrite table dws_mall.dws_user_new_item partition(dt='20260201') select
duat.xaid
from dws_mall.dws_user_active_20260201_tmp duat
left join (select xaid from dws_mall.dws_user_active_history group by xaid) duah
on duat.xaid = duah.xaid
where duah.xaid is null;

insert overwrite table dws_mall.dws_user_active_history partition(dt='20260201') select
xaid,
times
from dws_mall.dws_user_active_20260201_tmp;

create external table if not exists dws_mall.dws_user_lost_item(
    xaid    string
)partitioned by(dt string)
 row format delimited  
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/dws/user_lost_item';
 
insert overwrite table dws_mall.dws_user_lost_item partition(dt='20260201') select
xaid
from dws_mall.dws_user_active_history
where dt >= regexp_replace(date_add('2026-02-01',-7),'-','')
group by xaid
having max(dt) = regexp_replace(date_add('2026-02-01',-7),'-','');

  1. app层
create external table if not exists app_mall.app_user_new_count(
    num    int
)partitioned by(dt string)
 row format delimited  
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/app/user_new_count';
 

insert overwrite table app_mall.app_user_new_count partition(dt='20260201') select
count(*) as num
from dws_mall.dws_user_new_item
where dt = '20260201';


create external table if not exists app_mall.app_user_new_count_ratio(
    num    int,
	day_ratio    double,
	week_ratio    double
)partitioned by(dt string)
 row format delimited  
 fields terminated by '\t'
 location 'hdfs://bigdata01:9000/data/app/user_new_count_ratio';
 
# 日环比,周同比
insert overwrite table app_mall.app_user_new_count_ratio partition(dt='20260201') select
num,
(num-num_1)/num_1 as day_ratio,
(num-num_7)/num_7 as week_ratio
from(
    select
    dt,
    num,
    lead(num,1) over(order by dt desc) as num_1,
    lead(num,7) over(order by dt desc) as num_7
    from app_mall.app_user_new_count
	where dt >=regexp_replace(date_add('2026-02-01',-7),'-','')
) as t
where dt = '20260201';

4)开发脚本
针对 层抽取脚本 dws
(1) :表初始化脚本 初始化执行一次
dws_mall_init_table_1.sh

#!/bin/bash
# 需求一:每日新增用户相关指标
# dws 层数据库和表初始化脚本,只需要执行一次即可
# 由于这个表需要每天创建一个,用完之后就删除,所以选择把这个建表语句放到添加分区
数据的表中
#create table if not exists dws_mall.dws_user_active_20260201_tmp(
# xaid string,
# times int
#);
hive -e "
create database if not exists dws_mall;
create external table if not exists dws_mall.dws_user_active_history(
 xaid string,
times int
)partitioned by(dt string)
row format delimited
fields terminated by '\t'
location 'hdfs://bigdata01:9000/data/dws/user_active_history/';
create external table if not exists dws_mall.dws_user_new_item(
xaid string
)partitioned by(dt string)
row format delimited
fields terminated by '\t'
location 'hdfs://bigdata01:9000/data/dws/user_new_item/';
"

(2) :添加分区数据脚本 每天执行一次
dws_mall_add_partition_1.sh

#!/bin/bash
# 需求一:每日新增用户相关指标
# 每天凌晨执行一次
# 默认获取昨天的日期,也支持传参指定一个日期
if [ "z$1" = "z" ]
then
dt=`date +%Y%m%d --date="1 days ago"`
else
dt=$1
fi
hive -e "
create table if not exists dws_mall.dws_user_active_${dt}_tmp(
xaid string,
times int
);
insert overwrite table dws_mall.dws_user_active_${dt}_tmp select
xaid,
count(*) as times
from dwd_mall.dwd_user_active
where dt = '${dt}'
 group by xaid;
-- 注 意 : 考 虑 掉 脚 本 重 跑 的 情 况 , 所 以 在 这 里 面 每 次 执 行 的 时 候 都 会 先 删 除
dws_user_active_history 表中指定分区的数据
-- dws_user_active_history 因为在计算每日新增用户的时候需要和 进行关联查询。
alter table dws_mall.dws_user_active_history drop partition(dt='${dt}');
insert overwrite table dws_mall.dws_user_new_item partition(dt='${dt}') select
duat.xaid
from dws_mall.dws_user_active_${dt}_tmp duat
left join (select xaid from dws_mall.dws_user_active_history group by xaid) duah
on duat.xaid = duah.xaid
where duah.xaid is null;
insert overwrite table dws_mall.dws_user_active_history partition(dt='${dt}') select
xaid,times from dws_mall.dws_user_active_${dt}_tmp;
"

针对 app 层抽取脚本
1 :表初始化脚本 ( 初始化执行一次 )
app_mall_init_table_1.sh

#!/bin/bash
# 需求一:每日新增用户相关指标
# app 层数据库和表初始化脚本,只需要执行一次即可
hive -e "
create database if not exists app_mall;
create external table if not exists app_mall.app_user_new_count(
num int
)partitioned by(dt string)
row format delimited
fields terminated by '\t'
location 'hdfs://bigdata01:9000/data/app/user_new_count';
 create external table if not exists app_mall.app_user_new_count_ratio(
num int,
day_ratio double,
week_ratio double
)partitioned by(dt string)
row format delimited
fields terminated by '\t'
location 'hdfs://bigdata01:9000/data/app/user_new_count_ratio';
"

2:添加分区数据脚本(每天执行一次)
app_mall_add_partition_1.sh

#!/bin/bash
# 需求一:每日新增用户相关指标
# 每天凌晨执行一次
# 默认获取昨天的日期,也支持传参指定一个日期
if [ "z$1" = "z" ]
then
dt=`date +%Y%m%d --date="1 days ago"`
else
dt=$1
fi
# 转换日期格式, 20260201 改为 2026-02-01
dt_new=`date +%Y-%m-%d --date="${dt}"`
hive -e "
insert overwrite table app_mall.app_user_new_count partition(dt='${dt}') select
count(*) as num
from dws_mall.dws_user_new_item
where dt = '${dt}';
insert overwrite table app_mall.app_user_new_count_ratio partition(dt='${dt}') select
num,
(num-num_1)/num_1 as day_ratio,
(num-num_7)/num_7 as week_ratio
from
(
select
dt,
num,
lead(num,1) over(order by dt desc) as num_1,
lead(num,7) over(order by dt desc) as num_7
from app_mall.app_user_new_count
where dt >=regexp_replace(date_add('${dt_new}',-7),'-','')
) as t
where dt = '${dt}';
"

5) 验证结果
由于日环比最起码要有两天的数据,周环比最起码要有一周的数据
所以在这我们需要至少计算一周的数据
计算 2026-02-01~2026-02-02-09
针对 dws 层

sh dws_mall_add_partition_1.sh 20260201
sh dws_mall_add_partition_1.sh 20260202
sh dws_mall_add_partition_1.sh 20260203
sh dws_mall_add_partition_1.sh 20260204
sh dws_mall_add_partition_1.sh 20260205
sh dws_mall_add_partition_1.sh 20260206
sh dws_mall_add_partition_1.sh 20260207
sh dws_mall_add_partition_1.sh 20260208
sh dws_mall_add_partition_1.sh 20260209

针对 app 层

sh app_mall_add_partition_1.sh 20260201
sh app_mall_add_partition_1.sh 20260202
sh app_mall_add_partition_1.sh 20260203
sh app_mall_add_partition_1.sh 20260204
sh app_mall_add_partition_1.sh 20260205
sh app_mall_add_partition_1.sh 20260206
sh app_mall_add_partition_1.sh 20260207
sh app_mall_add_partition_1.sh 20260208
sh app_mall_add_partition_1.sh 20260209

针对 app 层查看表 app_mall.app_user_new_count和app_mall.app_user_new_count_ratio中的数据

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
01_数仓项目介绍.avi4 b4 Q* Q8 Z0 Y) C6 O! w 02_数仓采集_用户行为采集课程介绍.avi8 \7 f3 O. c- {: v# W& V$ Y& b 03_数仓采集_数仓的概念.avi8 Z# X* q/ c; }3 A* [ T 04_数仓采集_项目需求.avi6 B8 n s0 h! M4 X# j! |0 ` 05_数仓采集_项目技术选型.avi8 [% N% W, U# y5 s 06_数仓采集_系统数据流程设计.avi8 N: L Y6 D6 y 07_数仓采集_框架版本选型.avi, k8 c& `! j& B 08_数仓采集_框架版本具体型号.avi1 x& Q/ D. O' l 09_数仓采集_服务器选型.avi3 _: b. H. i! a; O8 V3 A7 [1 s0 t; B 100_业务数仓_DWS层之用户行为宽表.avi* o! `2 N, _5 u& a$ W 101_业务数仓_需求九:GMV成交总额.avi; x4 H& X( _' I8 L7 r* n3 I/ y 102_业务数仓_需求十:ADS层之用户占日活跃用户比率.avi 103_业务数仓_需求十一:ADS层之用户行为漏斗分析.avi 104_业务数仓_用户购买商品明细表(宽表).avi 105_业务数仓_需求十二:ADS层品牌复购率.avi 106_业务数仓_需求十三:求每个等级的用户对应的复购率前十的商品排行(学生分享).avi6 e) h" C# G2 X+ z6 B 107_业务数仓_数据可视化.avi! @5 r5 g- n0 f, J3 l 108_业务数仓_Azkaban安装.avi( r9 z2 L3 \% G' k9 [: t9 K 109_业务数仓_GMV指标获取的全调度流程.avi& O, S. M2 Q# o 10_数仓采集_集群资源规划设计.avi 110_业务数仓_拉链表理论.avi 111_业务数仓_拉链表制作.avi+ k: N4 e; P4 X; ?( i' O0 {0 u. M9 Y 112_业务数仓_业务数仓项目总结.avi/ {1 S. ^* Y" b# M) | 113_业务数仓_即席数仓课程介绍.avi 114_即席数仓_Presto简介.avi+ r. E# z! Z4 t% o+ r8 }7 Q 115_即席数仓_Presto安装及使用.avi 116_即席数仓_Presto优化.avi% @4 x# m3 } G# h 117_即席数仓_Druid概念、特点、场景.avi 118_即席数仓_Druid对比其他框架.avi7 C4 m1 z" }# n% h( F 119_即席数仓_Druid框架原理.avi 11_数仓采集_测试集群服务器规划.avi* X" H5 S4 M1 C0 j" w 120_即席数仓_Druid数据结构.avi, V& D, ]# l" a0 R1 ?) n; L f 121_即席数仓_Druid安装.avi 122_面试题_总体架构.avi! c' O1 I8 T6 n Q 123_面试题_技术框架.avi 124_面试题_用户行为、业务数据、即席查询.avi4 N2 j# j6 P% O" a 125_面试题_开发经验.avi3 b$ C' k; H" B2 p# c( \ 126_CDH数仓_课程介绍.avi9 _. V/ m% J5 ^* s/ g+ f; g( s 127_CDH数仓_CM简介及架构.avi8 ]' ]* B! X' j. Z9 [ 128_CDH数仓_CM安装环境准备.avi, Q8 k8 x/ j3 v 129_CDH数仓_CM、Hadoop、Zookeeper安装.avi7 z) @! o) G0 @4 s; J 12_数仓采集_埋点数据基本格式.avi 130_CDH数仓_采集Flume的安装.avi# V L4 F& x1 t* }( Z8 F' o9 g' ` 131_CDH数仓_Kafka安装.avi" N8 o- i b/ W) o3 j8 j/ a/ g 132_CDH数仓_测试Flume和Kafka安装.avi 133_CDH数仓_消费Flume配置完成.avi6 ?$ m3 H4 m; C# ^$ j 134_CDH数仓_Hive、Oozie、Hue安装.avi# ]& Y, M2 |) A( o# Y( b& w 135_CDH数仓_用户行为数仓ODS层导数据.avi 136_CDH数仓_用户行为数仓完结.avi. F4 z* v& a; q" }% V* \ 137_CDH数仓_业务数据生成.avi7 W7 \$ ~$ n% w2 N, {( A; l! }8 K: S 138_CDH数仓_业务数仓完结.avi! N7 f. d0 U2 N( }' w) P- b" S 139_CDH数仓_Oozie执行前准备.avi 13_数仓采集_事件日志数据(上).avi2 S' ` H& ^& S3 a1 X 140_CDH数仓_Oozie任务编写及运行.avi 141_CDH数仓_即席查询数仓搭建Impala.avi 142_CDH数仓_Spark安装及总结.avi 14_数仓采集_事件日志数据(下).avi 15_数仓采集_日志生成代码编写.avi4 |* G) Z3 J4 ]/ b9 z$ @ 16_数仓采集_Logback日志打印控制.avi 17_数仓采集_服务器准备.avi 18_数仓采集_Hadoop安装.avi 19_数仓采集_项目经验之HDFS多目录配置.avi 20_数仓采集_项目经验之支持LZO压缩配置.avi j3 Q& D8 m* G9 R Q$ G 21_数仓采集_项目经验之基准测试.avi 22_数仓采集_项目经验之HDFS参数调优.avi; F" t) F) H7 W' {& L% n3 H ~7 s 23_数仓采集_Zookeeper安装.avi6 c1 v9 x4 \% K5 D. \0 M 24_数仓采集_项目经验之ZK集群启动停止脚本.avi( i1 P# ^( y1 Q- a 25_数仓采集_生成测试日志.avi 26_数仓采集_集群日志生成启动脚本.avi 27_数仓采集_集群时间同步修改脚本.avi, n2 a/ j1 @) t* d w 28_数仓采集_集群所有进程查看脚本.avi 29_数仓采集_每日回顾.avi; R" Y P2 X, E/ [+ B' j# ~& K. e 30_数仓采集_日志采集Flume安装.avi* V0 |0 U7 o- @* R; w) M 31_数仓采集_Flume组件及配置.avi 32_数仓采集_日志采集Flume配置分析.avi U6 j% Q4 F$ T6 U5 ^ 33_数仓采集_ETL拦截器.avi 34_数仓采集_分类型拦截器.avi! b5 ^. a8 ^; }$ x8 z) l2 U3 }" p 35_数仓采集_日志采集Flume启动停止脚本.avi2 ~/ r- J: h$ U, q/ e# e7 k% M 36_数仓采集_Kafka集群安装.avi3 L6 `7 F& o/ U6 F" U5 U 37_数仓采集_Kafka集群启动停止脚本.avi 38_数仓采集_Kafka Manager安装及脚本.avi& h9 z' v' g0 ^. }0 j 39_数仓采集_项目经验之Kafka压力测试.avi7 ~8 m+ w$ q/ G$ ?- _- K 40_数仓采集_项目经验之Kafka机器数量计算.avi 41_数仓采集_消费Kafka数据Flume.avi 42_数仓采集_项目经验之Flume内存优化.avi; q3 Q6 E! I, d7 n& k# {# B6 K 43_数仓采集_项目经验之Flume组件.avi- S+ J+ s/ {5 S0 d 44_数仓采集_采集通道启动停止脚本.avi! Q; X6 }4 C" g. f 45_数仓采集_调试经验.avi! P; q2 w N1 c i5 Z' c; i" i' O- x 46_数仓采集_面试题(Linux、Shell、Hadoop).avi2 R" A6 R7 D' p9 h( i. \ I" F9 w 47_数仓采集_面试题(Flume、Kafka).avi& A1 w0 W) S1 ~# i& n, } ~6 o( b& o 48_用户行为数仓_每日回顾.avi% U( @. v7 D* C* B W J 49_用户行为数仓_用户行为数仓课程介绍.avi 50_用户行为数仓_为什么要分层.avi! J- C* F* K' R* l 51_用户行为数仓_数仓分层.avi4 W _. ]: j5 U; l$ Q9 l. Q [/ u 52_用户行为数仓_数据集市与数据仓库概念.avi5 U5 c# e( Y8 B% c 53_用户行为数仓_数仓命名规范.avi 54_用户行为数仓_Hive&MySQL;安装.avi 55_用户行为数仓_Hive运行引擎Tez.avi! L# \% m0 s- F; A" q 56_用户行为数仓_项目经验之元数据备份.avi 57_用户行为数仓_ODS层启动日志和事件日志表创建.avi 58_用户行为数仓_ODS层加载数据脚本.avi' J8 ^- I/ b5 O3 Y) @9 a- h 59_用户行为数仓_DWD层启动日志建表及导入数据.avi9 h3 [. T0 F1 ~6 s! i/ J 60_ 用户行为数仓_DWD层启动表加载数据脚本.avi$ \1 Z0 Z/ m; d: F+ B5 u$ c 61_用户行为数仓_DWD层事件基础明细表创建.avi; Y& i+ U7 S6 P" X) T3 n! V 62_用户行为数仓_自定义UDF函数(解析公共字段).avi7 Q/ i) X8 O6 S0 M( V' m- ]- M 63_用户行为数仓_自定义UDTF函数(解析事件日志基础明细表).avi 64_用户行为数仓_DWD层数据解析脚本.avi 65_用户行为数仓_DWD层事件表加载数据脚本.avi 66_用户行为数仓_今日回顾.avi* e9 W+ P$ {5 ?! x9 [- e5 ]# a 67_用户行为数仓_业务术语.avi 68_用户行为数仓_日期的系统函数.avi 69_用户行为数仓_每日活跃设备明细.avi 70_用户行为数仓_每周活跃设备明细.avi 71_用户行为数仓_每月活跃设备明细.avi 72_用户行为数仓_DWS层加载数据脚本.avi- i* h$ d' Q7 M1 G0 ?% f 73_用户行为数仓_需求一:ADS层日活、周活、月活用户数.avi- I- Q* u3 n; v. n, T 74_用户行为数仓_每日增设备明细表.avi/ B# |; {' c4 y6 y9 \2 r( i 75_用户行为数仓_需求二:ADS层每日增设备表.avi 76_用户行为数仓_用户留存分析.avi 77_用户行为数仓_1、2、3、n日留存用户明细.avi v. ^5 Q1 \ `9 V4 Q 78_用户行为数仓_需求三:ADS层留存用户和留存比率.avi 79_用户行为数仓_数据准备.avi 80_用户行为数仓_需求四:沉默用户.avi 81_用户行为数仓_需求五:本周回流用户数.avi 82_用户行为数仓_需求六:流失用户.avi2 x0 _( B( `, z4 j$ |5 S2 Z4 T- e% R) ] 83_用户行为数仓_需求七:最近连续3周活跃用户数.avi 84_用户行为数仓_需求八:最近七天内连续三天活跃用户数.avi- C- l" J O8 v3 x- J$ r 85_用户行为数仓_用户行为数仓业务总结.avi- V4 n, x9 B* A( P6 n/ e! E! U 86_用户行为数仓_Hive企业面试题总结.avi3 l9 J8 F2 t0 p& S! O! ^ 87_业务数仓_业务数仓课程介绍.avi 88_业务数仓_电商业务与数据结构简介.avi 89_业务数仓_表的分类.avi# X. Q* ~# f7 F P' @; i+ z 90_业务数仓_同步策略.avi; k0 r$ A: b9 E) @1 W 91_业务数仓_范式理论.avi5 ~2 z+ A' F+ N- J" S% r 92_业务数仓_雪花模型、星型模型和星座模型.avi 93_业务数仓_配置Hadoop支持Snappy压缩.avi 94_业务数仓_业务数据生成.avi 95_业务数仓_Sqoop安装及参数.avi% s/ l0 E. R( Y9 s, h3 k 96_业务数仓_Sqoop导入数据.avi4 {8 ~! a8 o4 `" y: p5 {1 ^ 97_业务数仓_ODS层建表及数据导入.avi 98_业务数仓_DWD层建表及导入数据.avi 99_业务数仓_需求讲解.avi7 X6 q, I3 Y+ F: N8 h 源码笔记资料.rar0 W

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值