天天看點

Hive之學習之路

1、自定義函數UDF

UDF 一進一出(行) 改變大小寫、增加字元串之類的操作

UDAF 聚集函數(行) 多進一出 count max min sum

UDTF 一進多出(行) lateral view explore() 例如:explode

2、大資料解決什麼事情

傳輸 存儲 計算

3、hive定義

解決海量結構化日志的資料統計,結構化資料檔案映射為一張表,是一個資料倉庫工具,分析資料底層預設實作是MapReduce

4、hive的缺點

HQL表達能力有限

(1)疊代式算法無法表達

(2)資料挖掘不擅長(一般是疊代,挖掘兩個資料的關系)

5、hive的架構裡有哪些元件

中繼資料(meta store):hive表與hdfs上檔案的映射關系,預設derby資料庫,正常時mysql存

解析器-編譯器-優化器-執行器

6、hive沒有索引,查詢資料,需要掃描整個表,延遲較高

7、顯示資料庫詳細資訊,extended 例子desc database extended db_hive;

8、如果資料庫不為空,可以采用 cascade 指令,強制删除

建表:

create table log_orc_snappy(

track_time string,

url string,

session_id string,

referer string,

ip string,

end_user_id string,

city_id string )

row format delimited fields terminated by ‘\t’

stored as orc tblproperties (“orc.compress”=“SNAPPY”);

壓縮模式是snappy的建表語句

查詢結構:

select

from

join in

where

group by

order by

having

limit

順序是:先from->join in->where->group by->select->having->order by->limit

select之後的才能用别名

SELECT count(A1) c,B1 from a JOIN b on a.A2=b.B2 GROUP BY B1 HAVING c>1能執行

是以,having排在select的後面,因為hiving能識别select後的别名,說明select運作過了

是以就涉及到一些優化的問題:

select

id,

name

from A

join B on A.id=B.id

where A.id=11;

可以優化成

select

from

(select id ,name from A where A.id=11) r1

join B

on r1.id =B.id

提前縮小資料集,因為join先執行,是以執行的資料集就比較大,那如果先把where執行完,再執行join,資料集就會小很多。不過where條件一定是原表有的才能用這個

對某個查詢結果再做加工的要用子查詢

例子:

select

count() ct

ct+1

明顯是錯誤的,因為count() ct和ct+1是平級的,count要查詢全表,才能出來,是以就找不到ct,更别說+1,是以對于某一個結果再進行加工的時候要用子函數

select

count(*) ct

from

A; t1

select

ct,

ct+1

from

t1

select

ct,

ct+1

from

(select

count(*) ct

from

A)

10、建表時候的語句:STORED AS file_format

COMMENT 為表和列添加注釋

CLUSTERED BY 分桶

PARTITIONED BY 分區

LOCATION 改變存儲路徑

hive中 full join 保留所有資料

11、show create table cc; 檢視建表語句

12、LIKE 允許使用者複制現有的表結構,但是不複制資料。

13、desc formatted dept;查詢表是外部表EXTERNAL_TABLE還是内部表 MANAGED_TABLE

14、修改内部表 student2 為外部表

alter table student2 set tblproperties(‘EXTERNAL’=‘TRUE’); 固定寫法,區分大小寫

修改外部表 student2 為内部表

alter table student2 set tblproperties(‘EXTERNAL’=‘FALSE’);

15、增加分區

建立單個分區:hive (default)> alter table dept_partition add partition(month=‘201706’) ;

同時建立多個分區:alter table dept_partition add partition(month=‘201705’) partition(month=‘201704’);

檢視分區表有多少分區: show partitions dept_partition;

删除單個分區:alter table dept_partition drop partition

(month=‘201704’);

檢視分區表結構:desc formatted dept_partition;

執行修複指令 msck repair table a;

16、重命名表:ALTER TABLE table_name RENAME TO new_table_name

增加列:alter table dept_partition add columns(deptdesc string);

更新列:alter table dept_partition change column a(之前列名) b(改後列名) int(對應格式 );

替換列:alter table dept_partition replace columns(a string, bstring, c string);直接把目标表中所有列都替換掉了

DML 資料操作

1、根據查詢結果建立表

create table if not exists student3 as select id, name from student;

2、清除表中資料 truncate table a;

3、select官方文檔 https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Select

4、常用函數 sum count max min avg平均數

5、A<=>B 和A=B差別在于如果 A 和 B 都為 NULL,則傳回 TRUE,也就是說<=>可以比對null,=不可以

6、IN[數值 1, 數值 2] 兩邊是閉區間

7、like查詢 % 代表零個或多個字元(任意個字元)。_ 代表一個字元。relike 後邊可以使用java正則

例子:查找以 2 開頭薪水的員工資訊 select * from emp where sal LIKE ‘2%’;

查找第二個數值為 2 的薪水的員工資訊select * from emp where sal LIKE ‘_2%’;

查找薪水中含有 2 的員工資訊 select * from emp where sal RLIKE ‘[2]’;

8、where 後面不能寫聚合函數,而 having 後面可以使用聚合函數。having 隻用于 group by 分組統計語句。where 針對表中的列發揮作用,查詢資料;having 針對查詢結果中的列發揮作用,

篩選資料

例子: 求每個部門的平均薪水大于 2000 的部門

select deptno, avg(sal) avg_sal from emp group by deptno having avg_sal > 2000;

9、在hive中,join文法隻支援等值連接配接,不支援非等值連接配接,和mysql不同

10、left join 指的是:首先取出a表中所有資料,然後再加上與a,b比對的的資料

11、連接配接操作,Hive 總是按照從左到右的順序執行的

12、沒有連接配接條件就會生成笛卡兒積,兩個表所有行對乘

排序

1、全局排序(Order By)隻有一個reducer

ASC(ascend): 升序(預設)

DESC(descend): 降序

2、每個 MapReduce 内部排序(Sort By)

設定 reduce 個數: set mapreduce.job.reduces=3; 再sort by 就生效了

檢視設定 reduce 個數:set mapreduce.job.reduces;

————但是如果隻用sort by 分的區是随機分區,是以加入Distribute By

注意:!!Hive 要求 DISTRIBUTE BY 語句要寫在 SORT BY 語句之前。

————如果當 distribute by 和 sorts by 字段相同時,可以使用 cluster by。cluster by 除了具有 distribute by 的功能外還兼具 sort by 的功能。但是排序隻能是升序排序,不能指定排序規則為 ASC 或者 DESC。

分桶

1、分區不是按照建表字段,分桶需要按照建表字段來分桶

建立分桶表時,資料通過子查詢的方式導入。直接用load導入,相當于在hdfs上使用put,改變的是中繼資料資訊,一個檔案不可能分成多個。

但是同過子查詢方式導入也需要先設定屬性:

set hive.enforce.bucketing=true; 開啟分桶功能

set mapreduce.job.reduces=-1;将reduce個數設定為-1,意思就是自己會根據桶的個數來決定reduce的個數,這也是預設值

2、分桶抽樣查詢

查詢表 stu_buck 中的資料

select * from stu_buck tablesample(bucket 1 out of 4 on id);

tablesample 是抽樣語句,文法:TABLESAMPLE(BUCKET x OUT OF y) 。

x是從哪個桶開始抽,y 必須是 table 總 bucket 數的倍數或者因子,y是抽取總數 bucket/y 桶的資料,如果抽的超過一個分區,例如一共12個桶,x=1,y=3 ,就是從桶1開始抽,抽4個桶,分别是1,4,7,10這4個桶,每次都+y

x值必須小于y值

常用函數

1、空字段指派

select nvl(comm,-1) from emp; 如果員工的 comm 為 NULL,則用-1 代替

如果員工的 comm 為 NULL,則用上司 id 代替 select nvl(comm,mgr) from emp;另外一列來代替

2、時間類

date_format:格式化時間 date_format(‘2019-06-29’,‘yyyy-MM-dd’) 後面是你想格式化後的格式

date_add:時間跟天數相加; date_sub:時間跟天數相減,可以傳負數,兩個記一個就行,select date_add(‘2019-06-29’,5);可以自動跨月,前面得是字元串

datediff:兩個時間相減 :datediff(‘2019-06-29’,‘2019-06-24’);

select datediff(‘2019-06-24 12:12:12’,‘2019-06-29’);

OK

_c0

-5

因為2019/2/12 時間函數無法解析,是以用如下函數

regexp_replace(對哪個字段進行切換,你要替換的什麼東西,換成什麼)

例子:regexp_replace(‘2019/2/12’,’/’,’-’)

3、case when

列轉行就要用到case when

dept_id,

sum(case sex when ‘男’ then 1 else 0 end) male_count,

sum(case sex when ‘女’ then 1 else 0 end) female_count

from

emp_sex

group by

dept_id;

如果隻有兩個分支也可以用if來代替

dept_id,

if(sex=‘男’,1,0) male_count,

if(sex=‘女’,1,0) male_count if的結構:if(布爾值,true的結果,false的結果)

from

emp_sex

group by

dept_id;

4、CONCAT

CONCAT_WS(separator, str1, str2,…):如果有多個同樣的分隔符,可以用這個!!必須是String

例子: concat_ws(’-’.‘as’,‘df’)

***COLLECT_SET(列)***:因為set函數沒有重複的值,是以這個函數有去重的作用,會生成一個array數組 聚合函數,列轉行

可以混合使用:concat_ws(’-’.COLLECT_SET(列)) 把一列資料形成一個-分割的字元串

5、EXPLODE(col):将 hive 一列中複雜的 array 或者 map 結構拆分成多行。explode(炸裂的意思)

如果直接用select explode(a)from b; 可以全部炸開

如果select f,explode(a) from b 報錯,文法不能這樣使用

這時就需要LATERAL VIEW (側寫)跟原來表關聯上

用法:

select

movie,

category_name

from

movie_info lateral view explode(category) table_tmp(表别名) as category_name(列别名);

substring(orderdate,1,7)截取字元串從1到7個字元

視窗函數

當一個聚合和一個多行的在一起需要用到視窗函數

開窗:

一、對開窗的了解

開窗等于開一部分資料集出來

1、開窗函數必須在聚合函數後邊

2、開窗函數開出的資料集,隻給聚合函數使用

3、over()裡面沒有參數代表對整個資料集進行開窗

4、開窗是針對于每一條資料來開窗

我的了解是:over() 是用來標明聚合函數所使用的資料集的

例子:

(1)select name

from business

where substring(orderdate,1,7) = ‘2017-04’

小三

小三

小四

小屋

小氣

(2)select name,count() over()

from business

where substring(orderdate,1,7) = ‘2017-04’

小三 5

小三 5

小四 5

小屋 5

小氣 5

為什麼呢,首先在(2)中先做了一些(1)中的查詢名字的操作,形成了一個名字的資料集,也就是這5個人(不一定都是不同的人)。然後再做count()操作,針對于哪一部分進行count呢,over()裡面沒有參數,就是針對所有資料集做count(*),那所有資料集是什麼,就是這5個人。

如果不加over(),那麼有聚合函數必須加group by ,那麼就會按照name分組,那麼結果就應該是

小三 2

小四 1

小屋 1

小氣 1

二、over()的那些參數

1、over(order by a) 對每個資料開窗的時候,加上了比目前資料小的資料,一起作為一個開窗資料集

例子:有一列資料

shuzi

4

5

6

7

對4開窗的時候,資料集就是4

對5 開窗的時候資料集是

4

5

對6開窗是

4

5

6以此類推

是以用sum函數的時候,結果集就是

4

9(4+5)

15(4+5+6)

22(4+5+6+7)

2、over(distrubute by a) 類似于group by 針對a 分組分資料集,也就是說小米的資料集就是3個小米

比如如下資料

a ——b

小米 30

小米 20

小米 10

小頂 40

小皮 50

sum(b)over(distrubute by a)

小米 60

小米 60

小米 60

小頂 40

小皮 50

那麼同理

如下資料

a ——b——c

小米 30 3

小米 20 2

小米 10 1

小頂 40 4

小皮 50 6

3、sum(b)over(distrubute by a sort by c) 就是先把資料集限定在小米裡,然後對小米對應的c排序累加,原理和order by 那個一樣 ,隻不過order by 那個是全局累加,這個是在分區的資料集裡累加

那麼結果是:

小米 10 1

小米 30 2

小米 60 3

小頂 40 4

小皮 50 6

4、over()裡面還有其他函數,都是劃分資料集的(不太常用)

CURRENT ROW:目前行;

n PRECEDING:往前 n 行資料;

n FOLLOWING:往後 n 行資料;

UNBOUNDED:起點,UNBOUNDED PRECEDING 表示從前面的起點,UNBOUNDED

FOLLOWING 表示到後面的終點;

例子:

select

xx,

sum(ss)over(rows between 2 preceding and current row) 目前行到前面2行的資料加和

from a;

5、over()跟在後面的(必須有over才能用)

(1)LAG(col,n):往前第 n 行資料; 隻指一條資料 col哪一列 還可以在n後邊在加個參數

如果第一個資料的前面是沒有資料的,就把這個參數就是填在第一行 LAG(col,n,p)

例子:select name,orderdate,cost,

lag(orderdate,1,‘1900-01-01’) over(partition by name order by

orderdate ) as time1, 就是所有orderdate位置的資料寫的都是前1天

lag(orderdate,2) over (partition by name

order by orderdate) as time2

from business;

就是所有orderdate位置的資料寫的都是前2天

(2)LEAD(col,n):往後第 n 行資料;——同理

partition by…order by=distrubute by … sort by

(3)NTILE(n):把有序分區中的行分發到指定資料的組中,各個組有編号,編号從 1 開始,

對于每一行,NTILE 傳回此行所屬的組的編号。注意:n 必須為 int 類型。

例子:

select * from (

select name,orderdate,cost, ntile(5) over(order by orderdate)

sorted

from business

) t

where sorted = 1;

ntile(5) 就是把一個資料集分成5份,order by orderdate是哪一部分資料集呢,按順序的時間分成5份

也就是前20%的時間

6、rank 函數

RANK() 排序就是 1 1 3 4 排序相同時會重複,總數不會變

DENSE_RANK() 排序就是 1 1 2 3 排序相同時會重複,總數會減少 dense密集的意思

ROW_NUMBER() 排序就是 1 2 3 4 會根據順序計算

思考:group by 用不了的情況才用over,一般是聚合函數,有相同人,需要按每個人來聚合後面的數,就不能用group by ,group by 就把相同的姓名的都合在一起了,但是要每個人單獨顯示就得用over了

實際用到over的案例,了解一下

(1)查詢在 2017 年 4 月份購買過的顧客及總人數

(2)查詢顧客的購買明細及購買總額

(3)上述的場景,要将 cost 按照日期進行累加

(4)查詢顧客上次的購買時間

(5)查詢前 20%時間的訂單資訊

就是要展示明細的同時還要聚合

group by 有時候等同于 over(partition by ) over在group by後進行

distinct去重是針對于全表的,用一個reducer處理,資料量大的時候不适合使用