Hive项目之谷粒影音:ETL清洗原数据、Hive统计视频观看数top10、视频类别top、视频观看数top其所属类别、类别流量top、类别热度top、上传视频用户数量top、类别视频观看top
Hive实战之谷粒影音
项目数据下载地址: guiliVideo.zip谷粒影音项目视频表、用户表
包含内容:
两个文件夹
User表中的74702条数据
video表中5张表,每张表中都有多条数据
需求描述
统计硅谷影音视频网站的常规指标,各种TopN指标:
--统计视频观看数Top10
--统计视频类别热度Top10
--统计视频观看数Top20所属类别
--统计视频观看数Top50所关联视频的所属类别Rank
--统计每个类别中的视频热度Top10
--统计每个类别中视频流量Top10
--统计上传视频最多的用户Top10以及他们上传的视频
--统计每个类别视频观看数Top10
项目数据结构
1.视频表
表6-13 视频表
字段 |
备注 |
详细描述 |
video id |
视频唯一id |
11位字符串 |
uploader |
视频上传者 |
上传视频的用户名String |
age |
视频年龄 |
视频在平台上的整数天 |
category |
视频类别 |
上传视频指定的视频分类 |
length |
视频长度 |
整形数字标识的视频长度 |
views |
观看次数 |
视频被浏览的次数 |
rate |
视频评分 |
满分5分 |
ratings |
流量 |
视频的流量,整型数字 |
conments |
评论数 |
一个视频的整数评论数 |
related ids |
相关视频id |
相关视频的id,最多20个 |
表6-14 用户表2.用户表
字段 |
备注 |
字段类型 |
uploader |
上传者用户名 |
string |
videos |
上传视频数 |
int |
friends |
朋友数量 |
int |
通过观察原始数据形式,可以发现,视频可以有多个所属分类,每个所属分类用&符号分割,且分割的两边有空格字符,同时相关视频也是可以有多个元素,多个相关视频又用“\t”进行分割。为了分析数据时方便对存在多个子元素的数据进行操作,我们首先进行数据重组清洗操作。即:将所有的类别用“&”分割,同时去掉两边空格,多个相关视频id也使用“&”进行分割。
ETL原始数据
三件事情
- 长度不够9的删掉
- 视频类别删掉空格
- 该相关视频的分割符
1.ETL之ETLUtil
public class ETLUtil {public static String oriString2ETLString(String ori){StringBuilder etlString = new StringBuilder();String[] splits = ori.split("\t");if(splits.length < 9) return null;splits[3] = splits[3].replace(" ", "");for(int i = 0; i < splits.length; i++){if(i < 9){if(i == splits.length - 1){etlString.append(splits[i]); }else{etlString.append(splits[i] + "\t"); }}else{if(i == splits.length - 1){etlString.append(splits[i]);}else{etlString.append(splits[i] + "&");}}}return etlString.toString();}
}
2.ETL之Mapper
import java.io.IOException;import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;import com.z.youtube.util.ETLUtil;public class VideoETLMapper extends Mapper<Object, Text, NullWritable, Text>{Text text = new Text();@Overrideprotected void map(Object key, Text value, Context context) throws IOException, InterruptedException {String etlString = ETLUtil.oriString2ETLString(value.toString());if(StringUtils.isBlank(etlString)) return;text.set(etlString);context.write(NullWritable.get(), text);}
}
3.ETL之Runner
import java.io.IOException;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;public class VideoETLRunner implements Tool {private Configuration conf = null;@Overridepublic void setConf(Configuration conf) {this.conf = conf;}@Overridepublic Configuration getConf() {return this.conf;}@Overridepublic int run(String[] args) throws Exception {conf = this.getConf();conf.set("inpath", args[0]);conf.set("outpath", args[1]);Job job = Job.getInstance(conf, "youtube-video-etl");job.setJarByClass(VideoETLRunner.class);job.setMapperClass(VideoETLMapper.class);job.setMapOutputKeyClass(NullWritable.class);job.setMapOutputValueClass(Text.class);job.setNumReduceTasks(0);this.initJobInputPath(job);this.initJobOutputPath(job);return job.waitForCompletion(true) ? 0 : 1;}private void initJobOutputPath(Job job) throws IOException {Configuration conf = job.getConfiguration();String outPathString = conf.get("outpath");FileSystem fs = FileSystem.get(conf);Path outPath = new Path(outPathString);if(fs.exists(outPath)){fs.delete(outPath, true);}FileOutputFormat.setOutputPath(job, outPath);}private void initJobInputPath(Job job) throws IOException {Configuration conf = job.getConfiguration();String inPathString = conf.get("inpath");FileSystem fs = FileSystem.get(conf);Path inPath = new Path(inPathString);if(fs.exists(inPath)){FileInputFormat.addInputPath(job, inPath);}else{throw new RuntimeException("HDFS中该文件目录不存在:" + inPathString);}}public static void main(String[] args) {try {int resultCode = ToolRunner.run(new VideoETLRunner(), args);if(resultCode == 0){System.out.println("Success!");}else{System.out.println("Fail!");}System.exit(resultCode);} catch (Exception e) {e.printStackTrace();System.exit(1);}}
}
4.执行ETL
上传数据到HDFS笔记
[atguigu@hadoop102 datas]$ hadoop fs -put user /
[atguigu@hadoop102 datas]$ hadoop fs -put video /
gulivideo_user_orc:
insert into table gulivideo_user_orc select * from gulivideo_user_ori; |
完整步骤:
创建maven工程,在pom中添加如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>hdfs</artifactId><groupId>Hdfs20190817</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><groupId>hive</groupId><artifactId>Hive20190828</artifactId><dependencies><!-- https://mvnrepository.com/artifact/org.apache.hive/hive-exec --><dependency><groupId>org.apache.hive</groupId><artifactId>hive-exec</artifactId><version>1.2.1</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>RELEASE</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.8.2</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-common</artifactId><version>2.7.2</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>2.7.2</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-hdfs</artifactId><version>2.7.2</version></dependency><dependency><groupId>jdk.tools</groupId><artifactId>jdk.tools</artifactId><version>1.8</version><scope>system</scope><systemPath>C:/DeveloperTools/Java/jdk1.8.0_211/lib/tools.jar</systemPath></dependency></dependencies></project>
新建三个类用于数据清洗
ETLMapper
package guliETL;import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;import java.io.IOException;/*** @author cherry* @create 2019-08-29-15:49*/
public class ETLMapper extends Mapper<LongWritable, Text, Text, NullWritable> {private Text k = new Text();@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {//1、获取一行数据String line = value.toString();//2.清洗数据String etlStr = ETLUtils.etlStr(line);//3.过滤掉空数据if (StringUtils.isBlank(etlStr)) return;//4.写出数据k.set(etlStr);context.write(k, NullWritable.get());}
}
ETLUtils
package guliETL;/*** 工具类用于清洗数据* 1.过滤脏数据* 2.将类别字段中的空格" "替换为""** @author cherry* @create 2019-08-29-15:51*/
public class ETLUtils {public static String etlStr(String line) {//0.按照制表符切割数据String[] split = line.split("\t");//1.过滤脏数据,将长度不够9的删掉if (split.length < 9) {return null;}//2.去掉类别字段中的空格split[3] = split[3].replaceAll(" ", "");//3.替换关联视频的分隔符StringBuffer sb = new StringBuffer();for (int i = 0; i < split.length; i++) {if (i < 9) {if (i == split.length - 1) sb.append(split[1]);else sb.append(split[i]).append("\t");} else {if (i == split.length - 1) sb.append(split[i]);else sb.append(split[i]).append("&");}}return sb.toString();}
}
ETLDriver
package guliETL;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;/*** 实现Tool接口对Driver进行封装** @author cherry* @create 2019-08-29-16:23*/
public class ETLDriver implements Tool {private Configuration conf;public static void main(String[] args) throws Exception {int run = ToolRunner.run(new ETLDriver(), args);//将返回结果打印到控制台System.out.println(run);}@Overridepublic int run(String[] args) throws Exception {//1.获取Job对象Job job = Job.getInstance(getConf());//2.封装driver类job.setJarByClass(ETLDriver.class);//3.关联Mapper类job.setMapperClass(ETLMapper.class);//4.Mapper输出KV类型job.setMapOutputKeyClass(Text.class);job.setMapOutputValueClass(NullWritable.class);//5.最终输出类型job.setOutputKeyClass(Text.class);job.setOutputValueClass(NullWritable.class);//6.输入输出路径FileInputFormat.setInputPaths(job, new Path(args[0]));//通过传参FileOutputFormat.setOutputPath(job, new Path(args[1]));//补充:将Reduce的个数设置为0以提高效率job.setNumReduceTasks(0);//7.提交boolean b = job.waitForCompletion(true);return b ? 0 : 1;}@Overridepublic void setConf(Configuration conf) {this.conf = conf;}@Overridepublic Configuration getConf() {return this.conf;}
}
将maven工程打包
将生成的jar文件重命名为ETL.jar,长传到集群
业务分析
1 统计视频观看数Top10
思路:使用order by按照views字段做一个全局排序即可,同时我们设置只显示前10条。
hive (gulivideo)> select videoId, views, comments from gulivideo_orc order by views desc limit 10;
转存失败重新上传取消
最终代码:
select videoId, uploader, age, category, length, views, rate, ratings, comments
from gulivideo_orc
order by views
desc limit
10;
2 统计视频类别热度Top10
思路:
1) 即统计每个类别有多少个视频,显示出包含视频最多的前10个类别。
SELECT videoId,category_name
FROM gulivideo_orc
lateral view explode(category) category_t as category_name; t1
2) 我们需要按照类别group by聚合,然后count组内的videoId个数即可。
3) 因为当前表结构为:一个视频对应一个或多个类别。所以如果要group by类别,需要先将类别进行列转行(展开),然后再进行count即可。
4) 最后按照热度排序,显示前10条。
最终代码:
select category_name as category, count(t1.videoId) as hot
from (select videoId,category_name from gulivideo_orc lateral view explode(category) t_catetory as category_name) t1
group by t1.category_name
order by hot
desc limit
10;
3 统计出视频观看数最高的20个视频的所属类别以及类别包含Top20视频的个数
思路:
1) 先找到观看数最高的20个视频所属条目的所有信息,降序排列
SELECTvideoId,views,category
FROMgulivideo_orc
ORDER BYviews DESC
LIMIT 20;t1
2) 把这20条信息中的category分裂出来(列转行)
SELECTdistinct(category_name)
FROM(SELECTvideoId,views,categoryFROMgulivideo_orcORDER BYviews DESCLIMIT 20) t1 lateral VIEW explode (category) category_t AS category_name;
t2
3) 最后查询视频分类名称和该分类下有多少个Top20的视频
最终代码:
selectcategory_name as category,count(t2.videoId) as hot_with_views
from (selectvideoId,category_namefrom (select*fromgulivideo_orcorder byviewsdesc limit20) t1 lateral view explode(category) t_catetory as category_name) t2
group bycategory_name
order byhot_with_views
desc;
4 统计视频观看数Top50所关联视频的所属类别Rank
1)查询出观看数最多的前50个视频的所有信息(当然包含了每个视频对应的关联视频),记为临时表t1
t1:观看数前50的视频
select*
fromgulivideo_orc
order byviews
desc limit50;
2)将找到的50条视频信息的相关视频relatedId列转行,记为临时表t2
t2:将相关视频的id进行列转行操作
selectexplode(relatedId) as videoId
fromt1;
3)将相关视频的id和gulivideo_orc表进行inner join操作
t5:得到两列数据,一列是category,一列是之前查询出来的相关视频id
(selectdistinct(t2.videoId),t3.category
fromt2
inner joingulivideo_orc t3 on t2.videoId = t3.videoId) t4 lateral view explode(category) t_catetory as category_name;
4) 按照视频类别进行分组,统计每组视频个数,然后排行
最终代码:
selectcategory_name as category,count(t5.videoId) as hot
from (selectvideoId,category_namefrom (selectdistinct(t2.videoId),t3.categoryfrom (selectexplode(relatedId) as videoIdfrom (select*fromgulivideo_orcorder byviewsdesc limit50) t1) t2inner joingulivideo_orc t3 on t2.videoId = t3.videoId) t4 lateral view explode(category) t_catetory as category_name) t5
group bycategory_name
order byhot
desc;
5 统计每个类别中的视频热度Top10,以Music为例
思路:
1) 要想统计Music类别中的视频热度Top10,需要先找到Music类别,那么就需要将category展开,所以可以创建一张表用于存放categoryId展开的数据。
2) 向category展开的表中插入数据。
3) 统计对应类别(Music)中的视频热度。
最终代码:
创建表类别表:
create table gulivideo_category(videoId string, uploader string, age int, categoryId string, length int, views int, rate float, ratings int, comments int, relatedId array<string>)
row format delimited
fields terminated by "\t"
collection items terminated by "&"
stored as orc;
向类别表中插入数据:
insert into table gulivideo_category select videoId,uploader,age,categoryId,length,views,rate,ratings,comments,relatedId from gulivideo_orc lateral view explode(category) catetory as categoryId;
统计Music类别的Top10(也可以统计其他)
select videoId, views
from gulivideo_category
where categoryId = "Music"
order by views
desc limit
10;
6 统计每个类别中视频流量Top10,以Music为例
思路:
1) 创建视频类别展开表(categoryId列转行后的表)
2) 按照ratings排序即可
最终代码:
select videoId,views,ratings
from gulivideo_category
where categoryId = "Music"
order by ratings
desc limit 10;
7 统计上传视频最多的用户Top10以及他们上传的观看次数在前20的视频
思路:
1) 先找到上传视频最多的10个用户的用户信息
select *
from gulivideo_user_orc
order by videos
desc limit 10;
2) 通过uploader字段与gulivideo_orc表进行join,得到的信息按照views观看次数进行排序即可。
最终代码:
select t2.videoId, t2.views,t2.ratings,t1.videos,t1.friends
from (select * from gulivideo_user_orc order by videos desc limit 10) t1
join gulivideo_orc t2
on t1.uploader = t2.uploader
order by views desc
limit
20;
将观看次数设置为100检测,可以看出以上代码没问题
8 统计每个类别视频观看数Top10
思路:
1) 先得到categoryId展开的表数据
2) 子查询按照categoryId进行分区,然后分区内排序,并生成递增数字,该递增数字这一列起名为rank列
3) 通过子查询产生的临时表,查询rank值小于等于10的数据行即可。
最终代码:
select t1.*
from (select videoId,categoryId,views,row_number() over(partition by categoryId order by views desc) rank from gulivideo_category) t1
where rank <= 10;
Hive项目之谷粒影音:ETL清洗原数据、Hive统计视频观看数top10、视频类别top、视频观看数top其所属类别、类别流量top、类别热度top、上传视频用户数量top、类别视频观看top相关推荐
- discuz论坛中,如何上传并插入一段本地视频,并支持实时展示、实时播放
一.创建编辑器工具栏视频播放功能键 1.打开discuz论坛后台,在界面模块找到编辑器设置. 新增一条video标签,自己定义上传图标,默认大小为21x20的. 我们可以模仿qq标签的参数设置,来设置 ...
- SSM上传,下载,在线播放视频
SSM上传,下载,在线播放视频 前言 基于ckplayer插件的视频在线播放,首先需要下载ckplayer插件.引入你的javaweb项目. 核心代码 上传的Jsp代码 <form method ...
- 阿里云视频点播-URL批量拉取上传(调整为多个视频上传)
阿里云视频点播之URL批量拉取上传(调整为多个视频上传) 项目引入阿里云视频点播PHP-SDK URL批量拉取上传(调整为多个视频上传) 项目引入阿里云视频点播PHP-SDK 背景:2021年乐视云的 ...
- java短视频上传阿里云流程_短视频上传
启动上传前需要设置上传回调,需要实现VODSVideoUploadCallback回调:vodsVideoUploadClient.uploadWithVideoAndImg(vodSessionCr ...
- tpl.func.php,微赞微擎常用媒体上传函数 单图|多图|音频|视频
本文最后更新于2019-06-25,已超过 1年没有更新,如果文章内容.图片或者下载资源失效,请留言反馈,我会及时处理,谢谢! 温馨提示:本文共3017个字,读完预计8分钟. 函数库路径:web\co ...
- ajax上传.mp4文件不出错,ajax视频如何上传?
使用ajax如何上传视频呢?是否了解过呢?这个功能其实在各个网站中非常的常见,通用的技术是否了解呢?希望今天小编能给你们带来帮助哦,接下来就让我们一起来了解下吧. 功能:可实现拖拽上传视频,有进度条显 ...
- 【腾讯云的1001种玩法】 Laravel 整合微视频上传管理能力,轻松打造视频App后台...
版权声明:本文由白宦成原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/108597001488193402 来源:腾云阁 ...
- fastdfs上传文件资料(PDF,视频,图片,FileCaseUtil,FileUploadUtil)并生成缩略图
javacv里面有类型转换器的使用,对视频图片的处理工具等等 一.UML图 二.代码 pom依赖 <!-- fastdfs--><dependency><groupId& ...
- 优酷视频html代码在哪,如何把视频上传到优酷并获取视频通用代码?
我们在网站上添加视频,一般是有两种情况,一:在非产品非文章页面上添加视频,例如首页,使用到的是组件里面的视频组件:二:在产品或文章页面上添加视频,在内容->产品/文章->添加产品/文章-& ...
最新文章
- [Android官方API阅读]___Application Fundamentals
- IndexError: only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) and integer or boo
- 残疾人无障碍设施工程改造送上门 900户家庭
- 我2017年游泳特训安排
- An unspecified error occurred!
- [vue] 你有写过自定义组件吗?
- Linux 登陆用户时启动 ssh-agent 并在退出时关闭
- 【POJ2559】Largest Rectangle in a Histogram(单调栈)
- 又找到一个免费的ASP.net2.0免费空间,支持MS Sql Server Express2005 及Ftp
- Linux下安装zabbix-agent详解
- 把Date类型的Fri Feb 01 00:00:00 CST 2019转换成yyyy-MM-dd格式
- 刘潇翔:基于OpenHarmony的仿生四足狗开发分享
- C++随机生成中文名的实例
- win7 c盘空间不足怎么扩大
- UE4 如何开启 EQS
- Ethercat远程IO模块接线准则
- java 常用英语单词
- 对不起 我来晚了 —— Android群英传 出版祭
- SVN各种异常解决整理
- BIO与BIO的区别介绍详解
热门文章
- 第四次 Erlang 开发者大会(CN Erlounge IV)正式开通注册通道
- [.NET/C#]快速采集全国城市商圈数据
- 计算机专业英语词汇表RSTUVW
- 《Python数据分析与挖掘实战》笔记(四):数据预处理
- 使用kettle采集excel表格中的数据
- 四大会计师事务所python数据分析_用Python玩转数据分析4
- mysql统计重复次数并加序号_insert-mysql数据插入,计数时出现重复,序号不对
- Mysql面试题50例
- 记一次c#调matlab时初始化异常的解决过程
- iOS 用 AVPlayer 播放一个本地音频文件