离线数仓总结

离线数仓总结
一、1、背景介绍(某APP上线后,由于业务模式新颖,市场需求量大,经过一段时间的精心运营后,逐渐积累起了上千万会员,以及三四百万的日活量, app的业务功能和产品种类、数量也急速膨胀;主要问题有:营销分析断层;产品迭代无法量化;用户运营不精准;全局运营指标监控不实时)
2、需求总览:流量域分析
2.1、基础数据分析(整体概况、用户获取、活跃与留存、事件转化、用户特征)
2.2、基础数据分析指标概览
整体概况:产品整体的使用情况,包括用户量、访问情况、留存等帮助对产品整体指标有一个大致的了解(累计用户量、每日新增用户量、每日的全部访问人数、次数新老用户访问占比、新用户/全部用户的7日留存等)
用户获取
渠道访问(每个渠道的用户的使用情况,包括渠道中新用户的占比、留存等,了解产品在获客层面上的优势与不足;其中 App 的渠道数据,会根据 iOS,Android 进行细分)
新增用户量:全部新用户数量,包括自然流量和渠道流量
渠道新增用户量:仅计算渠道流量新增用户数(人均访问时长)
版本数据
App 每个版本的使用情况,帮助了解在产品升级的过程中,是否在活跃和留存方面有所改善(版本访问流量、人均访问时长、各版本留存:各版本的用户7日留存
活跃与留存
访问流量
产品的每日访问数据,指标集中在新老用户的访问行为上,提供访问次数、时长、次数分布、访问时段高峰等指标,帮助了解新老用户在使用产品时的一些行为特征
访问用户数
新老用户访问占比新老用户人均使用时长新老用户启动/访问次数 每日/每周启动时段(用户每日访问产品的时段分布、用户每周访问产品的星期分布)
用户留存
提供用户7日,次日,次周,次月留存、的数据,帮助了解新老用户的使用粘性
事件转化
各类关键事件(如收藏,分享,转发,加购等),发生次数、人数以及分布情况、新老用户事件发生次数/人数/人均次数、事件次数的分布
收益类事件转化
用户自定义收益类事件,神策会自动生成该事件的发生次数、人数以及分布情况,会根据您选择的数值类型属性,计算该数值的总值、人均值以及次均值、新老用户收益事件发生次数/人数/人均次数、新老用户收益事件
用户特征(访问省份分布、访问城市分布、访问性别分布、访问操作系统分布、新老用户占比)
2.3进阶用户行为分析
漏斗分析(漏斗模型主要用于分析一个多步骤过程中每一步的转化与流失情况)(举例来说,用户购买商品的完整流程可能包含以下步骤:1.浏览商品;2.将商品添加进购物车;3.结算购物车中的商品;4.选择送货地址、支付方式;5.点击付款;6.完成付款)
留存分析(留存分析是一种用来分析用户参与情况/活跃程度的分析模型,考查进行初始行为后的用户中,有多少人会进行后续行为,这是衡量产品对用户价值高低的重要指标)
分布分析、归因分析、用户路径分析、间隔分析、自定义查询
3、需求总览:业务域分析
3.1交易域
购物车分析(多维分析:品类、人群、时段)(7日加购总数、提交总数、取消总数)
订单GMV分析(多维分析:终端,地域,品类)(当日GMV总额、当日订单支付总额、当日下单人数客单价分析、7日取消订单数、取消订单用户数、退货次数、退货用户数、GMV近30日变化趋势
GMV各端贡献情况(平台类型,GMV,订单量,下单人数,客单价,笔单价)(下单金额分布(1000以下,1000-2000,2000-3000,3000-4000,4000+)))
7日商品销售情况(商品名称,商品品类,店铺,购买次数,购买人数,销售额)、各品类商品销量趋势(品类,日期,购买次数,购买人数,销售额)、店铺商品销量占比(店铺,购买次数,购买人数,销售额)
复购分析(多维分析:品类,人群,终端,地域)7日各端复购率、7日购买频次分析(1次,2-3次,3-4次,4-5次)、订单实时分析、订单量分钟级、订单量小时级、订单用户趋势分析)
3.2营销域
优惠券分析
优惠券抵扣力度(优惠券,日期,抵扣金额)、优惠券使用情况(优惠券,日期,使用次数)
团购分析(团购订单趋势、参团用户趋势、各品类开团数、各品类成团数
秒杀限时购分析(秒杀订阅人数、秒杀成交订单趋势、秒杀支付类型趋势)
其他营销活动(国庆大豪礼、金秋大放送、活动地域趋势分析、活动订单趋势分析)
3.3运营活动域(广告运营位分析、曝光度、点击率、转化率、拉新注册分析、渠道分布、转化率
3.4会员域(消费情况、充值情况、会员等级分布)
4、整体方案设计
4.1数据收集(主要数据类别:用户行为日志数据、业务数据、历史数据、其他第三方数据)
4.2核心处理流程
数据采集汇聚
用户行为数据(1、日志前端埋点,生成日志数据;2、数据采集;3、kafka缓存;4、Flume采集落地hdfs;5、日志预处理;6、落hive数仓明细层)
业务数据(1、业务系统增删改数据库,形成数据;2、Sqoop/DataX数据抽取;3、落hive数仓明细层;4、增量合并处理;)
数据仓库 & OLAP分析平台
模型设计
数仓分层运算
各类数据的输出
需要查询的明细数据,入库hbase、(用户画像标签明细,用户行为序列明细)、需要做规范模型分析的,由kylin映射、 需要做深入行为分析的,入库clickhouse(或者kudu+impala)
数据服务
固定报表查询(需要查询的固定报表数据,入库mysql/HBASE)(日新、日活、pv、留存、核心业务转化、关键路径转化、关键事件报表,gmv日报周报月报等)
规范多维分析(原料数据,入库kylin,基于kylin的restapi,开发上层olap平台)
进阶深入用户行为分析(入库kudu+impala (click house),基于jdbc,开发上层olap平台)
4.3管理辅助系统
Azkaban任务调度系统、Sqoop/datax业务库数据抽取、Atlas元数据和血缘管理、其他自研系统
5、数据埋点说明
日志埋点,是业务系统开发端的工作(作为数据开发人员的我们,仅需提出数据埋点需求,对具体实现技术仅作基本了解)
5.1埋点技术介绍
5.2埋点日志数据说明
埋点生成的日志数据,统一设计为JSON格式;
各个终端渠道的埋点日志,都由公共属性字段,和事件属性字段组成;1、不同终端渠道,公共属性字段略有不同;2、事件属性则根据事件类型,灵活多样;
6、业务数据说明
业务数据,是由业务系统(程序)根据用户的业务操作,在业务系统数据库(比如mysql)中记录下来的重要事务性数据(比如,订单信息,用户注册信息,积分信息,物流信息,商品信息等,通常至少几十张表,业务越丰富,表越多,上百是常事)
6.1、订单交易信息表(oms_order_item、oms_order_operate_history、oms_order_return_apply、oms_order_return_reason);
6.2、产品信息表(pms_album、pms_album_pic、pms_brand、pms_comment、pms_product、pms_product_category);
6.3、优惠券信息表(sms_coupon);
6.4、限时购秒杀信息表(sms_flash_promotion);
6.5、营销广告位信息表(sms_home_advertise);
6.6、会员信息表(ums_member、ums_member_level、ums_member_login_log);
6.7、购物车信息表(oms_cart_item)等等
7、数据建模理论
7.1经典建模方法论:三范式建模
第一范式(1NF):每一列都是不可分割的原子数据项
第二范式:在1NF基础上,非码属性必须完全依赖于主码(在1NF基础上消除非主属性对主码的部分函数依赖)
第三范式(3NF):在2NF的基础上,任何的非主属性不依赖于其他非主属性 (在第二范式基础上消除传递依赖)
7.2 经典建模方法论:维度建模
基本概念
事实:现实发生的某件事
维度:衡量事实的一个角度
事实表:记录事实的表;比如,订单表,注册表,购物车,退货表,浏览日志表
维度表:对维度的详细描述信息;比如,地域维表,产品维表,品类维表,栏目维表,时间维表;
对事实表,假如要计算pv数(指标 | 度量)
我们可以按如下口径来统计:
总pv数
每个栏目的pv数
每个省份的pv数
每个商品品类的pv数
每个省份下每个栏目的pv数
从这些需求中可以看出,同一个指标,可以通过多种角度(口径)去统计
这些角度,或口径,就叫“维度!”
维度组合中的维度越多,统计出来的事实指标粒度越细
维表举例
栏目维度表:
栏目id,栏目名称
lm1,生鲜水产
lm2,冲调饮品
lm3,智能设备
地域码维表:
地域码 省 市
11010 湖北省,武汉市
01010 山西省,临汾市
时间维表:
日期 季度 周数 周几 销售季 活动期间
2019-10-21 4 38 monday
2019-10-21 4 38 monday
维表的作用:可以对统计维度进行人性化的诠释,可以丰富维度内容;
维度建模经典模型
星型模型(星型模式的核心是一个大的中心表(事实表),一组小的附属表(维表))
雪花模型(雪花模式是星型模式的扩展,其中某些维表被规范化,进一步分解到附加表(维表)中)
星座模型(数据仓库由多个主题构成,包含多个事实表,而维表是公共的,可以共享,这种模式可以看做星型模式的汇集,因而称作星系模式或者事实星座模式)
8、项目建模:流量域方案
以Event事件表为中心事实表,以user,页面频道信息,产品信息,活动信息等为关联维表
9、项目建模:业务域方案
按不同事实主题建设宽表(交易域、营销域、活动域、广告域、会员域)
10、项目建模:画像域方案
用户基本属性标签表、用户订单属性标签表、用户退换货属性标签表、用户购物车属性标签表、用户活跃属性标签表、用户偏好属性标签表

二、数仓整体说明
1.1技术选型(数据采集:FLUME、存储平台:HDFS、基础设施:HIVE 、运算引擎:SPARK SQL、资源调度:YARN、任务调度:AZKABAN、元数据管理:ATLAS)
1.2分层设计:
分层原因(数据仓库中的数据表,往往是分层管理、分层计算的,所谓分层,具体来说,就是将大量的数据表按照一定规则和定义来进行逻辑划分;
ADS层: 应用服务层;DWS层:数仓汇总层;DWD层:数仓明细层;ODS层:操作数据(最原始的数据)层 – 贴源层;DIM层:存储维表
ODS层:对应着外部数据源ETL到数仓体系之后的表!
DWD层:数仓明细层;一般是对ODS层的表按主题进行加工和划分;本层中表记录的还是明细数据;
DWS层:数仓汇总层;
ADS层: 应用层,主要是一些结果报表;
分层的意义:数据管理更明晰;运算复用度更高;需求开发更快捷;便于解耦底层业务(数据)变化;
分层详解
ODS层(数据内容:存放flume采集过来的原始日志,存储格式以json格式文本文件存储,存储周期:3个月)
DWD层(数据内容:对ODS层数据做ETL处理后的扁平化明细数据,存储格式:以orc / parquet文件格式存储,存储周期:6个月)
DWS层(数据内容:根据主题分析需求,从DWD中轻度聚合后的数据,存储格式:以ORC/PARQUET文件格式存储,存储周期:1年)
ADS层(数据内容:根据业务人员需求,从DWS计算出来的报表存储格式:以ORC/PARQUET文件格式存储,存储周期:3年)
DIM层(存储各种维表)
1.3模型设计:
ODS层:操作数据层,建模方法:与原始日志数据保持完全一致,数据备份;
存储周期:相对来说,存储周期较短;视数据规模,增长速度,以及业务的需求而定;对于埋点日志数据ODS层存储,通常可以选择3个月或者半年;存1年的是土豪公司(或者确有需要)
数据规模
假如:公司用户规模1000万,平均日活400万,平均每个用户访问1.2次,每个用户平均每次访问时长10分钟,按经验,每个用户平均每 5~10 秒产生一条事件,则每次访问,将产生10分钟60秒/10 = 60条事件日志,则,每天产生的日志总条数:400万1.260条 = 28800 万=2.88亿条日志(2-3亿)
每条日志大小平均为0.5k,则每日增量日志大小为:28800万
0.5k = 28800
5M= 144G(100多个G),每月累积增量为:144G30 = 4.3T(2-4T),假如要存储1年的数据量,则1年的累计存储量为:51.6T(30-50T),考虑,增长趋势: 预估每月增长20%,则1年的累计存储量为:接近100T
注:在这里也可以估算实时流式计算中的数据量,假如最高峰值时,每秒同时在线人数有10万,则在此峰值期间,每秒将有50万条日志产生
数据采集:采集源:KAFKA ;TOPIC:app_log, wx_log,web_log;采集工具:FLUME;
创建外部表:由于原始数据是普通文本文件,而文件内容是json格式的一条一条记录,将数据按json格式进行映射(这需要外部工具包JsonSerde 的支持)
下载 json-serde-1.3.8-jar-with-dependencies.jar 并上传到 Hive的/lib库目录下
如果需要,也可以把本jar包安装到本地maven库
bin\mvn install:install-file -Dfile=d:/json-serde.1.3.8.jar -DgroupId=“org.openx.data” -DartifactId=json-serde -Dversion=“1.3.8” -Dpackaging=jar
create external table ods.app_event_log
(
account string,
appId string,
appVersion string,
carrier string,
deviceId string,
deviceType string,
eventId string,
ip string,
latitude double,
longitude double,
netType string,
osName string,
osVersion string,
properties map,
releaseChannel string,
resolution string,
sessionId string,
timeStamp bigint
)
partitioned by (y string,m string,d string)
row format serde ‘org.openx.data.jsonserde.JsonSerDe’
stored as textfile
;
DWD层(ods—>(etl)dwd)(spark)(dwd.app_event_dtl)
建模思想:不完全星型模型,事实表中,不是所有维度都按维度主键信息存储(维度退化)
地域维度信息:年月日周等时间维度信息,这些维度信息,基本不会发生任何改变,并且在大部分主题分析场景中,都需要使用,直接在事实表中存储维度值
页面信息:页面类别信息,频道信息,业务活动信息,会员等级信息等,可能发生缓慢变化的维度信息,事实表中遵循经典理论存储维度主键,具体维度值则在主题分析计算时临时关联
事实表(app_event_detail:APP-Event事件明细表;web_event_detail:WEB-Event事件明细表;wxapp_event_detail:小程序-Event事件明细表)
维度表coupon_info、ad_info、campain_info、lanmu_info、page_info、page_type、pindao_info、promotion_location、huodong_info、miaosha_info、product、product_detail、product_type、shop_info、tuangou_info、user_info)
清洗过滤
1,去除json数据体中的废弃字段(前端开发人员在埋点设计方案变更后遗留的无用字段):
2,过滤掉json格式不正确的(脏数据)
3,过滤掉日志中account及deviceid全为空的记录
4,过滤掉日志中缺少关键字段(event/eventid/sessionid 缺任何一个都不行)的记录
5,过滤掉日志中不符合时间段的记录(由于app上报日志可能的延迟,有数据延迟到达)
6,对于web端日志,过滤爬虫请求数据(通过useragent标识来分析)
数据解析
SESSION分割
1,对于web端日志,按天然session分割,不需处理
2,对于app日志,由于使用了登录保持技术,导致app进入后台很长时间后,再恢复前台,依然是同一个session,不符合session分析定义,需要按事件间隔时间切割(业内通用:30分钟)
3,对于wx小程序日志,与app类似,session有效期很长,需要按事件间隔时间切割(业内通用:30分钟)
数据规范处理(Boolean字段,在数据中有使用1/0标识的,也有使用true/false表示的,统一为Y/N/U,字符串类型字段,在数据中有空串,有null值,统一为null值)
维度集成
1,将日志中的GPS经纬度坐标解析成省、市、县(区)信息;(为了方便后续的地域维度分析)
2,将日志中的IP地址解析成省、市、县(区)信息;(为了方便后续的地域维度分析)
注:app日志和wxapp日志,有采集到的用户事件行为时的所在地gps坐标信息,web日志则无法收集到用户的gps坐标,但可以收集到ip地址,gps坐标可以表达精确的地理位置,而ip地址只能表达准确度较低而且精度较低的地理位置
3,将日志中的时间戳,解析出年、季度、月、日、年第几周、月第几周、年第几天
GEOHASH编码介绍
Geohash编码是一种地理位置编码技术,它可以将一个gps坐标(含经纬度)点,转化为一个字符串;
wx3y569
wx3y434
通过编码后得到的字符串,表达的是:包含被编码gps坐标点的一个矩形范围;
GEOHASH编码原理
在地球经纬度范围内,不断通过二分来划分矩形范围,通过观察gps坐标点所落的范围,来反复生成0/1二进制码,在满足精度要求后,将所得的二进制编码通过base32编码技术转成字符串码
GEOHASH码的精度
字符串长度越长,表达的精度越高,矩形范围越小,越逼近原gps坐标点;相反,长度越短,表达的精度越低,矩形范围越大;
GEOHASH编码工具包
IP查找算法
将字典中的起始ip和结束ip,都设法转成整数,这样,ip地址段就变成了整数段
接下来,将未知区域的ip按照相同方法转换成整数,则能相对方便地查找到字典数据了
具体的搜索算法,可以使用二分查找算法
IP地理位置处理工具包
开源工具包ip2region(含ip数据库)
ID_MAPPING(********************)
app的设备id和用户id绑定表生成程序
1.加载T日的日志(生成T日的绑定记录表)
2.对当天日志中的(设备,账号)组合,进行去重(只取时间最早的一条)
3.同一个设备上,对不同账号打不同的分(登录时间越早,分数越高)
3.1 先将相同设备的数据,分组
3.2 按时间先后顺序打分
(d0,List())
(d1,List((u1,11,100), (u2,13,90)))
(d2,List((u2,14,100)))
(d3,List((u3,14,100)))
(d4,List((u4,15,100)))
(d5,List())
(d8,List())
(d9,List((u4,18,100)))
4.加载 T-1日的绑定记录表
(d0,(List(BindScore(u0,7,100), BindScore(u1,8,20)),u0))
(d1,(List(BindScore(u1,9,100)),u1))
(d2,(List(BindScore(u2,8,100)),u2))
(d3,(List(BindScore(u2,9,90)),u2))
(d4,(List(),d4))
(d5,(List(),d5))
5.将T日的绑定记录表 与T-1日的绑定记录表进行fullOuterJoin
(d0,(Some(List()),Some((List(BindScore(u0,7,100), BindScore(u1,8,20)),u0))))
(d1,(Some(List(BindScore(u1,11,100), BindScore(u2,13,90))),Some((List(BindScore(u1,9,100)),u1))))
(d2,(Some(List(BindScore(u2,14,100))),Some((List(BindScore(u2,8,100)),u2))))
(d3,(Some(List(BindScore(u3,14,100))),Some((List(BindScore(u2,9,90)),u2))))
(d4,(Some(List(BindScore(u4,15,100))),Some((List(),d4))))
(d5,(Some(List()),Some((List(),d5))))
(d8,(Some(List()),None))
(d9,(Some(List(BindScore(u4,18,100))),None))
(d6,(None,Some(List(BindScore(u4,18,100))))
情况1:右表(历史)根本没有这个设备
看今日的lst是否为空,如果今日的lst为空的话,guid=deviceid,如果今日的lst不为空的话,一个账号对应的account为guid,多个账号,取时间最早得分最高的account为guid(多个账号的情况下)
情况2:左表(今日)根本没有这个设备
lst和guid都保留历史的
情况3:左右表都有some,需要对两边的lst进行分数合并
如果左右两边的lst都为空,则deviceid=guid, 左右表都有some,需要对两边的lst进行分数合并,一个账号对应的account为guid,多个账号,取分数最高时间最早的account为guid(多个账号的情况下)
GUID 标识
加载当日的 guid设备绑定表,取出bean中的account,如果有值,则guid=account,否则,用deviceid去guidDict字典中查询,加载前一日的设备绑定表,标记新老访,规则: 数据上的guid如果在前日中的设备绑定表中存在,则为老访客,否则即为新访客
DWS层
建模思想
主题建模
维度建模
主要表模型(流量会话聚合天/月表、日新日活维度聚合表、事件会话聚合天/月表、访客连续活跃区间表、新用户留存维度聚合表、运营位维度聚合表、渠道拉新维度聚合表、访客分布维度聚合表、用户事件链聚合表(支撑转化分析,高级留存分析,)
1.会话聚合表(页面浏览事件的会话聚合表:一次会话,一条记录)
dws.app_pv_agg_session
CREATE TABLE DWS.APP_PV_AGG_SESSION(
guid STRING, – 全局唯一标识
session_id STRING, – 会话id
start_time BIGINT, – 会话起始时间
end_time BIGINT,
first_page STRING,
last_page STRING,
pv_cnt STRING,
isnew INT,
hour INT,
province STRING,
city STRING,
district STRING,
device_type STRING
)
PARTITIONED BY (dt STRING)
STORED AS PARQUET
;
//first_value(properties[‘pageid’]) over(partition by sessionid order by ts) as first_page,
//last_value(properties[‘pageid’]) over(partition by sessionid order by ts) as last_page,
INSERT INTO TABLE dws.app_pv_agg_session PARTITION(dt=‘2020-07-30’)
SELECT
guid,
sessionid as session_id,
min(ts) as start_time,
max(ts) as end_time,
max(first_page) as first_page,
max(last_page) as last_page,
count(1) as pv_cnt,
max(isnew) as isnew,
max(hour) as hour,
max(province) as province,
max(city) as city,
max(district) as district,
max(devicetype) as device_type
FROM
(
SELECT
guid,
sessionid,
ts,
isnew,
first_value(properties[‘pageid’]) over(partition by sessionid order by ts) as first_page,
last_value(properties[‘pageid’]) over(partition by sessionid order by ts) as last_page,
first_value(hour(from_unixtime(cast(ts/1000 as bigint)))) over() as hour,
first_value(province) over(partition by sessionid order by ts) as province,
first_value(city) over(partition by sessionid order by ts) as city,
first_value(district) over(partition by sessionid order by ts) as district,
devicetype
FROM dwd.app_event_dtl
WHERE dt = ‘2020-07-30’ AND eventid = ‘pageView’
) O
GROUP BY guid,sessionid
;
可以支撑的报表分析举例:
PV/UV/DAU日活跃用户/DNU日新增用户概况日报表,周报表,月报表、访问次数分析、访问深度分析、访问时长分析、访问入口页分析等
2.用户分布分析主题(用户分布,无非就是各种维度下的用户数,比如,不同地域的用户数,不同app版本的用户数,不同设备类型的用户数,不同性质(新、老)的用户数;
可以看出,其本质的度量就是“用户数”,而用户数及所需的关联维度,都可以很方便地从 dws.app_pv_agg_session表中得出
可以支撑的报表分析举例:新老访客占比、访客app版本分布、访客地域分布、访客手机型号分布
3.交互事件会话聚合表
dws.app_itr_agg_session(交互事件(点赞,收藏,分享)会话聚合表)
create table dws.app_itr_agg_session
(
dtstr string, – 日期
guid string, – guid
session_id string, – 会话id
event_id string, – 事件类型
cnt int, – 发生次数
product_id string, – 商品id
page_id string, – 页面id
share_method string, – 分享方式
province string,
city string,
district string,
device_type string
)
partitioned by (dt string)
stored as parquet
;
insert into table dws.app_itr_agg_session partition (dt = ‘2020-07-30’)
select ‘2020-07-30’ as dtstr,
guid,
sessionid as session_id,
eventid as event_id,
properties[‘productid’] as product_id,
properties[‘pageid’] as page_id,
properties[‘sharemethod’] as share_method,
province as province,
city as city,
district as district,
devicetype as device_type,
count(1) as cnt
from dwd.app_event_dtl
where eventid in (‘collect’, ‘thumbup’, ‘share’) and dt = ‘2020-07-30’
GROUP BY guid, sessionid, eventid, properties[‘productid’]
, properties[‘pageid’], properties[‘sharemethod’],
province, city, district, devicetype
;
可以支撑的报表分析举例:各栏目x事件发生次数、各栏目x事件发生人数、各item各分享平台发生次数、各item各分享平台发生人数,日点赞item排行榜,日收藏item排行榜
4.用户活跃区间记录表
dws.app_user_active_range
– 源表:T日 流量聚合表:dws.app_pv_agg_session 区间记录表:dws.app_user_active_range T-1日
– 目标:区间记录表:dws.app_user_active_range T日
– 计算逻辑
– 1.将区间表中所有用户的所有区间记录进行处理(已封闭区间原样保留,开放区间得判断今日是否有活跃,如果无,则将开放区间封闭)
– 2.将区间表中昨天没有活跃的用户找出来,跟今日活跃老用户join,生成老用户的新活跃区间
– 3.从流量表中过滤出新用户,为这些新用户生成活跃区间
– 老用户,老区间的处理
– 老用户,新开区间的处理
– 新用户,新开区间的处理
create table dws.app_user_active_range
(
dtstr string, – 计算日期
guid string, – guid
first_dt string, – 用户首访日(新增日)
rng_start string, – 连续活跃区间起始日期
rng_end string – 连续活跃区间结束日期
)
partitioned by (dt string) stored as parquet
;
with a as (
select *
from dws.app_user_active_range
where dt = ‘2020-07-29’
),
oldu as (
select guid
from dws.app_pv_agg_session
where dt = ‘2020-07-30’ and isnew = 0
group by guid
),
newu as (
select guid
from dws.app_pv_agg_session
where dt = ‘2020-07-30’ and isnew = 1
group by guid
)
INSERT INTO TABLE app_user_active_range PARTITION (dt = ‘2020-07-30’)
– 老用户,老区间的处理
select ‘2020-07-30’ as dtstr,
a.guid,
a.first_dt,
a.rng_start,
if(a.rng_end = ‘9999-12-31’ and oldu.guid is null, ‘2020-07-29’, a.rng_end) as rng_end
from a
left join oldu on a.guid = oldu.guid
UNION ALL
– 老用户,新开区间的处理
select ‘2020-07-30’ as dtstr,
o1.guid,
o1.first_dt,
‘2020-07-30’ as rng_start,
‘9999-12-31’ as rng_end
from (
select guid,
max(first_dt) as first_dt
from a
group by guid
having max(rng_end) != ‘9999-12-31’
) o1
join oldu on o1.guid = oldu.guid
UNION ALL
– 新用户,新开区间的处理
select ‘2020-07-30’ as dtstr,
newu.guid,
‘2020-07-30’ as first_dt,
‘2020-07-30’ as rng_start,
‘9999-12-31’ as rng_end
from newu
;
可以支撑的报表分析举例:最近一个月内,有过连续活跃10+天的人、最近一个月内,每个用户的平均活跃天数、最近一个月内,连续活跃1-10天的人数,10-20天的人数,20-30天的人数、最近一周内,…、最近一个月内,最大沉默天数超20天的人
5.新用户留存表(dws.app_user_retention)
– 源表:用户连续活跃区间记录表 dws.app_user_active_range 当天
– 目标:新用户留存表 dws.app_user_retention
我们有一张用户连续活跃区间记录表,这张表记录了每一个人的连续活跃区间的起始日和结束日,结束日如果在今天还在活跃的就是9999,
通过这张表可以知道哪些人在今天是活跃的,在今天是活跃的才是留存的,根据今天的日期减去首访日期可以得到这个人的留存天数,
根据留存天数分组,不同留存天数的人数就都算出来了
create table dws.app_user_retention(
dtstr string,
start_dt string,
retention_days int,
retention_cnt int
)
stored as parquet;
with tmp as (
select first_dt,
if(datediff(dt, first_dt)<=30,datediff(dt, first_dt),-1) as retention_days
from dws.app_user_active_range
where dt = ‘2020-07-30’ and rng_end = ‘9999-12-31’
)
insert into table dws.app_user_retention
select ‘2020-07-30’ as dtstr,
first_dt,
retention_days,
count(1)
from tmp
group by first_dt, retention_days

6.漏斗转化分析表
dws.app_funnel_model
create table dws.app_funnel_model(
dtstr string,
guid string,
funnel_name string,
funnel_step int
)
partitioned by (dt string)
stored as parquet
;
– 关键技术点
select regexp_extract(‘e1,e1,e4,e5’,’.
?(e1).?(e3).?’,2);drop table ev;
(测试数据)
create table ev(guid string,eventid string,properties map,ts bigint)
row format delimited fields terminated by ‘,’
collection items terminated by ‘|’
map keys terminated by ‘:’;
load data local inpath ‘/root/ev.txt’ into table ev;
a,e8,p1:v1|p6:v8,1
a,e1,p3:v4|p7:v1,2
a,e2,p1:v1|p6:v8,3
a,e1,p1:v1|p6:v8,4
a,e3,p4:v3|p6:v8,5
a,e4,p8:v5|p5:v3,6
a,e2,p1:v1|p6:v8,7
a,e3,p1:v1|p6:v8,8
a,e4,p1:v1|p6:v2,9
b,e3,p1:v1|p3:v8,1
b,e4,p1:v1|p6:v8,2
b,e2,p1:v1|p6:v1,3
b,e1,p3:v4|p2:v8,4
b,e4,p1:v1|p6:v8,5
b,e3,p4:v3|p6:v8,6
b,e3,p1:v1|p6:v5,7
b,e2,p1:v1|p6:v8,8
–漏斗模型:搜购
步骤1:e1, 且事件中有属性 p3 的值为 v4
步骤2:e3, 且事件中有属性 p4 的值为 v3
步骤3:e4, 且事件中有属性 p8 的值为 v5
– 最终结果:
搜购,step1,32
搜购,step2,10
搜购,step3,8
– 关键技术点
select regexp_extract(‘e1,e1,e4,e5’,’.?(e1).?(e3).?’,2);
– 开发
– 过滤掉不属于漏斗模型中的事件
with tmp as (
select
*
from ev
where (eventid=‘e1’ and properties[‘p3’]=‘v4’)
or (eventid=‘e3’ and properties[‘p4’]=‘v3’)
or (eventid=‘e4’ and properties[‘p8’]=‘v5’)
)
select
‘2020-07-30’ as dtstr,
‘搜索购买’ as model_name,
guid,
step
from
(
select
guid,
array(if(regexp_extract(evelst,’.
?(e1).?’,1)=‘e1’,1,null), if(regexp_extract(evelst,’.?(e1).?(e3).?’,2)=‘e3’,2,null),if(regexp_extract(evelst,’.?(e1).?(e3).?(e4).?’,3)=‘e4’,3,null)) as arr
from
(
select
guid,
concat_ws(’,’,collect_list(eventid)) as evelst
from tmp
group by guid
) o1
) o2
lateral view explode(arr) tmp as step
where step is not null
;
7、站内运营位分析主题
可以支撑的报表分析举例:X运营广告位日曝光量、X运营广告位曝光量分时趋势分析、X运营广告位点击量等
8、站外投放分析主题
以支撑的报表分析举例:渠道投放引流效果分析、渠道拉新分析、各渠道投放引流量分析、各渠道投放引流量拉新数量分析……
9、优惠券分析主题
可以支撑的报表分析举例:优惠券领取次数人数分析、优惠券分时段领取趋势变化分析……
10、红包分析主题
可以支撑的报表分析举例:红包领取次数、人数分析、红包分时段领取趋势变化分析
ADS
DIM
三、业务域
1、业务域的数据来自业务系统的数据库,通过sqoop(或datax)抽取到数仓的ods层,在ods层对有需要的表进行增量合并,字段选择,形成dwd明细层表,在明细层基础上,进行各类主题的数据统计、分析
主要分析的主题有:交易域分析、营销域分析、会员域分析
2、Sqoop数据抽取工具
sqoop是Hadoop中的各种存储系统(HDFS、HIVE、HBASE)和关系数据库(mysql、oracle、sqlserver等)服务器之间传送数据”的工具
核心的功能有两个:导入、导出
导入数据:MySQL,Oracle 导入数据到 Hadoop 的 HDFS、HIVE、HBASE 等数据存储系统
导出数据:从 Hadoop 的文件系统中导出数据到关系数据库 mysql 等 Sqoop 的本质还是一个命令行工具,
3.DataX数据抽取工具
Reader:Reader为数据采集模块,负责采集数据源的数据,将数据发送给Framework
Writer: Writer为数据写入模块,负责不断向Framework取数据,并将数据写入到目的端
Framework:Framework用于连接reader和writer,作为两者的数据传输通道,并处理缓冲,流控,并发,数据转换等核心技术问题
核心模块介绍:
DataX完成单个数据同步的作业,我们称之为Job,DataX接受到一个Job之后,将启动一个进程来完成整个作业同步过程,DataX Job模块是单个作业的中枢管理节点,承担了数据清理、子任务切分(将单一作业计算转化为多个子Task)、TaskGroup管理等功能
DataXJob启动后,会根据不同的源端切分策略,将Job切分成多个小的Task(子任务),以便于并发执行,Task便是DataX作业的最小单元,每一个Task都会负责一部分数据的同步工作
切分多个Task之后,DataX Job会调用Scheduler模块,根据配置的并发数据量,将拆分成的Task重新组合,组装成TaskGroup(任务组),每一个TaskGroup负责以一定的并发运行完毕分配好的所有Task,默认单个任务组的并发数量为5
每一个Task都由TaskGroup负责启动,Task启动后,会固定启动Reader—>Channel—>Writer的线程来完成任务同步工作
DataX作业运行起来之后, Job监控并等待多个TaskGroup模块任务完成,等待所有TaskGroup任务完成后Job成功退出,否则,异常退出,进程退出值非0
DataX调度流程:
举例来说,用户提交了一个DataX作业,并且配置了20个并发,目的是将一个100张分表的mysql数据同步到odps里面,DataX的调度决策思路是:
DataXJob根据分库分表切分成了100个Task
根据20个并发,DataX计算共需要分配4个TaskGroup,4个TaskGroup平分切分好的100个Task,每一个TaskGroup负责以5个并发共计运行25个Task
4.数据抽取策略
维度表
维度小表(品类信息维表,活动信息维表等),每天抽取过来一份全量(或者一周、一月)
维度大表(商品信息表)【实体表】,每天抽取过来一份增量数据
事实表
订单相关表
优惠券领取使用记录表
秒杀订阅记录表
每天都会抽取一份增量数据
总原则
小表——全量抽取
大表——增量抽取
5.ODS
5.1主要表模型
 商品信息(主要信息、详情信息、类目信息、属性信息、商品相册信息)
用户信息(主要信息、附加信息、会员等级信息)
订单信息及购物车相关(主要信息、详情信息、物流信息、评论信息)
内容管理(话题,文章,评论)
营销管理(优惠券、代金券、活动规则、主题推荐)
5.2增量合并
– 1. 业务域,ods层,订单主要信息表,增量抽取后所放入的表

   -- 2. sqoop抽取命令(第一天7.30)
   -- 3. 将写入表目录的数据文件,映射到ods.oms_order_info 的日分区中

hive> alter table ods.oms_order_info add partition ( dt= ‘2020-07-30’) ;

   -- 4. 创建DWD层表

   -- 5. 将7.30号的ods增量数据,直接抽入 7.30号的dwd全量表,作为初始全量快照
   -- 6. sqoop抽取命令(第2天: 7.31)
   -- 7. 将写入表目录的数据文件,映射到ods.oms_order_info 的日分区中
   -- 8 . 将dwd的7.30号全量 union  ods的7.31号增量  ==》 得到dwd的7.31号全量
   5.3拉链表(测试数据)
   7.31的拉链

   o1,u1,未支付,2020-07-30,9999-12-31

   o2,u2,未支付,2020-07-30,2020-07-30

   o2,u2,待发货,2020-07-31,9999-12-31

   o3,u3,未支付,2020-07-30,9999-12-31


   create table test.lalian(

   oid string,

   uid string,

   order_status string,

   start_dt  string,

   end_dt   string

   )

   row format delimited fields terminated by ','

;

load data local inpath ‘/root/lalian.txt’ into table test.lalian;

   8.1的增量

   o1,u1,待发货

   o2,u2,已发货

   o4,u4,未支付


   create table test.order_incr(

   oid string,

   uid string,

   order_status string

   )

   row format delimited fields terminated by ','

;

   load data local inpath '/root/order_incr.txt' into table test.order_incr;


   8.1号的拉链表结果

   o1,u1,未支付,2020-07-30,2020-07-31

   o2,u2,未支付,2020-07-30,2020-07-30

   o2,u2,待发货,2020-07-31,2020-07-31

   o3,u3,未支付,2020-07-30,9999-12-31

   o1,u1,待发货,2020-08-01,9999-12-31

   o2,u2,已发货,2020-08-01,9999-12-31

   o4,u4,未支付,2020-08-01,9999-12-31



   select

    a.oid,
    a.uid,

    a.order_status,

    a.start_dt,

    if(a.end_dt='9999-12-31' and b.oid is not null,'2020-07-31',a.end_dt) as end_dt

   from lalian a left join order_incr b

on a.oid=b.oid

   union all


   select

    oid,

    uid,

    order_status,

    '2020-08-01' as start_dt,

    '9999-12-31' as end_dt

   from order_incr;
 6.DWD层设计开发
   6.1订单明细表
   所需支撑的ADS层各类分析需求
   核心度量:
    订单单数
    下单人数
     GMV金额
     实付金额
     优惠券抵扣金额
     促销折扣金额
     积分抵扣金额
     退货金额
     退货人数
     退货单数
   主要维度:
     时段(小时段,日,周,月,季,.....)
    品类
    品牌
    订单类型(普通订单,团购订单,秒杀订单)
    促销活动
   6.2购物车明细表
   所需支撑的ADS层各类分析需求
   核心度量:
    加购商品数
    加购次数
    加购人数
   主要维度:
    时段(小时段,日,周,月,季,.....)
    品类
    品牌
    会员等级
   6.3团购活动明细表
   所需支撑的ADS层各类分析需求
   核心度量:
    开团次数
    参团人数
   主要维度:
    时段(小时段,日,周,月,季,.....)
    品类
    品牌
    会员等级
   6.4秒杀活动明细表
      秒杀活动,dwd层表模型
      create table dwd.flash_promotion_dtl(
      dtstr                         string,
      id                            int,
      member_id                     int,
      product_id                    bigint,
      subscribe_time                timestamp,
      send_time                     timestamp,
      member_level_name             string,
      gender                        string,
      city                          string,
      brand_name                    string,
      product_name                  string,
      product_category_name         string,
      flash_promotion_session_id    bigint,
      flash_promotion_session_name  string,
      flash_promotion_id            bigint,
      flash_promotion_title         string         
      )
      partitioned by (dt string)
      stored as parquet
      ;
     ETL代码 
  insert into table dwd.flash_promotion_dtl partition(dt ='2020-07-30')
  select
     '2020-07-30' as dtstr                               ,                       
      a.id                                                ,
      a.member_id                                         ,
      a.product_id                                        ,
      a.subscribe_time                                    ,
      a.send_time                                         ,
      l.name as member_level_name                         ,
     case u.gender  
     when  0 then '未知'  
     when  1 then '男'
     else  '女'
     end as gender                                       ,  
     u.city                                              ,
     p.brand_name                                        ,
     p.product_name                                      ,
     p.product_category_name                             ,
     s.id as  flash_promotion_session_id                 ,
     s.name as flash_promotion_session_name              ,
     m.id as  flash_promotion_id                         ,
     m.title as flash_promotion_title                    
 from dwd.sms_flash_promotion_log a 
    join dwd.ums_member u on a.member_id=u.id
    join dwd.ums_member_level l on u.member_level_id=l.id
    join dwd.pms_product p on a.product_id=p.id
    join dwd.sms_flash_promotion_product_relation r on a.product_id=r.product_id
    join dwd.sms_flash_promotion_session s on r.flash_promotion_session_id=s.id
    join dwd.sms_flash_promotion m on r.flash_promotion_id=m.id
where to_date(subscribe_time)>'2020-07-29'

7DWS层设计开发
7.1订单金额分析dws层聚合表
create table dws.oms_order_amount_agg(
gmv decimal(10,2),
pay_amount decimal(10,2),
coupon_amount decimal(10,2),
promotion_discount_amount decimal(10,2),
integration_discount_amount decimal(10,2),
time_range_hour int,
product_brand string, – 商品品牌
product_category_name string, – 商品品类
member_level_name string, – 会员等级
order_type string, – 订单类型
source_type string, – 订单来源
promotion_name string – 所属活动
)
partitioned by (dt string)
stored as parquet
;

– ETL 开发
– 源表:
– dwd.oms_order_info 订单表
– dwd.oms_order_item 订单商品详情表
– dwd.ums_member 会员信息表
– dwd.ums_member_level 会员等级信息表
– dwd.pms_product 产品信息表
– 目标:dws.oms_order_amount_agg 销售金额分析维度聚合表

– 开发逻辑,首先要以订单表为中心,去join其他几张需求相关的表,形成如下表结构

订单id,会员id,产品id,产品销售价,产品促销减免,产品积分抵扣,产品优惠券减免,订单类型,订单来源,所属活动,品类, 品牌, 会员等级,时段
o1 m1 p1 20 5 1 1 普通 PC 大放送 c1 b1 lev1 3
o1 m1 p2 80 0 5 5 活动 H5 新品秒 c2 b2 lev1 3
o2

with tmp as (
select
od.dtstr as dtstr ,
od.order_id as order_id ,
od.member_id as member_id ,
od.product_id as product_id ,
od.order_type as order_type ,
od.source_type as source_type ,
od.promotion_info as promotion_info ,
it.product_price as product_price ,
it.product_quantity as product_quantity ,
it.promotion_amount as promotion_amount ,
it.coupon_amount as coupon_amount ,
it.integration_amount as integration_amount ,
it.real_amount as real_amount ,
pd.brand_name as brand_name ,
pd.product_category_name as product_category_name ,
lv.name as member_level_name ,
hour(od.create_time) as time_range_hour
from dwd.oms_order_info od
join dwd.oms_order_item it on to_date(od.create_time) = ‘2020-07-30’ and od.id=it.order_id
join dwd.ums_member mb on od.member_id = mb.id
join dwd.ums_member_level lv on mb.member_level_id = lv.id
join dwd.pms_product pd on it.product_id=pd.id

)

select
sum(product_price*product_quantity) as gmv,
sum(real_amount) as pay_amount,
sum(coupon_amount) as coupon_amount,
sum(promotion_amount) as promotion_discount_amount,
sum(integration_amount) as integration_discount_amount

from tmp
group by
product_brand ,
product_category_name ,
member_level_name ,
order_type ,
source_type ,
promotion_name
;

7.2用户消费画像标签表
drop table if exists ads.portrait_consume_tag;
create table ads.portrait_consume_tag(
member_id bigint ,–用户
first_order_time string ,–首单日期
last_order_time string ,–末单日期
first_order_ago bigint ,–首单距今时间
last_order_ago bigint ,–末单距今时间
month1_order_cnt bigint ,–近30天购买次数
month1_order_amt double ,–近30天购买金额
month2_order_cnt bigint ,–近60天购买次数
month2_order_amt double ,–近60天购买金额
month3_order_cnt bigint ,–近90天购买次数
month3_order_amt double ,–近90天购买金额
max_order_amt double ,–最大订单金额
min_order_amt double ,–最小订单金额
total_order_cnt bigint ,–累计消费次数(不含退拒)
total_order_amt double ,–累计消费金额(不含退拒)
total_coupon_amt double ,–累计使用代金券金额
user_avg_order_amt double ,–平均订单金额(含退拒)
month3_user_avg_amt double ,–近90天平均订单金额(含退拒)
common_address string ,–常用收货地址
common_paytype string ,–常用支付方式
month1_cart_cnt_30 bigint ,–最近30天加购次数
month1_cart_goods_cnt_30 bigint ,–最近30天加购商品件数
month1_cart_submit_cnt_30 bigint ,–最近30天提交件数
month1_cart_submit_rate_30 double , --最近30天商品提交占比
month1_cart_cancel_cnt_30 bigint ,–最近30天取消商品件数
dw_date string 计算日期
) partitioned by
(dt string)
;

ETL 开发
1.给订单表中的订单记录标记上是否退货
with tmp1 as (
select
member_id as member_id ,
min(create_time) as first_order_time ,
max(create_time) as last_order_time ,
datediff(‘2020-07-30’,to_date(min(create_time))) as first_order_ago ,
datediff(‘2020-07-30’,to_date(max(create_time))) as last_order_ago ,
count(if(datediff(‘2020-07-30’,to_date(create_time))<=30,1,null)) as month1_order_cnt ,
sum(if(datediff(‘2020-07-30’,to_date(create_time))<=30,total_amount,0)) as month1_order_amt ,
count(if(datediff(‘2020-07-30’,to_date(create_time))<=60,1,null)) as month2_order_cnt ,
sum(if(datediff(‘2020-07-30’,to_date(create_time))<=60,total_amount,0)) as month2_order_amt ,
count(if(datediff(‘2020-07-30’,to_date(create_time))<=90,1,null)) as month3_order_cnt ,
sum(if(datediff(‘2020-07-30’,to_date(create_time))<=90,total_amount,0)) as month3_order_amt ,
max(total_amount) as max_order_amt ,
min(total_amount) as min_order_amt ,
count(if(return_amount=0,1,null)) as total_order_cnt , --累计消费次数(不含退拒)
sum(total_amount-return_amount) as total_order_amt , --累计消费金额(不含退拒)
sum(coupon_amount) as total_coupon_amt ,
round(sum(total_amount)/count(1),2) as user_avg_order_amt, --平均订单金额(含退拒)
round(sum(if(datediff(‘2020-07-30’,to_date(create_time))<=90,total_amount,0))/count(if(datediff(‘2020-07-30’,to_date(create_time))<=90,1,null)),2) as month3_user_avg_amt --近90天平均订单金额(含退拒)
from
(
select
od.member_id,
od.create_time,
od.total_amount,
od.pay_amount,
od.coupon_amount,
if(rt.return_amount is not null,rt.return_amount,0) as return_amount – 退款金额

           from 
              dwd.oms_order_info od 
           left join 
             (    
                 select 
                    order_id,sum(return_amount) as return_amount
                 from 
                   dwd.oms_order_return_apply
                 group by 
                   order_id
           
              ) rt
           on od.id = rt.order_id       
      ) tmp
  group by 
      member_id

)

常用收获地址
,tmp2 as (
select
member_id,
address as common_address
from
(
select
member_id,
address,
row_number() over(partition by member_id order by cnt desc) as rn
from
(
select
member_id ,
concat_ws(’,’,receiver_province,receiver_city,receiver_region,receiver_detail_address) as address,
count(1) as cnt
from
dwd.oms_order_info od
group by
member_id,concat_ws(’,’,receiver_province,receiver_city,receiver_region,receiver_detail_address)
) o1
) o2
where rn = 1
)

常用支付方式
,tmp3 as (
select
member_id,
pay_type as common_paytype
from
(
select
member_id,
pay_type,
row_number() over(partition by member_id order by cnt desc) as rn
from
(
select
member_id,
pay_type,
count(1) as cnt
from
dwd.oms_order_info od
group by
member_id,pay_type
) o1

  )o2 
where rn = 1   

)

– 购物车统计
,tmp4 as (
select
member_id ,
count(if(datediff(‘2020-07-30’,to_date(create_date))<=30,1,null)) as month1_cart_cnt_30 ,–最近30天加购次数
sum(if(datediff(‘2020-07-30’,to_date(create_date))<=30,quantity,0)) as month1_cart_goods_cnt_30 ,–最近30天加购商品件数
sum(if(datediff(‘2020-07-30’,to_date(create_date))<=30 and delete_status = 1,quantity,0)) as month1_cart_submit_cnt_30 ,–最近30天提交件数
sum(if(datediff(‘2020-07-30’,to_date(create_date))<=30 and delete_status = 2,quantity,0)) as month1_cart_cancel_cnt_30 --最近30天取消商品件数
from
dwd.oms_cart_item ct
group by
member_id

)

整合订单表和购物车表中的所有member_id
,uids as (
select member_id from dwd.oms_order_info
union
select member_id from dwd.oms_cart_item
)

INSERT INTO TABLE ads.portrait_consume_tag partition (dt = ‘2020-07-30’)

SELECT

uids.member_id                           ,--用户
tmp1.first_order_time                    ,--首单日期
tmp1.last_order_time                     ,--末单日期
tmp1.first_order_ago                     ,--首单距今时间
tmp1.last_order_ago                      ,--末单距今时间
tmp1.month1_order_cnt                    ,--近30天购买次数
tmp1.month1_order_amt                    ,--近30天购买金额
tmp1.month2_order_cnt                    ,--近60天购买次数
tmp1.month2_order_amt                    ,--近60天购买金额
tmp1.month3_order_cnt                    ,--近90天购买次数
tmp1.month3_order_amt                    ,--近90天购买金额
tmp1.max_order_amt                       ,--最大订单金额
tmp1.min_order_amt                       ,--最小订单金额
tmp1.total_order_cnt                     ,--累计消费次数(不含退拒)
tmp1.total_order_amt                     ,--累计消费金额(不含退拒)
tmp1.total_coupon_amt                    ,--累计使用代金券金额
tmp1.user_avg_order_amt                  ,--平均订单金额(含退拒)
tmp1.month3_user_avg_amt                 ,--近90天平均订单金额(含退拒)
tmp2.common_address                      ,--常用收货地址
tmp3.common_paytype                      ,--常用支付方式
tmp4.month1_cart_cnt_30                  ,--最近30天加购次数
tmp4.month1_cart_goods_cnt_30            ,--最近30天加购商品件数
tmp4.month1_cart_submit_cnt_30           ,--最近30天提交件数
tmp4.month1_cart_submit_cnt_30/tmp4.month1_cart_goods_cnt_30    as month1_cart_submit_rate_30     , --最近30天商品提交占比
tmp4.month1_cart_cancel_cnt_30            --最近30天取消商品件数

FROM
uids left join tmp1 on uids.member_id = tmp1.member_id
left join tmp2 on uids.member_id = tmp2.member_id
left join tmp3 on uids.member_id = tmp3.member_id
left join tmp4 on uids.member_id = tmp4.member_id
;

7.3用户退拒货统计画像标签表

drop table if exists ads.portrait_return_tag;
create table ads.portrait_return_tag(
user_id bigint ,-- 用户
p_sales_cnt bigint ,-- 不含退拒商品购买数量
p_sales_amt double ,-- 不含退拒商品购买的商品总价
p_sales_cut_amt double ,-- 不含退拒实付金额(扣促销减免)
h_sales_cnt bigint ,-- 含退拒购买数量
h_sales_amt double ,-- 含退拒购买金额
h_sales_cut_amt double ,-- 含退拒购买金额(扣促销减免)
return_cnt bigint ,-- 退货商品数量
return_amt double ,-- 退货商品金额
reject_cnt bigint ,-- 拒收商品数量
reject_amt double ,-- 拒收商品金额
dtstr string
) partitioned by (dt string)
stored as parquet
;

– ETL 开发

– 核心源表: dwd.oms_order_item dwd.oms_order_return_apply
with tmp as (
select
it.member_id, – 会员id
it.product_id, – 商品id
it.product_price, – 商品销售价
it.product_quantity, – 购买数量
it.promotion_amount, – 促销减免进额
it.real_amount , – 实付金额
rt.return_amount , – 退款金额
rt.reason , – 退货原因(‘1’:退货 ‘2’: 拒收)
rt.product_count as return_cnt – 退货数量
from
(
select
od.member_id,
od.id as order_id,
it.product_id,
it.product_price,
it.product_quantity,
it.promotion_amount,
it.real_amount
from
dwd.oms_order_item it
join
dwd.oms_order_info od
on it.order_id = od.id

  ) it
left join 
  dwd.oms_order_return_apply rt
on
  it.product_id = rt.product_id and it.order_id = rt.order_id 

)

SELECT
member_id ,
sum(if(reason is null,product_quantity,0)) as p_sales_cnt ,-- 不含退拒商品购买数量
sum(if(reason is null,product_priceproduct_quantity,0)) as p_sales_amt ,-- 不含退拒商品购买的商品总价
sum(if(reason is null,real_amount,0)) as p_sales_cut_amt ,-- 不含退拒实付金额(扣促销减免)
sum(product_quantity) as h_sales_cnt ,-- 含退拒购买数量
sum(product_price
product_quantity) as h_sales_amt ,-- 含退拒购买金额
sum(real_amount) as h_sales_cut_amt ,-- 含退拒购买金额(扣促销减免)
sum(if(reason = ‘1’,return_cnt,0)) as return_cnt ,-- 退货商品数量
sum(if(reason = ‘1’,return_amount,0)) as return_amt ,-- 退货商品金额
sum(if(reason = ‘2’,return_cnt,0)) as reject_cnt ,-- 拒收商品数量
sum(if(reason = ‘2’,return_amount,0)) as reject_amt ,-- 拒收商品金额
‘2020-07-30’ as dtstr
FROM
tmp
GROUP BY
member_id

;
7.4订单数量、人数维度轻聚合表
7.5优惠券领取数量,使用数量,使用人数,抵扣金额维度轻聚合表
7.6营销活动参与次数,人数,多维度轻聚合表
7.7用户消费情况月度聚合表
7.8用户购物偏好画像分析
需求说明
drop table if exists ads_user_profile_favor_tag;
create table ads_user_profile_favor_tag(
user_id bigint ,-- 用户
common_first_cat bigint ,-- 最常购买一级类目名称
common_second_cat bigint ,-- 最常购买二级类目名称
common_third_cat bigint ,–最常购买三级类目名称
common_brand_id bigint ,–最常购买的品牌
dw_date bigint
) partitioned by (dt string)
stored as parquet
;
最核心的要点是,收集到用户的每一次购买的行为记录

四、
4.1调度脚本开发

#!/bin/bash

##################################################
#
#  @desc: 加载flume采集的日志,到ods表分区中
#  @auth: HUNTER.DUAN
#  @date: 2020-08-11
#   
##################################################

export HIVE_HOME=/opt/apps/apache-hive-3.1.2-bin/

datestr=`date -d'-1 day' +%Y-%m-%d`

if [ $1 ]
then
datestr=$1
fi


year=`echo $datestr|cut -d"-" -f1`
month=`echo $datestr|cut -d"-" -f2`
day=`echo $datestr|cut -d"-" -f3`


${HIVE_HOME}/bin/hive -e "load data inpath '/eventlog/app_event/${datestr}' into table ods.app_event_log partition (y='${year}',m='${month}',d='${day}')"


if [ $? -eq 0 ]
then 
echo "execution successed ..............."
else
echo "execution failed ..............."
fi
#!/bin/bash

##################################################
#
#  @desc: 设备ID绑定SPARK计算任务
#  @auth: HUNTER.DUAN
#  @date: 2020-08-11
#  @param_1: 可传指定计算日期
#  @param_2: 可传指定绑定参照日   
#   
##################################################

export SPARK_HOME=/opt/apps/spark-2.4.0


pre_day=`date -d'-2 day' +%Y-%m-%d`
cur_day=`date -d'-1 day' +%Y-%m-%d`

if [[ $1 && $2 ]]
then
cur_day=$1
pre_day=$2
fi

${SPARK_HOME}/bin/spark-submit  --master yarn \
--deploy-mode client \
--num-executors 3 \
--executor-memory 1g \
--executor-cores 1 \
--class cn.doitedu.dwetl.idmp.AppIdBInd /opt/job_scripts/etl.jar ${cur_day} ${pre_day} yarn


if [ $? -eq 0 ]
then 
echo "execution succeed ,a mail has been sent ........."
else
echo "execution failed ,a mail has been sent ........."
fi

#!/bin/bash

##################################################
#
#  @desc: APP日志ods表 -> dwd表 spark计算任务
#  @auth: HUNTER.DUAN
#  @date: 2020-08-11
#  @param_1: 可传指定计算日期
#  @param_2: 可传指定绑定参照日   
#   
##################################################

export SPARK_HOME=/opt/apps/spark-2.4.0


pre_day=`date -d'-2 day' +%Y-%m-%d`
cur_day=`date -d'-1 day' +%Y-%m-%d`

if [[ $1 && $2 ]]
then
cur_day=$1
pre_day=$2
fi

${SPARK_HOME}/bin/spark-submit  --master yarn \
--deploy-mode client \
--num-executors 3 \
--executor-memory 3g \
--executor-cores 1 \
--class cn.doitedu.dwetl.etl.Ods2Dwd /opt/job_scripts/etl.jar ${cur_day} ${pre_day} yarn


if [ $? -eq 0 ]
then 
echo "execution succeed ,a mail has been sent ........."
else
echo "execution failed ,a mail has been sent ........."
fi

#!/bin/bash

##################################################
#
#  @desc: dwd.app_event_dtl -> dws.app_pv_agg_session
#  @auth: HUNTER.DUAN
#  @date: 2020-08-11
#  @param_1: 可传指定计算日期
#   
##################################################
#set hive.vecctorized.exeecution.enable=false;向量化执行引擎

export HIVE_HOME=/opt/apps/apache-hive-3.1.2-bin/

datestr=`date -d'-1 day' +%Y-%m-%d`

if [ $1 ]
then
datestr=$1
fi

${HIVE_HOME}/bin/hive -e "
set hive.vecctorized.exeecution.enable=false;
INSERT INTO TABLE dws.app_pv_agg_session PARTITION(dt='${datestr}')
SELECT
    guid,
    sessionid as session_id,
    min(ts) as start_time,
    max(ts) as end_time,
    max(first_page) as first_page,
    max(last_page) as last_page,
    count(1) as pv_cnt,
    max(isnew) as isnew,
    max(hour) as hour,
    max(province) as province,
    max(city) as city,
    max(district) as district,
    max(devicetype) as device_type

FROM
    (
        SELECT
            guid,
            sessionid,
            ts,
            isnew,
            first_value(properties['pageid']) over(partition by sessionid order by ts) as first_page,
            last_value(properties['pageid']) over(partition by sessionid order by ts) as last_page,
            first_value(hour(from_unixtime(cast(ts/1000 as bigint)))) over(partition by sessionid order by ts) as hour,
            first_value(province) over(partition by sessionid order by ts) as province,
            first_value(city) over(partition by sessionid order by ts) as city,
            first_value(district) over(partition by sessionid order by ts) as district,
            devicetype
        FROM dwd.app_event_dtl
        WHERE dt = '${datestr}' AND eventid = 'pageView'
    ) O
GROUP BY guid,sessionid
//;//
"
#!/bin/bash

##################################################
#
#  @desc: dwd.app_event_dtl -> dws.app_pv_agg_session
#  @auth: HUNTER.DUAN
#  @date: 2020-08-11
#  @param_1: 可传指定计算日期
#   
##################################################
#set hive.vecctorized.exeecution.enable=false;向量化执行引擎

export HIVE_HOME=/opt/apps/apache-hive-3.1.2-bin/

datestr=`date -d'-1 day' +%Y-%m-%d`

if [ $1 ]
then
datestr=$1
fi

${HIVE_HOME}/bin/hive -e "
set hive.vecctorized.exeecution.enable=false;
INSERT INTO TABLE dws.app_pv_agg_session PARTITION(dt='${datestr}')
SELECT
    guid,
    sessionid as session_id,
    min(ts) as start_time,
    max(ts) as end_time,
    max(first_page) as first_page,
    max(last_page) as last_page,
    count(1) as pv_cnt,
    max(isnew) as isnew,
    max(hour) as hour,
    max(province) as province,
    max(city) as city,
    max(district) as district,
    max(devicetype) as device_type

FROM
    (
        SELECT
            guid,
            sessionid,
            ts,
            isnew,
            first_value(properties['pageid']) over(partition by sessionid order by ts) as first_page,
            last_value(properties['pageid']) over(partition by sessionid order by ts) as last_page,
            first_value(hour(from_unixtime(cast(ts/1000 as bigint)))) over(partition by sessionid order by ts) as hour,
            first_value(province) over(partition by sessionid order by ts) as province,
            first_value(city) over(partition by sessionid order by ts) as city,
            first_value(district) over(partition by sessionid order by ts) as district,
            devicetype
        FROM dwd.app_event_dtl
        WHERE dt = '${datestr}' AND eventid = 'pageView'
    ) O
GROUP BY guid,sessionid
//;//
"

4.2任务调度
4.2.1【crontab】定时任务执行调度
crontab 是linux系统中自带的一个定时任务调度工具
它通过一个简单的配置文件,来按照需求定时执行用户所指定的程序(脚本)
示例:
crontab -e
30 0 * * * sh /root/jobs/0-pre.sh
40 0 * * * sh /root/jobs/1-load_data.sh
项目中的任务配置样例如下:
10 0 * * * sh /root/idmp.sh
30 0 * * * sh /root/applog_preprocess.sh
50 0 * * * sh /root/load_log_ods.sh
55 0 * * * sh /root/ods_app_2_dwd_glb.sh
10 1 * * * sh /root/dwd_glb_2_dwd_tfc.sh
10 1 * * * sh /root/dwd_glb_2_dwd_itr.sh
10 1 * * * sh /root/glb_adv.sh
10 1 * * * sh /root/glb_utm.sh
但是,我们项目中的大量运算任务,互相之间存在执行顺序约束,任务和任务之间还存在复杂依赖关系(比如只有A/B运行完才能运行C),那么,在crontab中就不太好控制,所以,本项目中的任务调度,使用crontab来实现,是不合适的,我们需要更强大的任务调度系统;
4.2.2【Azkaban】定时任务执行调度
与azkaban类似的做任务定时调度工具有很多,如:oozie
4.2.3【数据治理-Atlas元数据管理】
Atlas 是一个可伸缩且功能丰富的元数据管理系统,深度对接了 Hadoop 大数据组件,
简单理解就是一个跟 Hadoop 关系紧密的,可以用来做各类数据的元数据管理的一个软件系统;
atlas本身从技术上来说,就是一个典型的JAVAWEB系统,
4.2.3.1核心组件
4.2.3.1.1Core
Type System: Atlas 允许用户为他们想要管理的元数据对象定义一个模型。该模型由称为 “Type” 的定义组成。“类型” 的 实例被称为 “实体” 表示被管理的实际元数据对象。类型系统是一个组件,允许用户定义和管理类型和实体。由 Atlas 管理的所有元数据对象(例如Hive表)都使用类型进行建模,并表示为实体。要在 Atlas 中存储新类型的元数据,需要了解类型系统组件的概念。

Ingest/Export:Ingest 组件允许将元数据添加到 Atlas。类似地,Export 组件暴露由Atlas检测到的元数据更改,以作为事件引发,消费者可以使用这些更改事件来实时响应元数据更改。

Graph Engine:在内部,Atlas通过使用图模型管理元数据对象。以实现元数据对象之间的巨大灵活性和丰富的关系。图引擎是负责在类型系统的类型和实体之间进行转换的组件,以及基础图形模型。除了管理图对象之外,图引擎还为元数据对象创建适当的索引,以便有效地搜索它们。

Atlas 使用 JanusGraph图数据库来存储元数据对象。 JanusGraph使用两个存储:默认情况下元数据存储配置为 HBase ,索引存储配置为 Solr。
4.2.3.1.2Integration
用户可以使用两种方法管理 Atlas 中的元数据:

API:Atlas 的所有功能都可以通过 REST API 提供给最终用户,允许创建,更新和删除类型和实体。它也是查询和发现通过 Atlas 管理的类型和实体的主要方法。

Messaging:除了 API 之外,用户还可以选择使用基于 Kafka 的消息接口与 Atlas 集成。这对于将元数据对象传输到 Atlas 以及从 Atlas 使用可以构建应用程序的元数据更改事件都非常有用。如果希望使用与 Atlas 更松散耦合的集成,这可以允许更好的可扩展性,可靠性等,消息传递接口是特别有用的。Atlas 使用 Apache Kafka 作为通知服务器用于钩子和元数据通知事件的下游消费者之间的通信。事件由钩子(hook)和 Atlas 写到不同的 Kafka 主题:

ATLAS_HOOK: 来自各个组件的Hook 的元数据通知事件通过写入到名为 ATLAS_HOOK 的 Kafka topic 发送到 Atlas;

ATLAS_ENTITIES:从 Atlas 到其他集成组件(如Ranger)的事件写入到名为 ATLAS_ENTITIES 的 Kafka topic;

4.2.3.1.3Metadata source
Atlas支持与许多元数据源的集成,将来还会添加更多集成。目前,Atlas 支持从以下数据源获取和管理元数据:

Hive:通过hive bridge,可以接入Hive的元数据,包括hive_db/hive_table/hive_column/hive_process

Sqoop:通过sqoop bridge,可以接入关系型数据库的元数据,包括sqoop_operation_type/ sqoop_dbstore_usage/sqoop_process/sqoop_dbdatastore

Falcon:通过falcon bridge,atlas可以接入Falcon的元数据,包括falcon_cluster/falcon_feed
/falcon_feed_creation/falcon_feed_replication/ falcon_process

Storm:通过storm bridge,atlas可以接入流式处理的元数据,包括storm_topology/storm_spout/storm_bolt

Atlas集成大数据组件的元数据源需要实现以下两点:
首先,需要基于atlas的类型系统定义能够表达大数据组件元数据对象的元数据模型(例如Hive的元数据模型实现在org.apache.atlas.hive.model.HiveDataModelGenerator);
然后,需要提供hook组件去从大数据组件的元数据源中提取元数据对象,实时侦听元数据的变更并反馈给atlas;
4.2.3.1.4Applications
Atlas Admin UI: 该组件是一个基于 Web 的应用程序,允许数据管理员和科学家发现和注释元数据。Admin UI提供了搜索界面和 类SQL的查询语言,可以用来查询由 Atlas 管理的元数据类型和对象。Admin UI 使用 Atlas 的 REST API 来构建其功能。

4.2.3.2核心特性
Apache Atlas为Hadoop的元数据治理提供了以下特性:

4.2.3.2.1数据分类管理
为元数据导入或定义业务导向的分类注释
定义,注释,以及自动捕获数据集和底层元素之间的关系
导出元数据到第三方系统

4.2.3.2.2集中审计
捕获与所有应用,过程以及与数据交互的安全访问信息
捕获执行,步骤,活动等操作的信息;

4.2.3.2.3搜索与血缘管理
可以根据classfication类别、关键字、数据资产类型等条件来快捷搜索相关元数据,还可以很方便查看数据资产的血缘

4.2.3.3Atlas使用原理导论
ATLAS的使用,包含两个方面:
注入元数据信息到atlas中(本质是:写入元数据到atlas中)
注入方式1:通过atlas为数据系统开发好的hook来注入
注入方式2:通过atlas自带的WEB-UI来人工填写元数据信息再注入
注入方式3:通过在自己的数据系统中调用atlas对外暴露的api,来灵活注入

使用atlas中的元数据信息来为我们服务(本质是:从atlas中读、改元数据)
方式1:通过atlas自带的WEB-UI前端系统来查看、修改元数据
4.2.3.4Atlas WEB-UI 功能详解
ApacheAtlasUI功能包括4部分:
create entity:创建实体(创建数据资产的元数据–人工录入元数据)
(在atlas中,有大量的对各类数据资产适配的描述定义:实体类型
hive_table; hive_db;hive_column;hive_process;hdfs_path,…,如果我们有一个数据资产,没有对应的内置实体类型,可以自己去定义一个你的实体类型,来描述你的这个数据资产)
search:搜索查看
classfication:分类管理
glossary:对数据资产标记“术语”(标签)方式2:通过调用atlas对外暴露的api,来开发自己的管理系统

你可能感兴趣的:(总结,笔记,案例,大数据,kafka,hadoop,spark,hive)