1、预备知识一:Hive时间函数
(1)时间格式大体分为两类:
标准日期格式:2015-08-31 00:04:37
Unixtimestamp:以格林威治时间为基准的Unix时间戳,该时间戳为以1970年1月1日0点0分0秒开始一直到现在此时此刻总的秒数或毫秒数,是一个long型的数据。
(2)hive自带提供了Unixtimestamp的函数方法
功能:将日期转换成对应的Unixtimestamp时间戳
举例:要计算2015-08-31 00:04:37与2015-09-02 00:00:00之间的时间间隔,需要先将日期格式转换成Unix时间戳,然后再相减得到最后的时间差。
使用的业务场景:
网站后台处理数据:其中有一个指标“停留时间”,“停留时间”是一个衡量网站质量好坏的重要的基准指标之一。
(3)测试hive自带的函数
select unix_timestamp("2017-05-20 12:00:00") from u_data limit 1;
下面这种格式无法运行转换出结果,是NULL:
select unix_timestamp("20170520 12:00:00") from u_data limit 1;
指定格式转化:
select unix_timestamp("20170520 12:00:00","yyyyMMdd HH:mm:ss") from u_data limit 1;
使用字段进行转换:
select unix_timestamp("time","yyyyMMdd HH:mm:ss") from u_data limit 1;
from_unixtime将Unix时间戳转换为标准的日期格式,比如:2017-05-20 12:00:00。
select from_unixtime(1495252800,"yyyyMMdd HH:mm:ss") from u_data limit 1;
或者
select from_unixtime(1495252800,"yyyy-MM-dd HH:mm:ss") from u_data limit 1;
2、预备知识二:case when
when用来直接判断这一列的值.
(1)需求:奖金comm这列如果是NULL的话就显示为0。
select empno,ename,
case
when comm is null then 0
else comm
end
from emp;
结果:
empno ename _c2
7369 SMITH 0.0
7499 ALLEN 300.0
7521 WARD 500.0
7566 JONES 0.0
7654 MARTIN 1400.0
7698 BLAKE 0.0
7782 CLARK 0.0
7788 SCOTT 0.0
7839 KING 0.0
7844 TURNER 0.0
7876 ADAMS 0.0
7900 JAMES 0.0
7902 FORD 0.0
7934 MILLER 0.0
(2)需求:员工不同的薪资显示不同的等级
select empno,ename,
case
when sal<1000 then 'aaa'
when sal>=1500 and sal<3000 then 'ccc'
else 'ddd'
end as new_sal
from emp;
结果:
empno ename new_sal
7369 SMITH aaa
7499 ALLEN ccc
7521 WARD ddd
7566 JONES ccc
7654 MARTIN ddd
7698 BLAKE ccc
7782 CLARK ccc
7788 SCOTT ddd
7839 KING ddd
7844 TURNER ccc
7876 ADAMS ddd
7900 JAMES aaa
7902 FORD ddd
7934 MILLER ddd
3、预备知识三:Cast 方法
作用:数据类型的转换。
create table casttest as select empno e_no,ename e_name,cast(sal as string) new_sal from emp;
4、日志分析案例
分析流程
(1)需求分析
(2)数据采集
(3)数据清洗
(4)数据分析
(5)结果展示
(1)需求分析
预期结果统计:
日期 | PV | UV | 登录人数 | 游客人数 | 平均访问时长 | 二跳率 | 独立IP |
---|
1)日期
按照日期进行分组,基于时间维度进行分析。
可以考虑建分区表,按给定日期分区。
2)PV
count(url)
3)UV
count(distinct(guid))
4)登录人数
登录人数代表的就是会员,使用账号登录的人。
登录之后会产生一个会员ID。
处理的时候可以看会员ID有没有值。
5)游客人数
会员ID没有值,但是guid有值,那就是游客访问的数据。
6)平均访问时长
当进入页面后,就会在后台开启一个会话,生成sessionID。
会话关闭代表sessionID失效,再次建立会话,会生成不同的sessionID。
将进入页面的第一条记录的时间戳和最后离开的最后一条记录的时间戳进行相减得到访问时长。
再对session进行分组,最后求得平均访问时长。
7)二跳率
一个用户在一个session会话中点击了大于等于2的网页数量。
一个页面就是一个PV,统计PV大于等于2的页面个数,再除以总的人数。
8)独立IP
distinct(ip)
(2)数据采集
1)建库
create database yhd;
2)建源表
create table yhd_source(
id string,
url string,
referer string,
keyword string,
type string,
guid string,
pageId string,
moduleId string,
linkId string,
attachedInfo string,
sessionId string,
trackerU string,
trackerType string,
ip string,
trackerSrc string,
cookie string,
orderCode string,
trackTime string,
endUserId string,
firstLink string,
sessionViewNo string,
productId string,
curMerchantId string,
provinceId string,
cityId string,
fee string,
edmActivity string,
edmEmail string,
edmJobId string,
ieVersion string,
platform string,
internalKeyword string,
resultSum string,
currentPage string,
linkPosition string,
buttonPosition string
)
partitioned by (date string)
row format delimited fields terminated by '\t'
stored as textfile;
3)加载数据
load data local inpath '/opt/datas/2015082818' into table yhd_source partition(date='2015082818');
(3)数据清洗
访问渠道:就是指访问的方式,通过什么方式进来访问网页的
比如:收藏夹、百度、手敲网页等等
一定是第一条记录的访问渠道值才有意义
案例中的trackerU就是指用户访问网站的访问渠道
1)建源表
create table session_info(
session_id string ,
guid string ,
trackerU string ,
landing_url string ,
landing_url_ref string ,
user_id string ,
pv string ,
stay_time string ,
min_trackTime string ,
ip string ,
provinceId string
)
partitioned by (date string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' ;
2)建临时表一
create table session_tmp as
select
sessionId session_id,
max(guid) guid,
max(endUserId) user_id,
count(distinct url) pv,
(unix_timestamp(max(trackTime))-unix_timestamp(min(trackTime))) stay_time,
min(trackTime) min_trackTime,
max(ip) ip,
max(provinceId) provinceId
from yhd_source where date='2015082818'
group by sessionId;
PV值:count(distinct url) pv获取每一个session的PV,最后进行累加统计总的PV。
访问时长:每个session都会有第一个记录和最后一个记录,用最后的记录减去第一个记录得到的就是这个session的停留时间。
3)建临时表二
create table track_tmp as
select
sessionId session_id,
trackTime trackTime,
url landing_url,
referer landing_url_ref,
trackerU trackerU
from yhd_source where date='2015082818';
从源表中的每条记录都获取track_tmp表的五个字段。通过将某sessionID的每一条记录的时间trackTime和session_tmp表的最小时间min_trackTime进行join,join上了后track_tmp表记录的时间就是这个sessionID第一条记录的时间。然后获取(trackerU string),(landing_url string),(landing_url_ref string)这三个字段。
4)向源表插入数据,即join的实现
insert overwrite table session_info partition(date='2015082818')
select
a.session_id session_id,
max(a.guid) guid,
max(b.trackerU) trackerU,
max(b.landing_url) landing_url,
max(b.landing_url_ref) landing_url_ref,
max(a.user_id) user_id,
max(a.pv) pv,
max(a.stay_time) stay_time,
max(a.min_trackTime) min_trackTime,
max(a.ip) ip,
max(a.provinceId) provinceId
from session_tmp a join track_tmp b on
a.session_id = b.session_id and a.min_trackTime = b.trackTime
group by a.session_id;
注:加上group by a.sessionId为了避免实际的数据产生差错率,产生误差
5)数据清洗流程总结
- 建两张临时表,实现join生成数据,再放入session_info表中。
- 需要获取trackerU、landing_url、landing_url_ref这三个字段。
- track_tmp表中的sessionId session_id,trackTime trackTime字段是为了实现join。
- track_tmp表将所有值拿出来,不按照session进行分组,可以理解为作为一个全的集合,来获取其中的子集合。
- 大表拆小表是工作中一种常用的手段。
(4)数据分析
1)建结果集表一
create table result1 as
select
date date,
sum(pv) PV,
count(distinct guid) UV,
count(distinct case when user_id is not null then guid else null end) login_user,
count(distinct case when user_id is null then guid else null end) visitor,
avg(stay_time) avg_time,
count(case when pv>=2 then session_id else null end)/count(session_id) second_jump,
count(distinct ip) IP
from session_info
where date='2015082818'
group by date;
2)查询结果集表一
select * from result1;
结果如下:
日期 | PV | UV | 登录人数 | 游客人数 | 平均访问时长 | 二跳率 | 独立IP |
---|---|---|---|---|---|---|---|
2015082818 | 36420.0 | 23928 | 23928 | 0 | 49.74171774059963 | 0.25886201755838995 | 19174 |
发现游客人数为0,问题出在判断user_id is null的地方,源数据中user_id的位置不是null,而是一个’\n’。
3)建结果集表二
create table result2 as
select
date date,
sum(pv) PV,
count(distinct guid) UV,
count(distinct case when length(user_id)!=0 then guid else null end) login_user,
count(distinct case when length(user_id)==0 then guid else null end) visitor,
avg(stay_time) avg_time,
count(case when pv>=2 then session_id else null end)/count(session_id) second_jump,
count(distinct ip) IP
from session_info
where date='2015082818'
group by date;
4)查询结果集表二
select * from result2;
结果如下:
日期 | PV | UV | 登录人数 | 游客人数 | 平均访问时长 | 二跳率 | 独立IP |
---|---|---|---|---|---|---|---|
2015082818 | 36420.0 | 23928 | 11586 | 12367 | 49.74171774059963 | 0.25886201755838995 | 19174 |
(5)后续思考
1)一般还会在数据分析之前将数据进行过滤,清洗脏数据,去除非法数据。
2)可以考虑先写几个简单的MapReduce程序进行数据的过滤。
3)大数据处理一要考虑简单性,二要考虑效率问题。
4)一般在实际的工作中,还可以建外部表来进行多部门协作完成大数据的处理。