1. 程式人生 > >Hive影評案例二

Hive影評案例二

現有如此三份資料:
1、users.dat    資料格式為:  2::M::56::16::70072
對應欄位為:UserID BigInt, Gender String, Age Int, Occupation String, Zipcode String
對應欄位中文解釋:使用者id,性別,年齡,職業,郵政編碼

2、movies.dat資料格式為: 2::Jumanji (1995)::Adventure|Children's|Fantasy
對應欄位為:MovieID BigInt, Title String, Genres String
對應欄位中文解釋:電影ID,電影名字,電影型別

3、ratings.dat資料格式為:  1::1193::5::978300760
對應欄位為:UserID BigInt, MovieID BigInt, Rating Double, Timestamped String
對應欄位中文解釋:使用者ID,電影ID,評分,評分時間戳

資料:
連結:https://pan.baidu.com/s/1VL7Khp9TbEQ2kqDLNeInHA 密碼:kfp5

資料要求:
(1)寫shell指令碼清洗資料。(hive不支援解析多位元組的分隔符,也就是說hive只能解析':', 不支援解析'::',所以用普通方式建表來使用是行不通的,要求對資料做一次簡單清洗)
(2)使用Hive能解析的方式進行

Hive要求:正確建表,匯入資料(三張表,三份資料),並驗證是否正確

create table users(userid BigInt, gender String, age Int, occupation String, zipcode String)
row format serde 'org.apache.hadoop.hive.serde2.RegexSerDe'
with serdeproperties('input.regex'='(.*)::(.*)::(.*)::(.*)::(.*)','output.format.string'='%1$s %2$s %3$s %4$s %5$s')
stored as textfile;
load data local inpath '/home/hadoop/moviedata/users.dat' INTO TABLE users;
select * from users limit 5;

create table movies(movieid BigInt, name String, type String)
row format serde 'org.apache.hadoop.hive.serde2.RegexSerDe'
with serdeproperties('input.regex'='(.*)::(.*)::(.*)','output.format.string'='%1$s %2$s %3$s')
stored as textfile;
load data local inpath '/home/hadoop/moviedata/movies.dat' INTO TABLE movies;
select * from movies limit 5;

create table ratings(userid BigInt, movieid BigInt, rate Double, ts String)
row format serde 'org.apache.hadoop.hive.serde2.RegexSerDe'
with serdeproperties('input.regex'='(.*)::(.*)::(.*)::(.*)','output.format.string'='%1$s %2$s %3$s %4$s')
stored as textfile;
load data local inpath '/home/hadoop/moviedata/ratings.dat' INTO TABLE ratings;
select * from ratings limit 5;
問題6:求1997年上映的電影中,評分最高的10部Comedy類電影

核心要點:過濾條件  year = 1997      type = Comedy

                 按照評分進行降序排列 , 取 Top10      order by avgrate desc limit 10;

通過上篇文章《Hive影評案例一》我們已經有了movie_rate_year表,裡面有三個欄位:movieid, avgrate,  year

根據題目所求建立一個表:movie_rate_year_type  包含:movieid, avgrate, year, type這四個欄位。

create table movie_rate_year_type as 
select a.movieid as movieid, a.avgrate as avgrate, a.year as year, b.type as type 
from movie_rate_year a join movies b on a.movieid = b.movieid;
最後判斷1997年上映型別為Comedy排名前10的電影

由於資料中電影的型別中字母有大小寫之分,在進行判斷的時候要考慮,判斷一個字串中是否包含一個子串這裡使用instr( );

select a.movieid as movieid, b.name as name, a.avgrate as avgrate 
from movie_rate_year_type a join movies b on a.movieid = b.movieid 
where year = 1997 and instr(lcase(a.type), "comedy") > 0
order by avgrate desc limit 10;
問題7:該影評庫中各種型別電影中評價最高的5部電影(型別,電影名,平均影評分)

核心要點:

            分組條件: group by  movietype

            取值: 每組資料按照平均影評分降序排列;

                        每組取前5條記錄。

 注意:這裡使用order進行排序的時候 order by avgrate desc limit 5;這樣是不正確的;

上面這種情況是全域性排序取前五,沒有達到我們的要求,所以使用 order by movietype, avgrate desc limit 5;

通過分析資料我們可以看出,如果我們能將Comedy|Drama這個電影型別欄位進行拆分,這會有利於我們的統計。

2324    Life Is Beautiful (La Vita � bella) (1997)      4.999861111111111Comedy|Drama
2324    Life Is Beautiful (La Vita � bella) (1997)      4.999861111111111Comedy
2324    Life Is Beautiful (La Vita � bella) (1997)      4.999861111111111Drama

這個裂變的過程是這個題目的難點之一,對於這個問題使用的是explode( )函式,這個函式要傳入一個Array或者Map型別的資料,那麼我們就要考慮怎麼將Comedy|Drama這種型別的字串轉換成Array或者Map了,Hive中有一個split( )函式,我們可以使用split( )函式指定分隔符將字串轉換為Array型別的資料,然後要考慮怎麼資料進行上面的那種變形。Hive中有lateral view 這個操作,這樣我們就能將原來的一條記錄轉換為多條記錄了。

create table movie_rate_year_type_exp as 
select a.movieid as movieid, a.avgrate as avgrate, a.year as year, tv.movietype   
from movie_rate_year_type a 
lateral view explode(split(a.type, "\\|")) tv as movietype;

另一個難點是我們怎麼進行分組取TopN,通過Hive提供的視窗函式我們可以完成這個操作;

這裡使用的是row_number( )來為每一個組生成一個標記值index,通過over( )指明分桶和排序欄位,這樣我們就能夠對每一組中排好序的記錄進行遞增編號,我們可以直接通過這個標號index來限制獲取每一組的TopN.

select * from(
select movieid, avgrate, year, movietype, 
row_number() over (distribute by movietype sort by avgrate desc) as index 
from movie_rate_year_type_exp) a where a.index <= 5;
問題8:各年評分最高的電影型別(年份,型別,影評分)

核心要點:

           分組:年

           排序:各型別電影的平均分

           各型別電影的平均分:按電影型別分組,求每個組中電影評分的平均分。

建立一個表:movietype_year_rate表中的欄位:year  movietype  avgrate

我們在上一個題目中建立了一個movie_rate_year_type_exp表,我們按照這個表中的year和movietype進行分組求平均影評分

create table movietype_year_rate as 
select year, movietype, avg(avgrate) as avgrate 
from movie_rate_year_type_exp 
group by year, movietype;
最後我們給資料進行分組排序新增標號:
select * from (
select year, movietype, avgrate, 
row_number() over (distribute by year sort by avgrate desc) as index 
from movietype_year_rate) where index <= 1;
問題9:每個地區最高評分的電影名,把結果存入HDFS(地區,電影名,影評分)

核心要點:
            分組條件:地區 users.zipcode
            電影的平均評分:avg(ratings.rate)
            排序:每一組中的記錄參與降序排序
            取值:每個地區的評分最高的電影。 index = 1;

第一步:構建一個zip_id_rate表,用來儲存每個地區每部電影的平均影評分及相關資訊。

通過users.zipcode和ratings.movieid進行分組,求avg(ratings.rate).

create table zip_id_rate as 
select b.zipcode as zipcode, a.movieid  as movieid, avg(a.rate) as avgrate 
from ratings a join users b on a.userid = b.userid 
group by b.zipcode, a.movieid;

第二步:通過上面建立的表,我們對上面的資料進行分組排序,並新增編號。

create table zip_id_rate_index as 
select zipcode, movieid, avgrate, 
row_number() over (distribute by zipcode sort by avgrate desc) as index 
from zip_id_rate;

到這裡我們就已經完成了資料的建立,剩下的就只有查詢Top1並寫入到HDFS了。

insert overwrite direcotry "/movie/zicode_max_rate/" 
select * from zip_id_rate_index where index <= 1;