寫在前面:我是「雲祁」,一枚熱愛技術、會寫詩的大數據開發猿。暱稱來源於王安石詩中一句
[ 雲之祁祁,或雨於淵 ]
,甚是喜歡。
寫博客一方面是對自己學習的一點點總結及記錄,另一方面則是希望能夠幫助更多對大數據感興趣的朋友。如果你也對數據中臺、數據建模、數據分析以及Flink/Spark/Hadoop/數倉開發
感興趣,可以關注我的動態 https://blog.csdn.net/BeiisBei ,讓我們一起挖掘大數據的價值~
每天都要進步一點點,生命不是要超越別人,而是要超越自己! (ง •_•)ง
一、背景
在用HQL進行數據分析時,我們不僅想要聚集前的數據,又想要聚集後的數據,這時候往往可以想到用窗口函數,具體窗口函數的使用,可以參考的這篇博文 hive 窗口函數總結 。
幾道開胃菜,每一道筆試題,我都儘可能從多個角度來分析,大家可以參考一下,既可以通過自連接來實現,也可以通過窗口函數來解決,歡迎大家討論 🙆♂️:
二、筆試題實戰
Hive 的五個筆試題 |
---|
【Hive】筆試題 01 |
【Hive】筆試題 02 |
【Hive】筆試題 03 |
【Hive】筆試題 04 |
【Hive】筆試題 05 |
【Hive】大廠熱門數據分析題 |
未持完續… |
三、數據分析題(案例)
場景舉例:北京市學生成績分析 💥
成績的數據格式:時間,學校,年紀,姓名,科目,成績
樣例數據如下:
2013,北大,1,裘容絮,語文,97
2013,北大,1,慶眠拔,語文,52
2013,北大,1,烏灑籌,語文,85
2012,清華,0,欽堯,英語,61
2015,北理工,3,冼殿,物理,81
2016,北科,4,況飄索,化學,92
2014,北航,2,孔須,數學,70
2012,清華,0,王脊,英語,59
2014,北航,2,方部盾,數學,49
2014,北航,2,東門雹,數學,77
create table t_score (
time int,
school string,
class int,
name string,
subjects string,
score int
)
row format delimited fields terminated by ',';
load data local inpath "/opt/data/a.csv" into table t_score
問題:
分組 TopN,選出2014年每個學校、每個年級、分數前三的科目
select t.*
from
(
select
time,
school,
class,
score,
row_number() over (partition by school, class, subjects order by score desc) rank_code
from t_score
where time = "2014"
) t
where t.rank_code <= 3;
詳解如下:
row_number函數:row_number() 按指定的列進行分組生成行序列,從 1 開始,如果兩行記錄的分組列相同,則行序列 +1。
over 函數:是一個窗口函數。
over (order by score) 按照 score 排序進行累計,order by 是個默認的開窗函數。
over (partition by class) 按照班級分區。
over (partition by class order by score) 按照班級分區,並按着分數排序。
over (order by score range between 2 preceding and 2 following) 窗口範圍爲當前行的數據幅度減2加2後的範圍內的數據求和。
優化:
row_number() over (distribute by school, class, subjects sort by score desc) rank_code
2014年,北航,每個班級,每科的分數,及分數上下浮動 2 分的總和
select time,school, class, subjects, score,
sum(score) over (order by score range between 2 preceding and 2 following) sscore
from t_score
where time = "2014" and school="北航";
over (order by score rows between 2 preceding and 2 following):窗口範圍爲當前行前後各移動2行。
where 與 having:2012年,清華 0 年級,總成績大於 200 分的學生以及學生數
select *,sum(score) as total_score,
count(1) over (partition by school, class)
from t_score where school="清華" and class = 0 and time=2012
group by school, class, name,time,subjects,score having total_score > 50;
having 是分組(group by)後的篩選條件,分組後的數據組內再篩選,也就是說 HAVING 子句可以讓我們篩選成組後的各組數據。
where 則是在分組,聚合前先篩選記錄。也就是說作用在 GROUP BY 子句和 HAVING 子句前。
四、情景分析題
今年加入進來了 10 個學校,學校數據差異很大計算每個學校的平均分。
該題主要是考察數據傾斜的處理方式。
group by 方式很容易產生數據傾斜 ❗,需要注意一下幾點:
Map 端部分聚合
hive.map.aggr=true(用於設定是否在 map 端進行聚合,默認值爲真,相當於 combine)
hive.groupby.mapaggr.checkinterval=100000(用於設定 map 端進行聚合操作的條數)
有數據傾斜時進行負載均衡
設定 hive.groupby.skewindata,當選項設定爲 true 是,生成的查詢計劃有兩個 MapReduce 任務。
(先打散數據)
第一個 MapReduce 中,map 的輸出結果集合會隨機分佈到 reduce 中, 每個 reduce 做部分聚合操作,並輸出結果。
這樣處理的結果是,相同的 group by key 有可能分發到不同的 reduce 中,從而達到負載均衡的目的;
第二個 MapReduce 任務再根據預處理的數據結果按照 group by key 分佈到 reduce 中
(這個過程可以保證相同的 group by key 分佈到同一個 reduce 中),最後完成最終的聚合操作。
🚀
假設我創建了一張表,其中包含了 2016 年客戶完成的所有交易的詳細信息:
CREATE TABLE transaction_details
(cust_id INT, amount FLOAT, month STRING, country STRING)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ‘,’ ;
現在我插入了 100 萬條數據,我想知道每個月的總收入。
問:如何高效的統計出結果,寫出步驟即可。 (提示:動態分區)
1.首先分析這個需求,其實並不難,但是由於題目說了,要高效.而且數據量也不小,直接寫sql查詢估計肯定會掛.
2.分析:
a.我們可以通過根據每個月對錶進行分區來解決查詢慢的問題。 因此,對於每個月我們將只掃描分區的數據,而不是整個數據集。
b.但是我們不能直接對現有的非分區表進行分區。所以我們會採取以下步驟來解決這個問題:
c.創建一個分區表,partitioned_transaction:
i.create table partitioned_transaction
(cust_id int, amount float, country string) partitioned by (month string)
row format delimited fields terminated by ‘,’ ;
d.在 Hive 中啓用動態分區:
i.SET hive.exec.dynamic.partition=true;
ii.SET hive.exec.dynamic.partition.mode=nonstrict;
e.將數據從非分區表導入到新創建的分區表中:
i.insert overwrite table partitioned_transaction partition (month) select cust_id, amount, country, month from transaction_details;
f.使用新建的分區表實現需求。
歡迎掃碼關注我的公衆號,在這裏我將專注分享數據倉庫、數據建模與大數據技術的相關內容。