訂閱
糾錯
加入自媒體

最強最全面的Hive SQL開發(fā)指南,四萬字全面解析

2021-11-30 10:25
園陌
關注

本文整體分為兩部分,第一部分是簡寫,如果能看懂會用,就直接從此部分查,方便快捷,如果不是很理解此SQl的用法,則查看第二部分,是詳細說明,當然第二部分語句也會更全一些!

第一部分:

hive模糊搜索表:show tables like '*name*';

查看表結構信息:desc table_name;

查看分區(qū)信息:show partitions table_name;

加載本地文件:load data local inpath '/xxx/test.txt' overwrite into table dm.table_name;

從查詢語句給table插入數(shù)據(jù):insert overwrite table table_name partition(dt) select * from table_name;

導出數(shù)據(jù)到本地系統(tǒng):insert overwrite local directory '/tmp/text' select a.* from table_name a order by 1;

創(chuàng)建表時指定的一些屬性:

字段分隔符:row format delimited fields terminated by ' '

行分隔符:row format delimited lines terminated by ''

文件格式為文本型存儲:stored as textfile

命令行操作:hive -e 'select table_cloum from table'執(zhí)行一個查詢,在終端上顯示mapreduce的進度,執(zhí)行完畢后,最后把查詢結果輸出到終端上,接著hive進程退出,不會進入交互模式

hive -S -e 'select table_cloum from table' -S,終端上的輸出不會有mapreduce的進度,執(zhí)行完畢,只會把查詢結果輸出到終端上。

hive修改表名:alter table old_table_name rename to new_table_name;

hive復制表結構:create table new_table_name like table_name;

hive添加字段:alter table table_name add columns(columns_values bigint comment 'comm_text');

hive修改字段:alter table table_name change old_column new_column string comment 'comm_text';

刪除分區(qū):alter table table_name drop partition(dt='2021-11-30');

添加分區(qū):alter table table_name add partition (dt='2021-11-30');

刪除空數(shù)據(jù)庫:drop database myhive2;

強制刪除數(shù)據(jù)庫:drop database myhive2 cascade;

刪除表:drop table score5;

清空表:truncate table score6;

向hive表中加載數(shù)據(jù)

直接向分區(qū)表中插入數(shù)據(jù):insert into table score partition(month ='202107') values ('001','002','100');通過load方式加載數(shù)據(jù):load data local inpath '/export/servers/hivedatas/score.csv' overwrite into table score partition(month='201806');通過查詢方式加載數(shù)據(jù):insert overwrite table score2 partition(month = '202106') select s_id,c_id,s_score from score1;查詢語句中創(chuàng)建表并加載數(shù)據(jù):create table score2 as select * from score1;在創(chuàng)建表是通過location指定加載數(shù)據(jù)的路徑:create external table score6 (s_id string,c_id string,s_score int) row format delimited fields terminated by ',' location '/myscore';export導出與import 導入 hive表數(shù)據(jù)(內(nèi)部表操作):

create table techer2 like techer; --依據(jù)已有表結構創(chuàng)建表

export table techer to '/export/techer';

import table techer2 from '/export/techer';

20. hive表中數(shù)據(jù)導出

insert導出

將查詢的結果導出到本地:insert overwrite local directory '/export/servers/exporthive' select * from score;

將查詢的結果格式化導出到本地:insert overwrite local directory '/export/servers/exporthive' row format delimited fields terminated by ' ' collection items terminated by '#' select * from student;

將查詢的結果導出到HDFS上(沒有l(wèi)ocal):insert overwrite directory '/export/servers/exporthive' row format delimited fields terminated by ' ' collection items terminated by '#' select * from score;

Hadoop命令導出到本地:dfs -get /export/servers/exporthive/000000_0 /export/servers/exporthive/local.txt;hive shell 命令導出

基本語法:(hive -f/-e 執(zhí)行語句或者腳本 > file)hive -e "select * from myhive.score;" > /export/servers/exporthive/score.txt

hive -f export.sh > /export/servers/exporthive/score.txt

export導出到HDFS上:export table score to '/export/exporthive/score';Hive查詢語句

GROUP BY 分組:select s_id ,avg(s_score) avgscore from score group by s_id having avgscore > 85; 對分組后的數(shù)據(jù)進行篩選,使用 having

join 連接:inner join 內(nèi)連接;left join 左連接;right join 右鏈接;full join 全外鏈接。

order by 排序:ASC(ascend): 升序(默認) DESC(descend): 降序

sort by 局部排序:每個MapReduce內(nèi)部進行排序,對全局結果集來說不是排序。

distribute by 分區(qū)排序:類似MR中partition,進行分區(qū),結合sort by使用

Hive函數(shù)1. 聚合函數(shù)

指定列值的數(shù)目:count()

指定列值求和:sum()

指定列的最大值:max()

指定列的最小值:min()

指定列的平均值:avg()

非空集合總體變量函數(shù):var_pop(col)

非空集合樣本變量函數(shù):var_samp (col)

總體標準偏離函數(shù):stddev_pop(col)

分位數(shù)函數(shù):percentile(BIGINT col, p)

中位數(shù)函數(shù):percentile(BIGINT col, 0.5)

2. 關系運算

A LIKE B:LIKE比較,如果字符串A符合表達式B 的正則語法,則為TRUE

A RLIKE B:JAVA的LIKE操作,如果字符串A符合JAVA正則表達式B的正則語法,則為TRUE

A REGEXP B:功能與RLIKE相同

3. 數(shù)學運算

支持所有數(shù)值類型:加(+)、減(-)、乘(*)、除(/)、取余(%)、位與(&)、位或(|)、位異或(^)、位取反(~)

4. 邏輯運算

支持:邏輯與(and)、邏輯或(or)、邏輯非(not)

5. 數(shù)值運算

取整函數(shù):round(double a)

指定精度取整函數(shù):round(double a, int d)

向下取整函數(shù):floor(double a)

向上取整函數(shù):ceil(double a)

取隨機數(shù)函數(shù):rand(),rand(int seed)

自然指數(shù)函數(shù):exp(double a)

以10為底對數(shù)函數(shù):log10(double a)

以2為底對數(shù)函數(shù):log2()

對數(shù)函數(shù):log()

冪運算函數(shù):pow(double a, double p)

開平方函數(shù):sqrt(double a)

二進制函數(shù):bin(BIGINT a)

十六進制函數(shù):hex()

絕對值函數(shù):abs()

正取余函數(shù):pmod()

6. 條件函數(shù)

if

case when

coalesce(c1,c2,c3)

nvl(c1,c2)

7. 日期函數(shù)

獲得當前時區(qū)的UNIX時間戳: unix_timestamp()

時間戳轉日期函數(shù):from_unixtime()

日期轉時間戳:unix_timestamp(string date)

日期時間轉日期函數(shù):to_date(string timestamp)

日期轉年函數(shù):year(string date)

日期轉月函數(shù):month (string date)

日期轉天函數(shù): day (string date)

日期轉小時函數(shù): hour (string date)

日期轉分鐘函數(shù):minute (string date)

日期轉秒函數(shù): second (string date)

日期轉周函數(shù): weekofyear (string date)

日期比較函數(shù): datediff(string enddate, string startdate)

日期增加函數(shù): date_add(string startdate, int days)

日期減少函數(shù):date_sub (string startdate, int days)

8. 字符串函數(shù)

字符串長度函數(shù):length(string A)

字符串反轉函數(shù):reverse(string A)

字符串連接函數(shù): concat(string A, string B…)

帶分隔符字符串連接函數(shù):concat_ws(string SEP, string A, string B…)

字符串截取函數(shù): substr(string A, int start, int len)

字符串轉大寫函數(shù): upper(string A)

字符串轉小寫函數(shù):lower(string A)

去空格函數(shù):trim(string A)

左邊去空格函數(shù):ltrim(string A)

右邊去空格函數(shù):rtrim(string A)

正則表達式替換函數(shù):regexp_replace(string A, string B, string C)

正則表達式解析函數(shù): regexp_extract(string subject, string pattern, int index)

URL解析函數(shù):parse_url(string urlString, string partToExtract [, string keyToExtract])返回值: string

json解析函數(shù):get_json_object(string json_string, string path)

空格字符串函數(shù):space(int n)

重復字符串函數(shù):repeat(string str, int n)

首字符ascii函數(shù):ascii(string str)

左補足函數(shù):lpad(string str, int len, string pad)

右補足函數(shù):rpad(string str, int len, string pad)

分割字符串函數(shù): split(string str, string pat)

集合查找函數(shù): find_in_set(string str, string strList)

9. 窗口函數(shù)

分組求和函數(shù):sum(pv) over(partition by cookieid order by createtime) 有坑,加不加 order by 差別很大,具體詳情在下面第二部分。

分組內(nèi)排序,從1開始順序排:ROW_NUMBER() 如:1234567

分組內(nèi)排序,排名相等會在名次中留下空位:RANK() 如:1233567

分組內(nèi)排序,排名相等不會在名次中留下空位:DENSE_RANK() 如:1233456

有序的數(shù)據(jù)集合平均分配到指定的數(shù)量(num)個桶中:NTILE()

統(tǒng)計窗口內(nèi)往上第n行值:LAG(col,n,DEFAULT)

統(tǒng)計窗口內(nèi)往下第n行值:LEAD(col,n,DEFAULT)

分組內(nèi)排序后,截止到當前行,第一個值:FIRST_VALUE(col)

分組內(nèi)排序后,截止到當前行,最后一個值: LAST_VALUE(col)

小于等于當前值的行數(shù)/分組內(nèi)總行數(shù):CUME_DIST()

以下函數(shù)建議看第二部分詳細理解下,此處僅簡寫,!

將多個group by 邏輯寫在一個sql語句中: GROUPING SETS

根據(jù)GROUP BY的維度的所有組合進行聚合:CUBE

CUBE的子集,以最左側的維度為主,從該維度進行層級聚合:ROLLUP

第二部分1. 對數(shù)據(jù)庫的操作創(chuàng)建數(shù)據(jù)庫:create database if not exists myhive;

說明:hive的表存放位置模式是由hive-site.xml當中的一個屬性指定的 :hive.metastore.warehouse.dir

創(chuàng)建數(shù)據(jù)庫并指定hdfs存儲位置 :

create database myhive2 location '/myhive2';

修改數(shù)據(jù)庫:alter  database  myhive2  set  dbproperties('createtime'='20210329');

說明:可以使用alter  database 命令來修改數(shù)據(jù)庫的一些屬性。但是數(shù)據(jù)庫的元數(shù)據(jù)信息是不可更改的,包括數(shù)據(jù)庫的名稱以及數(shù)據(jù)庫所在的位置

查看數(shù)據(jù)庫詳細信息查看數(shù)據(jù)庫基本信息

hive (myhive)> desc  database  myhive2;

查看數(shù)據(jù)庫更多詳細信息

hive (myhive)> desc database extended  myhive2;

刪除數(shù)據(jù)庫刪除一個空數(shù)據(jù)庫,如果數(shù)據(jù)庫下面有數(shù)據(jù)表,那么就會報錯

drop  database  myhive2;

強制刪除數(shù)據(jù)庫,包含數(shù)據(jù)庫下面的表一起刪除

drop  database  myhive  cascade;

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

注意:

如果使用 group by 分組,則 select 后面只能寫分組的字段或者聚合函數(shù)

where和having區(qū)別:

1 having是在 group by 分完組之后再對數(shù)據(jù)進行篩選,所以having 要篩選的字段只能是分組字段或者聚合函數(shù)

2 where 是從數(shù)據(jù)表中的字段直接進行的篩選的,所以不能跟在gruopby后面,也不能使用聚合函數(shù)

join 連接INNER JOIN 內(nèi)連接:只有進行連接的兩個表中都存在與連接條件相匹配的數(shù)據(jù)才會被保留下來

select * from techer t [inner] join course c on t.t_id = c.t_id; -- inner 可省略

LEFT OUTER JOIN 左外連接:左邊所有數(shù)據(jù)會被返回,右邊符合條件的被返回

select * from techer t left join course c on t.t_id = c.t_id; -- outer可省略

RIGHT OUTER JOIN 右外連接:右邊所有數(shù)據(jù)會被返回,左邊符合條件的被返回、

select * from techer t right join course c on t.t_id = c.t_id;

FULL OUTER JOIN 滿外(全外)連接: 將會返回所有表中符合條件的所有記錄。如果任一表的指定字段沒有符合條件的值的話,那

就使用NULL值替代。

SELECT * FROM techer t FULL JOIN course c ON t.t_id = c.t_id ;

注:1. hive2版本已經(jīng)支持不等值連接,就是 join on條件后面可以使用大于小于符號了;并且也支持 join on 條件后跟or (早前版本 on 后只支持 = 和 and,不支持 > < 和 or)

2.如hive執(zhí)行引擎使用MapReduce,一個join就會啟動一個job,一條sql語句中如有多個join,則會啟動多個job

注意:表之間用逗號(,)連接和 inner join 是一樣的

select * from table_a,table_b where table_a.id=table_b.id;

它們的執(zhí)行效率沒有區(qū)別,只是書寫方式不同,用逗號是sql 89標準,join 是sql 92標準。用逗號連接后面過濾條件用 where ,用 join 連接后面過濾條件是 on。

order by 排序全局排序,只會有一個reduce

ASC(ascend): 升序(默認) DESC(descend): 降序

SELECT * FROM student s LEFT JOIN score sco ON s.s_id = sco.s_id ORDER BY sco.s_score DESC;

注意:order by 是全局排序,所以最后只有一個reduce,也就是在一個節(jié)點執(zhí)行,如果數(shù)據(jù)量太大,就會耗費較長時間

sort by 局部排序每個MapReduce內(nèi)部進行排序,對全局結果集來說不是排序。

設置reduce個數(shù)

set mapreduce.job.reduces=3;

查看設置reduce個數(shù)

set mapreduce.job.reduces;

查詢成績按照成績降序排列

select * from score sort by s_score;

將查詢結果導入到文件中(按照成績降序排列)

insert overwrite local directory '/export/servers/hivedatas/sort' select * from score sort by s_score;

distribute by  分區(qū)排序distribute by:類似MR中partition,進行分區(qū),結合sort by使用

設置reduce的個數(shù),將我們對應的s_id劃分到對應的reduce當中去

set mapreduce.job.reduces=7;

通過distribute by  進行數(shù)據(jù)的分區(qū)

* from score distribute by s_id sort by s_score;

注意:Hive要求 distribute by 語句要寫在 sort by 語句之前

cluster by當distribute by和sort by字段相同時,可以使用cluster by方式.

cluster by除了具有distribute by的功能外還兼具sort by的功能。但是排序只能是正序排序,不能指定排序規(guī)則為ASC或者DESC。

以下兩種寫法等價

select * from score cluster by s_id;

select * from score distribute by s_id sort by s_id;

Hive函數(shù)聚合函數(shù)hive支持 count(),max(),min(),sum(),avg() 等常用的聚合函數(shù)

注意:

聚合操作時要注意null值

count(*) 包含null值,統(tǒng)計所有行數(shù)

count(id) 不包含null值

min 求最小值是不包含null,除非所有值都是null

avg 求平均值也是不包含null

非空集合總體變量函數(shù): var_pop語法: var_pop(col)

返回值: double

說明: 統(tǒng)計結果集中col非空集合的總體變量(忽略null)

非空集合樣本變量函數(shù): var_samp語法: var_samp (col)

返回值: double

說明: 統(tǒng)計結果集中col非空集合的樣本變量(忽略null)

總體標準偏離函數(shù): stddev_pop語法: stddev_pop(col)

返回值: double

說明: 該函數(shù)計算總體標準偏離,并返回總體變量的平方根,其返回值與VAR_POP函數(shù)的平方根相同

中位數(shù)函數(shù): percentile語法: percentile(BIGINT col, p)

返回值: double

說明: 求準確的第pth個百分位數(shù),p必須介于0和1之間,但是col字段目前只支持整數(shù),不支持浮點數(shù)類型

關系運算支持:等值(=)、不等值(。 或 <>)、小于(<)、小于等于(<=)、大于(>)、大于等于(>=)

空值判斷(is null)、非空判斷(is not null)

LIKE比較: LIKE語法: A LIKE B

操作類型: strings

描述: 如果字符串A或者字符串B為NULL,則返回NULL;如果字符串A符合表達式B 的正則語法,則為TRUE;否則為FALSE。B中字符”_”表示任意單個字符,而字符”%”表示任意數(shù)量的字符。

JAVA的LIKE操作: RLIKE語法: A RLIKE B

操作類型: strings

描述: 如果字符串A或者字符串B為NULL,則返回NULL;如果字符串A符合JAVA正則表達式B的正則語法,則為TRUE;否則為FALSE。

REGEXP操作: REGEXP語法: A REGEXP B

操作類型: strings

描述: 功能與RLIKE相同

示例:select 1 from tableName where 'footbar' REGEXP '^f.*r$';

結果:1

數(shù)學運算支持所有數(shù)值類型:加(+)、減(-)、乘(*)、除(/)、取余(%)、位與(&)、位或(|)、位異或(^)、位取反(~)

邏輯運算支持:邏輯與(and)、邏輯或(or)、邏輯非(not)

數(shù)值運算取整函數(shù): round語法: round(double a)

返回值: BIGINT

說明: 返回double類型的整數(shù)值部分 (遵循四舍五入)

示例:select round(3.1415926) from tableName;

結果:3

指定精度取整函數(shù): round語法: round(double a, int d)

返回值: DOUBLE

說明: 返回指定精度d的double類型

hive> select round(3.1415926,4) from tableName;

3.1416

向下取整函數(shù): floor語法: floor(double a)

返回值: BIGINT

說明: 返回等于或者小于該double變量的最大的整數(shù)

hive> select floor(3.641) from tableName;

3

向上取整函數(shù): ceil語法: ceil(double a)

返回值: BIGINT

說明: 返回等于或者大于該double變量的最小的整數(shù)

hive> select ceil(3.1415926) from tableName;

4

取隨機數(shù)函數(shù): rand語法: rand(),rand(int seed)

返回值: double

說明: 返回一個0到1范圍內(nèi)的隨機數(shù)。如果指定種子seed,則會等到一個穩(wěn)定的隨機數(shù)序列

hive> select rand() from tableName; -- 每次執(zhí)行此語句得到的結果都不同

0.5577432776034763

hive> select rand(100) ;  -- 只要指定種子,每次執(zhí)行此語句得到的結果一樣的

0.7220096548596434

自然指數(shù)函數(shù): exp語法: exp(double a)

返回值: double

說明: 返回自然對數(shù)e的a次方

hive> select exp(2) ;

7.38905609893065

以10為底對數(shù)函數(shù): log10語法: log10(double a)

返回值: double

說明: 返回以10為底的a的對數(shù)

hive> select log10(100) ;

2.0

此外還有:以2為底對數(shù)函數(shù): log2()、對數(shù)函數(shù): log()

冪運算函數(shù): pow語法: pow(double a, double p)

返回值: double

說明: 返回a的p次冪

hive> select pow(2,4) ;

16.0

開平方函數(shù): sqrt語法: sqrt(double a)

返回值: double

說明: 返回a的平方根

hive> select sqrt(16) ;

4.0

二進制函數(shù): bin語法: bin(BIGINT a)

返回值: string

說明: 返回a的二進制代碼表示

hive> select bin(7) ;

111

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

圖片標題

hive (hive_explode)> select get_json_object(concat('{',sale_info_1,'}'),'$.source') as source,get_json_object(concat('{',sale_info_1,'}'),'$.monthSales') as monthSales,get_json_object(concat('{',sale_info_1,'}'),'$.userCount') as monthSales,get_json_object(concat('{',sale_info_1,'}'),'$.score') as monthSales from explode_lateral_view LATERAL VIEW explode(split(regexp_replace(regexp_replace(sale_info,'\[\{',''),'}]',''),'},\{'))sale_info as sale_info_1;

總結:

Lateral View通常和UDTF一起出現(xiàn),為了解決UDTF不允許在select字段的問題。Multiple Lateral View可以實現(xiàn)類似笛卡爾乘積。Outer關鍵字可以把不輸出的UDTF的空結果,輸出成NULL,防止丟失數(shù)據(jù)。

行轉列

相關參數(shù)說明:

CONCAT(string A/col, string B/col…):返回輸入字符串連接后的結果,支持任意個輸入字符串;

CONCAT_WS(separator, str1, str2,...):它是一個特殊形式的 CONCAT()。第一個參數(shù)剩余參數(shù)間的分隔符。分隔符可以是與剩余參數(shù)一樣的字符串。如果分隔符是 NULL,返回值也將為 NULL。這個函數(shù)會跳過分隔符參數(shù)后的任何 NULL 和空字符串。分隔符將被加到被連接的字符串之間;

COLLECT_SET(col):函數(shù)只接受基本數(shù)據(jù)類型,它的主要作用是將某字段的值進行去重匯總,產(chǎn)生array類型字段。

數(shù)據(jù)準備:

nameconstellationblood_type孫悟空白羊座A老王射手座A宋宋白羊座B豬八戒白羊座A鳳姐射手座A

需求: 把星座和血型一樣的人歸類到一起。結果如下:

射手座,A            老王|鳳姐

白羊座,A            孫悟空|豬八戒

白羊座,B            宋宋

實現(xiàn)步驟:

創(chuàng)建本地constellation.txt,導入數(shù)據(jù)node03服務器執(zhí)行以下命令創(chuàng)建文件,注意數(shù)據(jù)使用 進行分割

cd /export/servers/hivedatas

vim constellation.txt

數(shù)據(jù)如下:

孫悟空 白羊座 A

老王 射手座 A

宋宋 白羊座 B      

豬八戒 白羊座 A

鳳姐 射手座 A

創(chuàng)建hive表并導入數(shù)據(jù)創(chuàng)建hive表并加載數(shù)據(jù)

hive (hive_explode)> create table person_info(

name string,

constellation string,

blood_type string)

row format delimited fields terminated by " ";

                加載數(shù)據(jù)

hive (hive_explode)> load data local inpath '/export/servers/hivedatas/constellation.txt' into table person_info;

按需求查詢數(shù)據(jù)hive (hive_explode)> select

                    t1.base,
                       concat_ws('|', collect_set(t1.name)) name
                   from
                       (select
                           name,
                           concat(constellation, "," , blood_type) base
                       from
                           person_info) t1
                   group by
                       t1.base;

列轉行

所需函數(shù):

EXPLODE(col):將hive一列中復雜的array或者map結構拆分成多行。

LATERAL VIEW

用法:LATERAL VIEW udtf(expression) tableAlias AS columnAlias

解釋:用于和split, explode等UDTF一起使用,它能夠?qū)⒁涣袛?shù)據(jù)拆成多行數(shù)據(jù),在此基礎上可以對拆分后的數(shù)據(jù)進行聚合。

數(shù)據(jù)準備:

cd /export/servers/hivedatas

vim movie.txt

文件內(nèi)容如下:  數(shù)據(jù)字段之間使用 進行分割

《疑犯追蹤》 懸疑,動作,科幻,劇情

《Lie to me》 懸疑,警匪,動作,心理,劇情

《戰(zhàn)狼2》 戰(zhàn)爭,動作,災難

需求: 將電影分類中的數(shù)組數(shù)據(jù)展開。結果如下:

《疑犯追蹤》 懸疑

《疑犯追蹤》 動作

《疑犯追蹤》 科幻

《疑犯追蹤》 劇情

《Lie to me》 懸疑

《Lie to me》 警匪

《Lie to me》 動作

《Lie to me》 心理

《Lie to me》 劇情

《戰(zhàn)狼2》 戰(zhàn)爭

《戰(zhàn)狼2》 動作

《戰(zhàn)狼2》 災難

實現(xiàn)步驟:

創(chuàng)建hive表create table movie_info(

movie string,

category array<string>)

row format delimited fields terminated by " "

collection items terminated by ",";

加載數(shù)據(jù)load data local inpath "/export/servers/hivedatas/movie.txt" into table movie_info;

按需求查詢數(shù)據(jù)select

movie,
   category_name

from

movie_info lateral view explode(category) table_tmp as category_name;

reflect函數(shù)

reflect函數(shù)可以支持在sql中調(diào)用java中的自帶函數(shù),秒殺一切udf函數(shù)。

需求1: 使用java.lang.Math當中的Max求兩列中最大值

實現(xiàn)步驟:

創(chuàng)建hive表create table test_udf(col1 int,col2 int) row format delimited fields terminated by ',';

準備數(shù)據(jù)并加載數(shù)據(jù)cd /export/servers/hivedatas

vim test_udf

文件內(nèi)容如下:

1,2

4,3

6,4

7,5

5,6

加載數(shù)據(jù)hive (hive_explode)> load data local inpath '/export/servers/hivedatas/test_udf' overwrite into table test_udf;

使用java.lang.Math當中的Max求兩列當中的最大值hive (hive_explode)> select reflect("java.lang.Math","max",col1,col2) from test_udf;

需求2: 文件中不同的記錄來執(zhí)行不同的java的內(nèi)置函數(shù)

實現(xiàn)步驟:

創(chuàng)建hive表hive (hive_explode)> create table test_udf2(class_name string,method_name string,col1 int , col2 int) row format delimited fields terminated by ',';

準備數(shù)據(jù)cd /export/servers/hivedatas

vim test_udf2

文件內(nèi)容如下:

java.lang.Math,min,1,2

java.lang.Math,max,2,3

加載數(shù)據(jù)hive (hive_explode)> load data local inpath '/export/servers/hivedatas/test_udf2' overwrite into table test_udf2;

執(zhí)行查詢hive (hive_explode)> select reflect(class_name,method_name,col1,col2) from test_udf2;

需求3: 判斷是否為數(shù)字

實現(xiàn)方式:

使用apache commons中的函數(shù),commons下的jar已經(jīng)包含在hadoop的classpath中,所以可以直接使用。

select reflect("org.a(chǎn)pache.commons.lang.math.NumberUtils","isNumber","123")
Hive 窗口函數(shù)

窗口函數(shù)最重要的關鍵字是 partition by 和 order by

具體語法如下:XXX over (partition by xxx order by xxx)

特別注意:over()里面的 partition by 和 order by 都不是必選的,over()里面可以只有partition by,也可以只有order by,也可以兩個都沒有,大家需根據(jù)需求靈活運用。

窗口函數(shù)我劃分了幾個大類,我們一類一類的講解。

1. SUM、AVG、MIN、MAX

講解這幾個窗口函數(shù)前,先創(chuàng)建一個表,以實際例子講解大家更容易理解。

首先創(chuàng)建用戶訪問頁面表:user_pv

create table user_pv(
cookieid string,  -- 用戶登錄的cookie,即用戶標識
createtime string, -- 日期
pv int -- 頁面訪問量
);

給上面這個表加上如下數(shù)據(jù):

cookie1,2021-05-10,1

cookie1,2021-05-11,5

cookie1,2021-05-12,7

cookie1,2021-05-13,3

cookie1,2021-05-14,2

cookie1,2021-05-15,4

cookie1,2021-05-16,4

SUM()使用

執(zhí)行如下查詢語句:

select cookieid,createtime,pv,

sum(pv) over(partition by cookieid order by createtime) as pv1

from user_pv;

結果如下:(因命令行原因,下圖字段名和值是錯位的,請注意辨別!)

執(zhí)行如下查詢語句:

select cookieid,createtime,pv,

sum(pv) over(partition by cookieid ) as pv1

from user_pv;

結果如下:

第一條SQL的over()里面加 order by ,第二條SQL沒加order by ,結果差別很大

所以要注意了:

over()里面加 order by 表示:分組內(nèi)從起點到當前行的pv累積,如,11號的pv1=10號的pv+11號的pv, 12號=10號+11號+12號;

over()里面不加 order by 表示:將分組內(nèi)所有值累加。

AVG,MIN,MAX,和SUM用法一樣,這里就不展開講了,但是要注意 AVG,MIN,MAX 的over()里面加不加 order by 也和SUM一樣,如 AVG 求平均值,如果加上 order by,表示分組內(nèi)從起點到當前行的平局值,不是全部的平局值。MIN,MAX 同理。

2. ROW_NUMBER、RANK、DENSE_RANK、NTILE

還是用上述的用戶登錄日志表:user_pv,里面的數(shù)據(jù)換成如下所示:

cookie1,2021-05-10,1

cookie1,2021-05-11,5
cookie1,2021-05-12,7
cookie1,2021-05-13,3
cookie1,2021-05-14,2
cookie1,2021-05-15,4
cookie1,2021-05-16,4
cookie2,2021-05-10,2
cookie2,2021-05-11,3
cookie2,2021-05-12,5
cookie2,2021-05-13,6
cookie2,2021-05-14,3
cookie2,2021-05-15,9
cookie2,2021-05-16,7
ROW_NUMBER()使用:

ROW_NUMBER()從1開始,按照順序,生成分組內(nèi)記錄的序列。

SELECT
cookieid,
createtime,
pv,
ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY pv desc) AS rn
FROM user_pv;

結果如下:

RANK 和 DENSE_RANK 使用:

RANK() 生成數(shù)據(jù)項在分組中的排名,排名相等會在名次中留下空位。

DENSE_RANK()生成數(shù)據(jù)項在分組中的排名,排名相等會在名次中不會留下空位。

SELECT
cookieid,
createtime,
pv,
RANK() OVER(PARTITION BY cookieid ORDER BY pv desc) AS rn1,
DENSE_RANK() OVER(PARTITION BY cookieid ORDER BY pv desc) AS rn2,
ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY pv DESC) AS rn3
FROM user_pv
WHERE cookieid = 'cookie1';

結果如下:

NTILE的使用:

有時會有這樣的需求:如果數(shù)據(jù)排序后分為三部分,業(yè)務人員只關心其中的一部分,如何將這中間的三分之一數(shù)據(jù)拿出來呢?NTILE函數(shù)即可以滿足。

ntile可以看成是:把有序的數(shù)據(jù)集合平均分配到指定的數(shù)量(num)個桶中, 將桶號分配給每一行。如果不能平均分配,則優(yōu)先分配較小編號的桶,并且各個桶中能放的行數(shù)最多相差1。

然后可以根據(jù)桶號,選取前或后 n分之幾的數(shù)據(jù)。數(shù)據(jù)會完整展示出來,只是給相應的數(shù)據(jù)打標簽;具體要取幾分之幾的數(shù)據(jù),需要再嵌套一層根據(jù)標簽取出。

SELECT

cookieid,

createtime,

pv,

NTILE(2) OVER(PARTITION BY cookieid ORDER BY createtime) AS rn1,

NTILE(3) OVER(PARTITION BY cookieid ORDER BY createtime) AS rn2,

NTILE(4) OVER(ORDER BY createtime) AS rn3

FROM user_pv

ORDER BY cookieid,createtime;

結果如下:

3. LAG、LEAD、FIRST_VALUE、LAST_VALUE

講解這幾個窗口函數(shù)時還是以實例講解,首先創(chuàng)建用戶訪問頁面表:user_url

CREATE TABLE user_url (
cookieid string,
createtime string,  --頁面訪問時間
url string       --被訪問頁面
);

表中加入如下數(shù)據(jù):

cookie1,2021-06-10 10:00:02,url2

cookie1,2021-06-10 10:00:00,url1

cookie1,2021-06-10 10:03:04,1url3

cookie1,2021-06-10 10:50:05,url6

cookie1,2021-06-10 11:00:00,url7

cookie1,2021-06-10 10:10:00,url4

cookie1,2021-06-10 10:50:01,url5

cookie2,2021-06-10 10:00:02,url22

cookie2,2021-06-10 10:00:00,url11

cookie2,2021-06-10 10:03:04,1url33

cookie2,2021-06-10 10:50:05,url66

cookie2,2021-06-10 11:00:00,url77

cookie2,2021-06-10 10:10:00,url44

cookie2,2021-06-10 10:50:01,url55

LAG的使用:

LAG(col,n,DEFAULT) 用于統(tǒng)計窗口內(nèi)往上第n行值。

第一個參數(shù)為列名,第二個參數(shù)為往上第n行(可選,默認為1),第三個參數(shù)為默認值(當往上第n行為NULL時候,取默認值,如不指定,則為NULL)

SELECT cookieid,

createtime,

url,

ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY createtime) AS rn,

LAG(createtime,1,'1970-01-01 00:00:00') OVER(PARTITION BY cookieid ORDER BY createtime) AS last_1

time,

LAG(createtime,2) OVER(PARTITION BY cookieid ORDER BY createtime) AS last_2_time

FROM user_url;

結果如下:

解釋:

last_1_time: 指定了往上第1行的值,default為'1970-01-01 00:00:00'  
                cookie1第一行,往上1行為NULL,因此取默認值 1970-01-01 00:00:00
                cookie1第三行,往上1行值為第二行值,2021-06-10 10:00:02
                cookie1第六行,往上1行值為第五行值,2021-06-10 10:50:01

last_2_time: 指定了往上第2行的值,為指定默認值
      cookie1第一行,往上2行為NULL
      cookie1第二行,往上2行為NULL
      cookie1第四行,往上2行為第二行值,2021-06-10 10:00:02
      cookie1第七行,往上2行為第五行值,2021-06-10 10:50:01

LEAD的使用:

與LAG相反

LEAD(col,n,DEFAULT) 用于統(tǒng)計窗口內(nèi)往下第n行值。

第一個參數(shù)為列名,第二個參數(shù)為往下第n行(可選,默認為1),第三個參數(shù)為默認值(當往下第n行為NULL時候,取默認值,如不指定,則為NULL)

SELECT cookieid,

createtime,

url,

ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY createtime) AS rn,

LEAD(createtime,1,'1970-01-01 00:00:00') OVER(PARTITION BY cookieid ORDER BY createtime) AS next__time,

LEAD(createtime,2) OVER(PARTITION BY cookieid ORDER BY createtime) AS next_2_time

FROM user_url;

結果如下:

FIRST_VALUE的使用:

取分組內(nèi)排序后,截止到當前行,第一個值。

SELECT cookieid,

createtime,

url,

ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY createtime) AS rn,

FIRST_VALUE(url) OVER(PARTITION BY cookieid ORDER BY createtime) AS first1

FROM user_url;

結果如下:

LAST_VALUE的使用:

取分組內(nèi)排序后,截止到當前行,最后一個值。

SELECT cookieid,

createtime,

url,

ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY createtime) AS rn,

LAST_VALUE(url) OVER(PARTITION BY cookieid ORDER BY createtime) AS last1

FROM user_url;

結果如下:

如果想要取分組內(nèi)排序后最后一個值,則需要變通一下:

SELECT cookieid,

createtime,

url,

ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY createtime) AS rn,

LAST_VALUE(url) OVER(PARTITION BY cookieid ORDER BY createtime) AS last1,

FIRST_VALUE(url) OVER(PARTITION BY cookieid ORDER BY createtime DESC) AS last2

FROM user_url

ORDER BY cookieid,createtime;

注意上述SQL,使用的是 FIRST_VALUE 的倒序取出分組內(nèi)排序最后一個值!

結果如下:

此處要特別注意order  by

如果不指定ORDER BY,則進行排序混亂,會出現(xiàn)錯誤的結果

SELECT cookieid,

createtime,

url,

FIRST_VALUE(url) OVER(PARTITION BY cookieid) AS first2  

FROM user_url;

結果如下:

上述 url2 和 url55 的createtime即不屬于最靠前的時間也不屬于最靠后的時間,所以結果是混亂的。

4. CUME_DIST

先創(chuàng)建一張員工薪水表:staff_salary

CREATE EXTERNAL TABLE staff_salary (

dept string,

userid string,

sal int

);

表中加入如下數(shù)據(jù):

d1,user1,1000

d1,user2,2000

d1,user3,3000

d2,user4,4000

d2,user5,5000

CUME_DIST的使用:

此函數(shù)的結果和order by的排序順序有關系。

CUME_DIST:小于等于當前值的行數(shù)/分組內(nèi)總行數(shù)。order默認順序:正序

比如,統(tǒng)計小于等于當前薪水的人數(shù),所占總人數(shù)的比例。

SELECT

dept,

userid,

sal,

CUME_DIST() OVER(ORDER BY sal) AS rn1,

CUME_DIST() OVER(PARTITION BY dept ORDER BY sal) AS rn2

FROM staff_salary;

結果如下:

解釋:

rn1: 沒有partition,所有數(shù)據(jù)均為1組,總行數(shù)為5,

第一行:小于等于1000的行數(shù)為1,因此,1/5=0.2

第三行:小于等于3000的行數(shù)為3,因此,3/5=0.6

rn2: 按照部門分組,dpet=d1的行數(shù)為3

第二行:小于等于2000的行數(shù)為2,因此,2/3=0.6666666666666666

5. GROUPING SETS、GROUPING__ID、CUBE、ROLLUP

這幾個分析函數(shù)通常用于OLAP中,不能累加,而且需要根據(jù)不同維度上鉆和下鉆的指標統(tǒng)計,比如,分小時、天、月的UV數(shù)。

還是先創(chuàng)建一個用戶訪問表:user_date

CREATE TABLE user_date (
month STRING,
day STRING,
cookieid STRING
);

表中加入如下數(shù)據(jù):

2021-03,2021-03-10,cookie1
2021-03,2021-03-10,cookie5
2021-03,2021-03-12,cookie7
2021-04,2021-04-12,cookie3
2021-04,2021-04-13,cookie2
2021-04,2021-04-13,cookie4
2021-04,2021-04-16,cookie4
2021-03,2021-03-10,cookie2
2021-03,2021-03-10,cookie3
2021-04,2021-04-12,cookie5
2021-04,2021-04-13,cookie6
2021-04,2021-04-15,cookie3
2021-04,2021-04-15,cookie2
2021-04,2021-04-16,cookie1
GROUPING SETS的使用:

grouping sets是一種將多個group by 邏輯寫在一個sql語句中的便利寫法。

等價于將不同維度的GROUP BY結果集進行UNION ALL。

SELECT
month,
day,
COUNT(DISTINCT cookieid) AS uv,
GROUPING__ID
FROM user_date
GROUP BY month,day
GROUPING SETS (month,day)
ORDER BY GROUPING__ID;

注:上述SQL中的GROUPING__ID,是個關鍵字,表示結果屬于哪一個分組集合,根據(jù)grouping sets中的分組條件month,day,1是代表month,2是代表day。

結果如下:

上述SQL等價于:

SELECT month,
NULL as day,
COUNT(DISTINCT cookieid) AS uv,
1 AS GROUPING__ID
FROM user_date
GROUP BY month
UNION ALL
SELECT NULL as month,
day,
COUNT(DISTINCT cookieid) AS uv,
2 AS GROUPING__ID
FROM user_date
GROUP BY day;
CUBE的使用:

根據(jù)GROUP BY的維度的所有組合進行聚合。

SELECT
month,
day,
COUNT(DISTINCT cookieid) AS uv,
GROUPING__ID
FROM user_date
GROUP BY month,day
WITH CUBE
ORDER BY GROUPING__ID;

結果如下:

上述SQL等價于:

SELECT NULL,NULL,COUNT(DISTINCT cookieid) AS uv,0 AS GROUPING__ID FROM user_date
UNION ALL
SELECT month,NULL,COUNT(DISTINCT cookieid) AS uv,1 AS GROUPING__ID FROM user_date GROUP BY month
UNION ALL
SELECT NULL,day,COUNT(DISTINCT cookieid) AS uv,2 AS GROUPING__ID FROM user_date GROUP BY day
UNION ALL
SELECT month,day,COUNT(DISTINCT cookieid) AS uv,3 AS GROUPING__ID FROM user_date GROUP BY month,day;
ROLLUP的使用:

是CUBE的子集,以最左側的維度為主,從該維度進行層級聚合。

比如,以month維度進行層級聚合:

SELECT
month,
day,
COUNT(DISTINCT cookieid) AS uv,
GROUPING__ID  
FROM user_date
GROUP BY month,day
WITH ROLLUP
ORDER BY GROUPING__ID;

結果如下:

把month和day調(diào)換順序,則以day維度進行層級聚合:

SELECT
day,
month,
COUNT(DISTINCT cookieid) AS uv,
GROUPING__ID  
FROM user_date
GROUP BY day,month
WITH ROLLUP
ORDER BY GROUPING__ID;

結果如下:

這里,根據(jù)日和月進行聚合,和根據(jù)日聚合結果一樣,因為有父子關系,如果是其他維度組合的話,就會不一樣。

聲明: 本文由入駐維科號的作者撰寫,觀點僅代表作者本人,不代表OFweek立場。如有侵權或其他問題,請聯(lián)系舉報。

發(fā)表評論

0條評論,0人參與

請輸入評論內(nèi)容...

請輸入評論/評論長度6~500個字

您提交的評論過于頻繁,請輸入驗證碼繼續(xù)

暫無評論

暫無評論

    掃碼關注公眾號
    OFweek人工智能網(wǎng)
    獲取更多精彩內(nèi)容
    文章糾錯
    x
    *文字標題:
    *糾錯內(nèi)容:
    聯(lián)系郵箱:
    *驗 證 碼:

    粵公網(wǎng)安備 44030502002758號