1. 模块开发----数据仓库设计
1.1 维度建模基本概念
维度建模是专门用于分析型数据库、数据仓库、数据集市建模的方法 .
专门适用于OLAP的设计模式存在着两种类型的表:事实表 维度表
- 维度表(dimension) : 看问题分析问题的角度 信息精但是不全 可跟事实表关系
- 事实表:主题的客观度量 能够以记录主题为准 信息多不精准
事实表的设计是以能够正确记录历史信息为准则,维度表的设计是以能够以合适的角度来聚合主题内容为准则。
1.2 维度建模三种模式
-
星型模式 : 一个事实表带多个维度表 维度之间没关系 数仓发展建立初期(一个主题)
-
雪花模式 : 一个事实表带多个维度表 维度之间可以继续关系维度 不利于维护 少用
-
星座模式 :多个事实表带多个维度 有些维度可以共用 数仓发展后期(多个主题)
不管什么模型,在数仓中,一切有利于数据分析即可为,不用考虑数据冗余性和其他设计规范。
-
模块设计–维度建模
在本项目中,因为分析主题只有一个(网站流量日志),所有采用星型模型
事实表---->对应清洗完之后的数据
维度表----->来自于提前通过工具生成 维度表范围要横跨事实表分析维度
点击流模型属于业务模型数据 既不是事实表 也不是维度表 是为了后续计算某些业务指标方便而由业务指定
-
维度建模分析图
当下企业发展大多朝着星座模式发展
1.3 本项目中数据仓库的设计
注 : 采用星型模型
1.3.1 事实表设计
1.3.2 维度表设计
注意 :
维度表的数据一般要结合业务情况自己写脚本按照规则生成 , 也可以使用工具生成.
2. 模块开发----ETL
ETL工作的实质就是从各个数据源提取数据 , 对数据进行转换 , 并最终加载填充数据到数据仓库维度建模后的表中 .
2.1 创建ODS层数据表
2.1.1 原始层数据表
分析 : 由于数据具有一定的时间性 , 因此我们创建表时对时间建立分区表
drop table if exists ods_weblog_origin;
create table ods_weblog_origin(
valid string,
remote_addr string,
remote_user string,
time_local string,
request string,
status string,
body_bytes_sent string,
http_referer string,
http_user_agent string)
partitioned by (datestr string)
row format delimited
fields terminated by '\001';
2.1.2 点击流模型pageviews表
drop table if exists ods_click_pageviews;
create table ods_click_pageviews(
session string,
remote_addr string,
remote_user string,
time_local string,
request string,
visit_step string,
page_staylong string,
http_referer string,
http_user_agent string,
body_bytes_sent string,
status string)
partitioned by (datestr string)
row format delimited
fields terminated by '\001';
2.1.3 点击流模型visit表
drop table if exists ods_click_stream_visit;
create table ods_click_stream_visit(
session string,
remote_addr string,
inTime string,
outTime string,
inPage string,
outPage string,
referal string,
pageVisits int)
partitioned by (datestr string)
row format delimited
fields terminated by '\001';
2.1.4 维度表创建
由于我们的需求是对每天进行分析 , 或者某一时间段进行分析 , 此时我们建立一个时间维度表
drop table if exists t_dim_time;
create table t_dim_time(date_key int,year string,month string,day string,hour string) row format delimited fields terminated by ',';
2.2 导入ODS层数据
导入原始层
如果是本地运行获得的数据 , 将数据上传到指定文件夹下 , 如果是在hdfs上运行获得的数据 , 用相应的代码导入数据
load data local inpath '/root/hivedata/part-m-00000' overwrite into table ods_weblog_origin partition(datestr='20130918');
查看是否导入成功 , 由于数据较大 , 我们可以查看部分数据即可
select * from ods_weblog_origin limit 10;
查看分区
show partitions ods_weblog_origin;---查看分区
统计导入的数据总数
ods_weblog_origin --开启智能本地模式
select count(*) from ods_weblog_origin; --统计导入的数据总数
导入点击流pageviews数据
load data local inpath '/root/hivedata/part-r-00000' overwrite into table ods_click_pageviews partition(datestr='20130918');
其他操作同上
导入点击流visit数据
load data local inpath '/root/hivedata/part-r-00000' overwrite into table ods_click_stream_visit partition(datestr='20130918');
其他操作同上
导入维度表数据
时间维度一般采用java , Python等生成
load data local inpath '/root/hivedata/dim_time_dat.txt' overwrite into table t_dim_time;
其他操作同上
2.3 生成ODS明细宽表
-
需求:统计今天每个小时分别有多个pv
group by (substring(ods_weblog_origin.time_local,xx))
性能点:表中的某些字段看似一个字段,实则是多个属性糅合在一起的,比如time_local
对于后续不利于直接分组利用
2013-09-18 06:49:18--->2013 09 18 06 49 18 2013-09-18 06:49:18
http_referer,表示用户来访信息也是如此
"http://www.angularjs.cn/A00n"--->http www.angularjs.cn /A00n 参数
当我们有统计每个小时的访问量时 , 此时我们直接用上述处理后的表 , 发现不那么容易处理 , 此时我们想到了创建一个宽(明细)表来将较大范围的字段进行细化
宽表 : 为了分析 , 把原来表中某些字段属性提取出来 , 构成新的字段 , 也称之为明细表
窄表 : 没有扩宽的表 , 原始表
宽表的数据来自于窄表 , 插入方式 insert(宽) + select (窄)
总结 : hive中 , 有以下几种方式可以创建带有数据的表 :
- create + load data 创建表加载数据(内部表)
- create + external + location 创建外部表指定数据路径
- create + insert + select 表的数据来自于后面查询语句返回的结果
- create + select 创建的表结构和数据来自于后面的查询语句
宽表的生成
hive内置函数parse_url_tuple
parse_url_tuple(url,host path,query,queryvalue)
a LATERAL VIEW b
LATERAL VIEW通常用于把后面的表挂接在左边的表之上 返回成为一个新表
注 : lateral view 用于和 split, explode 等 UDTF 一起使用,它能够将一列数据拆成多行数据。
https://music.163.com/#/song?id=413829859&market=baiduqk
https://music.163.com/#/song?id=413829859&market=googleqk
https://music.163.com/#/song?id=413829859&market=360qk
parse_url_tuple(url,host path,query,query:market)
baiduqk
googleqk
360qk
query:market 即获取query中的某一(market)属性值
宽表的详细图解
- 创建宽表 ods_weblog_detail
drop table ods_weblog_detail;
create table ods_weblog_detail(
valid string, --有效标识
remote_addr string, --来源IP
remote_user string, --用户标识
time_local string, --访问完整时间
daystr string, --访问日期
timestr string, --访问时间
month string, --访问月
day string, --访问日
hour string, --访问时
request string, --请求的url
status string, --响应码
body_bytes_sent string, --传输字节数
http_referer string, --来源url
ref_host string, --来源的host
ref_path string, --来源的路径
ref_query string, --来源参数query
ref_query_id string, --来源参数query的值
http_user_agent string --客户终端标识
)
partitioned by(datestr string);
-
导入数据
- 分步导入
--抽取refer_url到中间表 t_ods_tmp_referurl --也就是将来访url分离出host path query query id drop table if exists t_ods_tmp_referurl; create table t_ods_tmp_referurl as SELECT a.*,b.* FROM ods_weblog_origin a LATERAL VIEW parse_url_tuple(regexp_replace(http_referer, "\"", ""), 'HOST', 'PATH','QUERY', 'QUERY:id') b as host, path, query, query_id; --抽取转换time_local字段到中间表明细表 t_ods_tmp_detail drop table if exists t_ods_tmp_detail; create table t_ods_tmp_detail as select b.*,substring(time_local,0,10) as daystr, substring(time_local,12) as tmstr, substring(time_local,6,2) as month, substring(time_local,9,2) as day, substring(time_local,11,3) as hour From t_ods_tmp_referurl b;
- 一步导入
insert into table ods_weblog_detail partition(datestr='20130918') select c.valid,c.remote_addr,c.remote_user,c.time_local, substring(c.time_local,0,10) as daystr, substring(c.time_local,12) as tmstr, substring(c.time_local,6,2) as month, substring(c.time_local,9,2) as day, substring(c.time_local,11,3) as hour, c.request,c.status,c.body_bytes_sent,c.http_referer,c.ref_host,c.ref_path,c.ref_query,c.ref_query_id,c.http_user_agent from (SELECT a.valid,a.remote_addr,a.remote_user,a.time_local, a.request,a.status,a.body_bytes_sent,a.http_referer,a.http_user_agent,b.ref_host,b.ref_path,b.ref_query,b.ref_query_id FROM ods_weblog_origin a LATERAL VIEW parse_url_tuple(regexp_replace(http_referer, "\"", ""), 'HOST', 'PATH','QUERY', 'QUERY:id') b as ref_host, ref_path, ref_query, ref_query_id) c;
查看分区
show partitions ods_weblog_detail;