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,評分,評分時間戳
資料:
資料要求:
(1)寫shell指令碼清洗資料。(hive不支援解析多位元組的分隔符,也就是說hive只能解析':', 不支援解析'::',所以用普通方式建表來使用是行不通的,要求對資料做一次簡單清洗)(2)使用Hive能解析的方式進行
Hive要求:正確建表,匯入資料(三張表,三份資料),並驗證是否正確
問題6:求1997年上映的電影中,評分最高的10部Comedy類電影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;
核心要點:過濾條件 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這四個欄位。
最後判斷1997年上映型別為Comedy排名前10的電影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;
由於資料中電影的型別中字母有大小寫之分,在進行判斷的時候要考慮,判斷一個字串中是否包含一個子串這裡使用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;