第一章.Hive实战

1.需求描述

需求描述

统计硅谷影音视频网站的常规指标,各种TopN指标

  • 统计视频观看数top10
  • 统计视频类别热度top10(类别热度:类别下的总视频数)
  • 统计出视频观看数最高的20个视频的所属类别以及类别包含top20视频的个数
  • 统计视频观看数top50所关联视频的所属类别Rank
  • 统计每个类别中的视频热度top10,以Music为例
  • 统计每个类别视频观看数top10
  • 统计上传视频最多的用户top10以及他们上传视频观看次数在前20的视频

2.数据结构

1.视频表

字段 备注 详细描述
videoid 视频唯一id(string) 11位字符串
uploader 视频上传者(string) 上传视频的用户名
age 视频年龄(int) 视频在平台上的整数天
category 视频类别(Array(string)) 上传视频指定的视频分类
length 视频长度(int) 整形数字标识的视频长度
views 观看次数(int) 视频被浏览的次数
rate 视频评分(double) 满分5分
Ratings 流量(int) 视频的流量,整形数字
conments 评论数(int) 一个视频的整数评论数
relatedid 相关视频id(Array(string)) 相关视频的id,最多20个

2.用户表

字段 备注 字段类型
uploader 上传者用户名 string
videos 上传视频数 int
friends 朋友数量 int

3.准备工作

需要准备的表

  • 创建外部数据表 : gulivideo_ori, gulivideo_user_ori
  • 创建最终表: gulivideo_orc,gulivideo_user_ori
  1. # 创建外部数据表
  2. 1. 上传原始数据到HDFS
  3. hadoop fs -mkdir -p /gulivideo/video
  4. hadoop fs -mkdir -p /gulivideo/user
  5. hadoop fs -put /home/atguigu/data/user/user.txt /gulivideo/user
  6. hadoop fs -put /home/atguigu/data/video/*.txt /gulivideo/video
  7. 2. 创建外部数据表:gulivideo_ori
  8. create external table gulivideo_ori(
  9. videoId string,
  10. uploader string,
  11. age int,
  12. category array<String>,
  13. length int,
  14. views int,
  15. rate float,
  16. ratings int,
  17. comments int,
  18. relatedId array<String>
  19. )
  20. row format delimited fields terminated by '\t'
  21. collection items terminated by '&'
  22. stored as textfile
  23. location '/gulivideo/video';
  24. 3. 创建外部数据表: gulivideo_user_ori
  25. create external table gulivideo_user_ori(
  26. uploader string,
  27. Videos int,
  28. friends int
  29. )
  30. row format delimited fields terminated by '\t'
  31. stored as textfile
  32. location '/gulivideo/user';
  1. # 创建orc存储格式带snappy压缩的管理表
  2. 1. gulivideo_orc
  3. create table gulivideo_orc(
  4. videoId string,
  5. uploader string,
  6. age int,
  7. category array<string>,
  8. length int,
  9. views int,
  10. rate float,
  11. ratings int,
  12. comments int,
  13. relatedId array<string>)
  14. stored as orc
  15. tblproperties("orc.compress"="SNAPPY");
  16. 2. gulivideo_user_orc
  17. create table gulivideo_user_orc(
  18. uploader string,
  19. videos int,
  20. friends int)
  21. row format delimited
  22. fields terminated by "\t"
  23. stored as orc
  24. tblproperties("orc.compress"="SNAPPY");
  1. # 向表中插入数据
  2. insert into table gulivideo_orc select * from gulivideo_ori;
  3. insert into table gulivideo_user_orc select * from gulivideo_user_ori;

4.业务分析

需求一: 统计视频观看数Top10

思路 : 使用order by 按照views字段做一个全局排序即可,同时我们设置只显示前10条

  1. select videoId,`views`
  2. from gulivideo_orc
  3. order by `views` desc
  4. limit 10;

需求二:统计视频类别热度Top10(类别热度:类别下的总视频数)

思路:

  1. 即统计每个类别有多少个视频,显示出包含视频最多的前10个类别
  2. 需要按照类别group by聚合,然后count组内的videoId个数即可
  3. 因为当前表结构为: 一个视频对应一个或多个类别,所以如果要group by类别,需要先将类别进行列转行(炸开),然后再进行count 即可
  4. 最终按照热度排序,显示前10条
  1. select t1.category_name,count(t1.videoId) cv
  2. from
  3. (select videoId,category_name
  4. from gulivideo_orc
  5. lateral view explode(category) lv as category_name) t1
  6. group by t1.category_name
  7. order by cv desc
  8. limit 10;

需求三: 统计出视频观看数最高的20个视频的所属类别以及类别包含Top20视频的个数

思路:

  1. 求出观看数前20的视频信息(主要是类别)
  2. 在第一步的结果下,求出观看数前20的视频的类别,需要炸开(列转行),形成新字段category_name
  3. 在第二步的结果下,按照炸开的视频类别category_name 分组,然后统计组内的个数category_count
  1. select t2.category_name,count(t2.videoId)
  2. from
  3. (select t1.videoId,category_name
  4. from
  5. (select videoId, `views` ,category
  6. from gulivideo_orc
  7. order by `views` desc
  8. limit 20) t1
  9. lateral view explode (t1.category) lv as category_name) t2
  10. group by t2.category_name;

需求四: 统计视频观看数top50的视频所关联视频的所属类别排序

思路:

  1. 先找出观看数前50的视频信息(主要是求出关联视频)
  2. 炸开第一步求出的关联视频array,形成一个新字段new_relatedid
  3. 用第二步求出的结果集的new_relatedid和gulivideo_orc表进行join,求出new_relatedid的类别
  4. 炸开第三部结果中的category,形成新字段category_name
  5. 在第四部的结果上,按照category_name分组,然后求出每组的个数 category_count
  6. 在第五步的基础上,对category_count进行排序,利用开窗函数
  1. -- 6.使用rank函数对count_number进行排序(要的是排名)
  2. select t6.category_name,t6.count_number,rank()over(order by t6.count_number desc)
  3. from (
  4. -- 5.将类别分组并统计出其数量
  5. select t5.category_name, count(t5.category_name) count_number
  6. from (
  7. -- 4.将关联视频的类别炸开
  8. select category_name
  9. from (
  10. -- 3.将相关视频的表和视频表进行关联(relatedid_name和videoid)
  11. select t2.relatedid_name, t3.videoid, t3.category
  12. from (
  13. --2.将关联的视频炸开
  14. select t1.relatedid, relatedid_name
  15. from (
  16. --1.获取top50的视频
  17. select videoid, `views`, relatedid
  18. from gulivideo_orc
  19. order by `views` desc
  20. limit 50
  21. ) t1
  22. lateral view explode(t1.relatedid) lv as relatedid_name
  23. ) t2
  24. join gulivideo_orc t3
  25. on t2.relatedid_name = t3.videoid
  26. ) t4
  27. lateral view explode(t4.category) lv as category_name
  28. ) t5
  29. group by t5.category_name
  30. ) t6;

需求五: 统计每个类别中的视频热度(视频观看数) Top10,以Music为例

思路 :

  1. 要想统计Music类别中的视频热度Top10,需要先找到Music类别,那么就需要将category炸开形成新的字段category_name
  2. 然后通过category_name过滤”Music”分类的所有视频信息,按照视频观看数倒序排序
  1. select t1.category_name,t1.`views`
  2. from
  3. (select `views`,category_name
  4. from
  5. gulivideo_orc
  6. lateral view explode(category) lv as category_name) t1
  7. where t1.category_name = 'Music'
  8. order by t1.`views` desc
  9. limit 10;

需求六: 统计每个类别视频观看数Top10

思路:

  1. 把原始表中的类别炸开,形成新字段category_name
  2. 按照炸开的类别字段category_name分区,按照视频观看数views倒序排序进行开窗,求出每个类别下的所有视频的观看次数排名
  3. 按照rk字段对全表进行where过滤,求出每个类别观看数Top10
  1. select t2.videoId,t2.`views`,t2.category_name,t2.r_number
  2. from
  3. (select t1.videoId,t1.`views`,t1.category_name,rank() over(partition by t1.category_name order by t1.`views` desc ) r_number
  4. from
  5. (select videoid,category_name,`views`
  6. from
  7. gulivideo_orc
  8. lateral view explode(category) lv as category_name) t1)t2
  9. where t2.r_number <= 10;

需求七: 统计上传视频最多的用户Top10,以及他们上传的视频观看次数在前20 的视频

此需求的后半段”他们上传的视频观看次数在前20的视频”说的含糊不清,有以下两种约定

约定一: 取Top10中所有人上传的视频的前20

思路:

  1. 去用户表gulivideo_user_orc 求出上传视频最多的10个用户
  2. 关联gulivideo_orc表,求出这10个用户上传的所有视频,按照观看数求前20
  1. # 上传视频最多的用户Top10
  2. select uploader,videos
  3. from
  4. gulivideo_user_orc
  5. order by videos desc
  6. limit 10;
  7. # 他们上传的视频观看次数在前20的视频
  8. select t1.uploader,t2.`views`
  9. from
  10. (select uploader,videos
  11. from
  12. gulivideo_user_orc
  13. order by videos desc
  14. limit 10) t1 join gulivideo_orc t2
  15. on t1.uploader = t2.uploader
  16. order by `views` desc
  17. limit 20;

约定二: 取Top10中每个人上传视频的前20

思路:

  1. 去用户表gulivideo_user_orc求出上传视频最多的10个用户
  2. 关联gulivideo_orc表,求出这10个用户上传的所有视频的id,视频观看次数,还要按照uploader分区,views倒序排序,求出每个uploader的上传的视频的观看排名r_number
  3. 在第二步的基础上,按照rk进行where过滤,求出r_number< =20的数据
  1. select t4.uploader,t4.`views`,t4.r_number
  2. from
  3. (select t3.`views`,t3.uploader,rank() over(partition by t3.uploader order by `views` desc) r_number
  4. from
  5. (select t1.uploader,t2.`views`
  6. from
  7. (select uploader,videos
  8. from gulivideo_user_orc
  9. order by videos desc
  10. limit 10) t1
  11. join gulivideo_orc t2
  12. on t1.uploader = t2.uploader) t3) t4
  13. where t4.r_number <= 20;

第二章.企业级优化

  1. 详情见avi视频