Hive -- 實習實踐經驗總結

explode列轉行函數的用法

select ~, col_name 
from table_name
lateral view explode(...) tmp_view as col_name

(…)裏面是要分割的列,tmp_view 臨時表 可以隨便寫, col_name 是要查詢的列

多行進行合併

concat_ws(’,’,collect_set())
concat_ws(’,’,collect_list())
數據

name type
aa 1
aa 2
aa 2
aa 3
select 
	name,
	concat_ws(',',collect_set(cast(type as string))) as type
from 
    collect_tmp_table
group by name;

結果:

name type
a 1,2,3
select 
	name,
	concat_ws(',',collect_list(cast(type as string))) as type
from 
    collect_tmp_table
group by name;

結果:

name type
a 1,2,2,3

collect_set()(對某列進行去重)
collect_list()(對某列不進行去重)
必須保證要合併的行是string類型,不是的話用cast(col as string)轉換

where 條件要寫在lateral view 後面,不然報錯

select ~, col_name 
from table_name
lateral view explode(...) tmp_view as col_name
where ....;

json字符串解析之get_json_object與json_tuple

要解析的json

json_name
{"name":"Triumph,"sex":"man","age":"25"}
{"name":"Candy,"sex":"woman","age":"22"}
{"name":"jack,"sex":"man","age":"12"}
  • get_json_object函數的作用:
    用來解析json字符串的一個字段
    例子:
  select get_json_object(json_name,'$.name') as name,
         get_json_object(json_name,'$.sex') as sex,
         get_json_object(json_name,'$.age') as age
  from table_name
  • json_tuple函數的作用:
    用來解析json字符串中的多個字段
    例子:
  select a.json_name,
      b.name,
      b.sex,
      b.age
  from table_name a 
  lateral view json_tuple(json_name,'name', 'sex', 'age') b as name, sex, age; 

distribute by的數據傾斜優化

distribute by是控制在map端如何拆分數據給reduce端的。hive會根據distribute by後面列,對應reduce的個數進行分發,默認是採用hash算法.
大部分情況都用於解決Map輸出的文件大小不均,Reduce輸出文件大小不均,小文件過多,文件超大等情況,動態分區過多,個別分區下文件大小不均,例如數據延遲等情況,如何控制不同分區下文件的個數。

insert overwrite  table table_name partition(day)
select * from temp_name 
distribute by day, pmod(cast(rand()*1000 as int),50);

這個sql,就是通過pmod(cast(rand()*1000 as int),50)對文件進行分區,防止按照day字段分區會出現的數據傾斜現象。
該數據會分爲50塊,對多少取模就分爲多少塊。
cast(a,b) 將a類型轉換爲b類型。
pmod(a,b) a對b 取模。
pmod(cast(rand()*1000 as int),50)和cast(rand()*1000 as int)%50是一樣的。

獲取當前日期時間函數

from_unixtime(unix_timestamp(),'yyyy-MM-dd HH:mm:ss') 
from_unixtime(unix_timestamp(),'yyyy-MM-dd  HH') 
from_unixtime(unix_timestamp(),'yyyyMMdd') 

在這裏插入圖片描述
也可以用current_timetamp(),它不支持from_unixtime(current_timetamp(),‘yyyy-MM-dd HH:mm:ss’) 這種截取格式
在這裏插入圖片描述

union 和 union all

如果我們需要將兩個select語句的結果作爲一個整體顯示出來,我們就需要用到union或者union all關鍵字。union(或稱爲聯合)的作用是將多個結果合併在一起顯示出來,但這兩者從使用和效率上來說都有所不同。
1、對重複結果的處理:UNION在進行錶鏈接後會篩選掉重複的記錄,Union All不會去除重複記錄。
2、對排序的處理:Union將會按照字段的順序進行排序;UNION ALL只是簡單的將兩個結果合併後就返回。
從效率上說,UNION ALL 要比UNION快很多,所以,如果可以確認合併的兩個結果集中不包含重複數據且不需要排序時的話,那麼就使用UNION ALL。

union:選取不同的值,不允許重複值出現,按字段進行排序,效率低

select column_name(s) from table_name1
union
select column_name(s) from table_name2

union all:允許重複,不排序,隨機插入,直接合並,效率高

select column_name(s) from table_name1
union all
select column_name(s) from table_name2

join 連接可以添加條件先對右部分表進行過濾再進行聚合

select 
	a.id, a.age, b.age
from
	a join b on a.id=b.id and b.age>20
where a.age>20

先按b.age>20過濾b表,然後進行join聚合操作,再按a.age>20對聚合後的數據進行過濾

聚合函數+窗口函數over()

OVER():指定分析函數工作的數據窗口大小,決定了聚合函數的範圍,這個數據窗口大小可能會隨着行的變而變化,同時可以使用以下進行限定範圍。

select name,orderdate,cost,
sum(cost) over() as sample1,--所有行相加
sum(cost) over(partition by name) as sample2,--按name分組,組內數據相加
sum(cost) over(partition by name order by orderdate) as sample3,--按name分組,組內數據累加
sum(cost) over(partition by name order by orderdate rows between UNBOUNDED PRECEDING and current row )  as sample4 ,--和sample3一樣,由起點到當前行的聚合
sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING   and current row) as sample5, --當前行和前面一行做聚合
sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING   AND 1 FOLLOWING  ) as sample6,--當前行和前邊一行及後面一行
sum(cost) over(partition by name order by orderdate rows between current row and UNBOUNDED FOLLOWING ) as sample7 --當前行及後面所有行
from t_window;

如果只使用partition by子句,未指定order by的話,我們的聚合是分組內的聚合。
使用了order by子句,未使用window子句的情況下,默認從起點到當前行。
window子句:

  • PRECEDING:往前
  • FOLLOWING:往後
  • CURRENT ROW:當前行
  • UNBOUNDED:起點
  • UNBOUNDED PRECEDING:表示從前面的起點
  • UNBOUNDED FOLLOWING:表示到後面的終點

窗口函數:lag,lead,first_value,last_value

  1. lag
    lag(col,n,~) 用於統計窗口內往上第n行值。
    第一個參數爲列名,第二個參數爲往上第n行(可選,默認爲1),第三個參數爲默認值(當往上第n行爲NULL時候,取默認值,如不指定,則爲NULL)
    用法示例:
select 
	age,sex,
	lag(age,2) over(partition by sex order by age desc) as rank
from
	row_table;
  1. lead(與lag相反)
    lead(col,n,~) 用於統計窗口內往下第n行值。
    第一個參數爲列名,第二個參數爲往下第n行(可選,默認爲1),第三個參數爲默認值(當往下第n行爲NULL時候,取默認值,如不指定,則爲NULL)

  2. first_value
    返回相對於窗口中第一行的指定列的值。
    用法示例:

select 
	id,age,sex,
	first_value(id) over(partition by sex order by age desc) as rank
from
	row_table;
  1. last_value
    返回相對於窗口中最後一行的指定列的值。

row_number over()的使用

row_number() over()他的作用就是分組排序加上序號標記
row_number() over(partition by col1 order by col2)表示根據col1分組,在分組內部根據col2排序,而此函數計算的值就表示每組內部排序後的順序編號(該編號在組內是連續並且唯一的)。
原表:

id age sex
1 10 m
2 14 m
3 16 w
4 8 w
5 20 m
6 18 w
select 
	id,age,sex,
	row_number() over(partition by sex order by age desc) as rank
from
	row_table;

結果:

id age sex rank
4 8 w 1
3 16 w 2
6 18 w 3
1 10 m 1
2 14 m 2
5 20 m 3

row_number() over(partition by sex order by age desc) as rank
就相當於增加了一列(rank),over()中partition by sex是按照sex分組,order by age desc按照年齡排序,然後row_number()在加上序號。

row_number()、rank()和dense_rank()

row_number:不管排名是否有相同的,都按照順序
例如:1,2,3,4,5,…,n
rank:排名相同的名次一樣,同一排名有幾個,後面排名就會跳過幾次
例如:1,2,2,4,5,5,5,8,…,n
dense_rank:排名相同的名次一樣,且後面名次不跳躍
例如:1,2,2,3,4,4,4,5,…,n
具體用法同上

計算天數差

datediff(start_time,end_time)

select datediff('2019-07-26 15:32:23','2019-07-22 16:23:34');

結果:4

計算時間差

(unix_timestamp(start_time)-unix_timestamp(end_time))/3600

select (unix_timestamp('2019-07-26 15:32:23') - unix_timestamp('2019-07-26 13:23:34')) /3600;

結果:2.1469444444444443

Python SimpleHTTPServer下載文件(尤其是從遠程服務器上下載)

在去重時能使用group by代替distinct就不要使用distinct

當一個表的數據量非常大的時候,會發現一個簡單的count(distinct col_name)這種語句跑的特別慢,和直接運行count(col_name)的時間差了很多。
在能使用group by代替distinct就不要使用distinct
Hive在處理時產生了數據傾斜
使用distinct會將所有的col_name都shuffle到一個reducer裏面,這就是數據傾斜,再看group by直接按列名分組,起多個reducer(動態分配,如果沒設置reduce的個數),將數據分佈到多臺機器上執行,處理速度就快了。
由於沒有設置Reduce的個數,Hive會根據數據的大小動態的指定Reduce大小,也可以手動設置

set mapred.reduce.tasks=300

注意:設置了reduce的任務個數,distinct去重也是走一個reduce,所以會很慢。

設置map的數量提高運行速度

1.如果想增加map個數,則設置mapred.map.tasks 爲一個較大的值。
2.如果想減小map個數,則設置mapred.min.split.size 爲一個較大的值。
mapred.max.split.size是參考值

這個參數是設置map的任務的數量。

set mapred.map.tasks=2000;

這個參數是設置每個map的大小,數值越大,每個map的大小就越大,相應的map的總數量就減少了。

set mapred.max.split.size=102400;

left join on + 多條件與 where 區別

總體規則:先匹配,再篩選where條件。
left join如果在on時添加限制條件,對左邊表進行約束的話是不會生效的,但是對右表會生效,會先篩選右邊表的數據再和左表關聯。
合理利用會減少查詢的時間。
例一:

select * from table a left join table b on a.id=b.id and a.id is not null
where b.id is not null;

例二:

select * from table a left join table b on a.id=b.id and  b.id is not null
where a.id is not null;

例一中a.id is not null不起作用,關聯時跑的是a表的全數據
例二中b.id is not null起作用,關聯時,先篩選b表的數據,然後再和a表進行關聯
例一例二中的where都是在表關聯完,然後再篩選數據

Mapreduce中Combiner的使用及誤區

–該部分點標題,看大佬的總結!

避免科學計數法

cast(列名 as decimal(m,n))的方式避免科學計數法結果的出現。
m是取多少整數位,n是取多少小數位。自動給四捨五入。
在這裏插入圖片描述

MSCK命令修復Hive表分區

我們平時通常是通過alter table add partition方式增加Hive的分區的,但有時候會通過HDFS put/cp命令往表目錄下拷貝分區目錄,如果目錄多,需要執行多條alter語句,非常麻煩。Hive提供了一個"Recover Partition"的功能。

具體語法如下:

MSCK REPAIR TABLE table_name;

原理相當簡單,執行後,Hive會檢測如果HDFS目錄下存在但表的metastore中不存在的partition元信息,更新到metastore中。
注意:爲了讓 MSCK 命令工作,分區的目錄名必須是 /partition_name=partition_value/結構的,否則將無法添加分區。這時候你必須使用add partition命令了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章