第一章、Hive參數配置
1.1 CLIs and Commands客戶端和命令
Hive CLI
$HIVE_HOME/bin/hive是一個shellUtil,通常稱之爲hive的第一代客戶端或者舊客戶端,主要功能有兩個:
- 一:用於以交互式或批處理模式運行Hive查詢,注意,此時作爲客戶端,需要並且能夠訪問的是Hive metastore服務,而不是hiveserver2服務。
- 二:用於hive相關服務的啓動,比如metastore服務。
可以通過運行"hive -H" 或者 "hive --help"來查看命令行選項。
Batch Mode 批處理模式
當使用-e或-f選項運行$ HIVE_HOME / bin / hive時,它將以批處理模式執行SQL命令。所謂的批處理可以理解爲一次性執行,執行完畢退出。
#-e $HIVE_HOME/bin/hive -e 'show databases' #-f cd ~ #編輯一個sql文件 裏面寫上合法正確的sql語句 vim hive.sql show databases; #執行 從客戶端所在機器的本地磁盤加載文件 $HIVE_HOME/bin/hive -f /root/hive.sql #也可以從其他文件系統加載sql文件執行 $HIVE_HOME/bin/hive -f hdfs://<namenode>:<port>/hive-script.sql $HIVE_HOME/bin/hive -f s3://mys3bucket/s3-script.sql #使用靜默模式將數據從查詢中轉儲到文件中 $HIVE_HOME/bin/hive -S -e 'select * from itheima.student' > a.txt
Interactive Shell 交互式模式
所謂交互式模式可以理解爲客戶端和hive服務一直保持連接,除非手動退出客戶端。
/export/server/hive/bin/hive hive> show databases; OK default itcast itheima Time taken: 0.028 seconds, Fetched: 3 row(s) hive> use itcast; OK Time taken: 0.027 seconds hive> exit;
啓動服務、修改配置
遠程模式部署方式下,hive metastore服務需要單獨配置手動啓動,此時就可以使用Hive CLI來進行相關服務的啓動,hiveserver2服務類似。
#--service $HIVE_HOME/bin/hive --service metastore $HIVE_HOME/bin/hive --service hiveserver2 #--hiveconf $HIVE_HOME/bin/hive --hiveconf hive.root.logger=DEBUG,console
Beeline CLI
$HIVE_HOME/bin/beeline被稱之爲第二代客戶端或者新客戶端,是一個JDBC客戶端,是官方強烈推薦使用的Hive命令行工具,和第一代客戶端相比,性能加強安全性提高。Beeline在嵌入式模式和遠程模式下均可工作。
在嵌入式模式下,它運行嵌入式Hive(類似於Hive CLI);
遠程模式下beeline通過Thrift連接到單獨的HiveServer2服務上,這也是官方推薦在生產環境中使用的模式。
常見的使用方式如下所示,在啓動hiveserver2服務的前提下使用beeline遠程連接:
[root@node3 ~]# /export/server/hive/bin/beeline Beeline version 3.1.2 by Apache Hive beeline> ! connect jdbc:hive2://node1:10000 Connecting to jdbc:hive2://node1:10000 Enter username for jdbc:hive2://node1:10000: root Enter password for jdbc:hive2://node1:10000: Connected to: Apache Hive (version 3.1.2) Driver: Hive JDBC (version 3.1.2) Transaction isolation: TRANSACTION_REPEATABLE_READ 0: jdbc:hive2://node1:10000>
beeline支持的參數非常多,可以通過官方文檔進行查詢
https://cwiki.apache.org/confluence/display/Hive/HiveServer2+Clients#HiveServer2Clients-Beeline%E2%80%93NewCommandLineShell
1.2 Configuration Properties配置屬性
配置屬性概述
Hive作爲一款複雜的數據倉庫軟件,除了一些默認的屬性行爲之外,還支持用戶配置屬性進行修改,使得在某些場景下滿足用戶的需求。
作爲用戶我們需要掌握兩件事:
- 一是:Hive有哪些屬性支持修改,修改了有什麼功能;
- 二是:Hive支持哪種方式進行修改,修改是臨時生效還是永久生效的。
Hive配置屬性的規範列表是在HiveConf.Java類中管理的,因此請參考該HiveConf.java文件,以獲取Hive當前使用的發行版中可用的配置屬性的完整列表。從Hive 0.14.0開始,會從HiveConf.java類中直接生成配置模板文件hive-default.xml.template,它是當前版本配置及其默認值的可靠來源。
詳細的配置參數大全可以參考Hive官網配置參數,在頁面使用ctrl+f進行搜索。
https://cwiki.apache.org/confluence/display/Hive/Configuration+Properties
修改配置屬性方式
方式1:hive-site.xml配置文件
在$HIVE_HOME/conf路徑下,可以添加一個hive-site.xml文件,把需要定義修改的配置屬性添加進去,這個配置文件會影響到這個Hive安裝包的任何一種服務啓動、客戶端使用方式,可以理解爲是Hive的全局配置。
比如我們指定使用MySQL作爲Hive元數據的存儲介質,那麼就需要把Hive連接MySQL的相關屬性配置在hive-site.xml文件中,這樣不管是本地模式還是遠程模式啓動,不管客戶端本地連接還是遠程連接,都將訪問同一個元數據存儲介質,大家使用的元數據都是一致的。
<configuration>
<!-- 存儲元數據mysql相關配置 --> <property> <name>javax.jdo.option.ConnectionURL</name> <value> jdbc:mysql://node1:3306/hive?createDatabaseIfNotExist=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8</value> </property> <property> <name>javax.jdo.option.ConnectionDriverName</name> <value>com.mysql.jdbc.Driver</value> </property> <property> <name>javax.jdo.option.ConnectionUserName</name> <value>root</value> </property> <property> <name>javax.jdo.option.ConnectionPassword</name> <value>hadoop</value> </property> </configuration>
方式2:hiveconf命令行參數
hiveconf是一個命令行的參數,用於在使用Hive CLI或者Beeline CLI的時候指定配置參數。這種方式的配置在整個的會話session中有效,會話結束,失效。
比如在啓動hive服務的時候,爲了更好的查看啓動詳情,可以通過hiveconf參數修改日誌級別:
$HIVE_HOME/bin/hive --hiveconf hive.root.logger=DEBUG,consol
方式3:set命令
在Hive CLI或Beeline中使用set命令爲set命令之後的所有SQL語句設置配置參數,這個也是會話級別的。
這種方式也是用戶日常開發中使用最多的一種配置參數方式。因爲Hive倡導一種:誰需要、誰配置、誰使用的一種思想,避免你的屬性修改影響其他用戶的修改。
#啓用hive動態分區,需要在hive會話中設置兩個參數: set hive.exec.dynamic.partition=true; set hive.exec.dynamic.partition.mode=nonstrict;
方式4:服務器特定的配置文件
您可以設置特定metastore的配置值hivemetastore-site.xml中,並在HiveServer2特定的配置值hiveserver2-site.xml中。
Hive Metastore服務器讀取$ HIVE_CONF_DIR或類路徑中可用的hive-site.xml以及hivemetastore-site.xml配置文件。
HiveServer2讀取$ HIVE_CONF_DIR或類路徑中可用的hive-site.xml以及hiveserver2-site.xml。
如果HiveServer2以嵌入式模式使用元存儲,則還將加載hivemetastore-site.xml。
概況總結
配置文件的優先順序如下,後面的優先級越高:
hive-site.xml-> hivemetastore-site.xml-> hiveserver2-site.xml->' -hiveconf'命令行參數
從Hive 0.14.0開始,會從HiveConf.java類中直接生成配置模板文件hive-default.xml.template,它是當前版本配置變量及其默認值的可靠來源。
hive-default.xml.template 位於安裝根目錄下的conf目錄中,並且 hive-site.xml 也應在同一目錄中創建。
從 Hive 0.14.0開始, 您可以使用SHOW CONF命令顯示有關配置變量的信息。
配置方式的優先級順序,優先級依次遞增:
set參數生命>hiveconf命令行參數>hive-site.xml配置文件。
即set參數聲明覆蓋命令行參數hiveconf,命令行參數覆蓋配置文件hive-site.xml設定。
日常的開發使用中,如果不是核心的需要全局修改的參數屬性,建議大家使用set命令進行設置。
另外,Hive也會讀入Hadoop的配置,因爲Hive是作爲Hadoop的客戶端啓動的,Hive的配置會覆蓋Hadoop的配置。
第二章、Hive內置運算符
隨着Hive版本的不斷髮展,在Hive SQL中支持的、內置的運算符也越來越多。可以使用下面的命令查看當下支持的運算符和函數,並且查看其詳細的使用方式。
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
也可以使用課程附件中的中文版本運算符函數說明文檔進行查看。
--顯示所有的函數和運算符 show functions; --查看運算符或者函數的使用說明 describe function +; --使用extended 可以查看更加詳細的使用說明 describe function extended +;
從Hive 0.13.0開始,select查詢語句FROM關鍵字是可選的(例如SELECT 1+1)。因此可以使用這種方式來練習測試內置的運算符、函數的功能。
除此之外,還可以通過創建一張虛表dual來滿足於測試需求。
--1、創建表dual create table dual(id string); --2、加載一個文件dual.txt到dual表中 --dual.txt只有一行內容:內容爲一個空格 --3、在select查詢語句中使用dual表完成運算符、函數功能測試 select 1+1 from dual;
2.1 關係運算符
關係運算符是二元運算符,執行的是兩個操作數的比較運算。每個關係運算符都返回boolean類型結果(TRUE或FALSE)。
•等值比較: = 、==
•不等值比較: <> 、!=
•小於比較: <
•小於等於比較: <=
•大於比較: >
•大於等於比較: >=
•空值判斷: IS NULL
•非空判斷: IS NOT NULL
•LIKE比較: LIKE
•JAVA的LIKE操作: RLIKE
•REGEXP操作: REGEXP
--is null空值判斷 select 1 from dual where 'itcast' is null; --is not null 非空值判斷 select 1 from dual where 'itcast' is not null; --like比較: _表示任意單個字符 %表示任意數量字符 --否定比較: NOT A like B select 1 from dual where 'itcast' like 'it_'; select 1 from dual where 'itcast' like 'it%'; select 1 from dual where not 'itcast' like 'hadoo_'; --rlike:確定字符串是否匹配正則表達式,是REGEXP_LIKE()的同義詞。 select 1 from dual where 'itcast' rlike '^i.*t$'; select 1 from dual where '123456' rlike '^\\d+$'; --判斷是否全爲數字 select 1 from dual where '123456aa' rlike '^\\d+$'; --regexp:功能與rlike相同 用於判斷字符串是否匹配正則表達式 select 1 from dual where 'itcast' regexp '^i.*t$';
2.2 算術運算符
算術運算符操作數必須是數值類型。 分爲一元運算符和二元運算符; 一元運算符,只有一個操作數; 二元運算符有兩個操作數,運算符在兩個操作數之間。
•加法操作: +
•減法操作: -
•乘法操作: *
•除法操作: /
•取整操作: div
•取餘操作: %
•位與操作: &
•位或操作: |
•位異或操作: ^
•位取反操作: ~
--is null空值判斷 select 1 from dual where 'itcast' is null; --is not null 非空值判斷 select 1 from dual where 'itcast' is not null; --like比較: _表示任意單個字符 %表示任意數量字符 --否定比較: NOT A like B select 1 from dual where 'itcast' like 'it_'; select 1 from dual where 'itcast' like 'it%'; select 1 from dual where not 'itcast' like 'hadoo_'; --rlike:確定字符串是否匹配正則表達式,是REGEXP_LIKE()的同義詞。 select 1 from dual where 'itcast' rlike '^i.*t$'; select 1 from dual where '123456' rlike '^\\d+$'; --判斷是否全爲數字 select 1 from dual where '123456aa' rlike '^\\d+$'; --regexp:功能與rlike相同 用於判斷字符串是否匹配正則表達式 select 1 from dual where 'itcast' regexp '^i.*t$';
2.3 邏輯運算符
•與操作: A AND B
•或操作: A OR B
•非操作: NOT A 、!A
•在:A IN (val1, val2, ...)
•不在:A NOT IN (val1, val2, ...)
•邏輯是否存在: [NOT] EXISTS (subquery)
--與操作: A AND B 如果A和B均爲TRUE,則爲TRUE,否則爲FALSE。如果A或B爲NULL,則爲NULL。 select 1 from dual where 3>1 and 2>1; --或操作: A OR B 如果A或B或兩者均爲TRUE,則爲TRUE,否則爲FALSE。 select 1 from dual where 3>1 or 2!=2; --非操作: NOT A 、!A 如果A爲FALSE,則爲TRUE;如果A爲NULL,則爲NULL。否則爲FALSE。 select 1 from dual where not 2>1; select 1 from dual where !2=1; --在:A IN (val1, val2, ...) 如果A等於任何值,則爲TRUE。 select 1 from dual where 11 in(11,22,33); --不在:A NOT IN (val1, val2, ...) 如果A不等於任何值,則爲TRUE select 1 from dual where 11 not in(22,33,44); --邏輯是否存在: [NOT] EXISTS (subquery) 如果子查詢返回至少一行,則爲TRUE。 select A.* from A where exists (select B.id from B where A.id = B.id)
第三章、Hive函數入門
3.1 函數概述
如同RDBMS中標準SQL語法一樣,Hive SQL也內建了不少函數,滿足於用戶在不同場合下的數據分析需求,提高開發SQL數據分析的效率。
可以使用show functions查看當下版本支持的函數,並且可以通過describe function extended funcname來查看函數的使用方式和方法。
3.2 函數分類
Hive的函數很多,除了自己內置所支持的函數之外,還支持用戶自己定義開發函數。
針對內置的函數,可以根據函數的應用類型進行歸納分類,比如:數值類型函數、日期類型函數、字符串類型函數、集合函數、條件函數等;
針對用戶自定義函數,可以根據函數的輸入輸出行數進行分類,比如:UDF、UDAF、UDTF。
內置函數分類
所謂的內置函數(buildin)指的是Hive開發實現好,直接可以使用的函數,也叫做內建函數。
官方文檔地址:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
內置函數根據應用歸類整體可以分爲以下8大種類型,我們將對其中重要的,使用頻率高的函數使用進行詳細講解。
String Functions 字符串函數
主要針對字符串數據類型進行操作,比如下面這些:
•字符串長度函數:length
•字符串反轉函數:reverse
•字符串連接函數:concat
•帶分隔符字符串連接函數:concat_ws
•字符串截取函數:substr,substring
•字符串轉大寫函數:upper,ucase
•字符串轉小寫函數:lower,lcase
•去空格函數:trim
•左邊去空格函數:ltrim
•右邊去空格函數:rtrim
•正則表達式替換函數:regexp_replace
•正則表達式解析函數:regexp_extract
•URL解析函數:parse_url
•json解析函數:get_json_object
•空格字符串函數:space
•重複字符串函數:repeat
•首字符ascii函數:ascii
•左補足函數:lpad
•右補足函數:rpad
•分割字符串函數: split
•集合查找函數: find_in_set
------------String Functions 字符串函數------------ describe function extended find_in_set; --字符串長度函數:length(str | binary) select length("angelababy"); --字符串反轉函數:reverse select reverse("angelababy"); --字符串連接函數:concat(str1, str2, ... strN) select concat("angela","baby"); --帶分隔符字符串連接函數:concat_ws(separator, [string | array(string)]+) select concat_ws('.', 'www', array('itcast', 'cn')); --字符串截取函數:substr(str, pos[, len]) 或者 substring(str, pos[, len]) select substr("angelababy",-2); --pos是從1開始的索引,如果爲負數則倒着數 select substr("angelababy",2,2); --字符串轉大寫函數:upper,ucase select upper("angelababy"); select ucase("angelababy"); --字符串轉小寫函數:lower,lcase select lower("ANGELABABY"); select lcase("ANGELABABY"); --去空格函數:trim 去除左右兩邊的空格 select trim(" angelababy "); --左邊去空格函數:ltrim select ltrim(" angelababy "); --右邊去空格函數:rtrim select rtrim(" angelababy "); --正則表達式替換函數:regexp_replace(str, regexp, rep) select regexp_replace('100-200', '(\\d+)', 'num'); --正則表達式解析函數:regexp_extract(str, regexp[, idx]) 提取正則匹配到的指定組內容 select regexp_extract('100-200', '(\\d+)-(\\d+)', 2); --URL解析函數:parse_url 注意要想一次解析出多個 可以使用parse_url_tuple這個UDTF函數 select parse_url('http://www.itcast.cn/path/p1.php?query=1', 'HOST'); --json解析函數:get_json_object --空格字符串函數:space(n) 返回指定個數空格 select space(4); --重複字符串函數:repeat(str, n) 重複str字符串n次 select repeat("angela",2); --首字符ascii函數:ascii select ascii("angela"); --a對應ASCII 97 --左補足函數:lpad select lpad('hi', 5, '??'); --???hi select lpad('hi', 1, '??'); --h --右補足函數:rpad select rpad('hi', 5, '??'); --分割字符串函數: split(str, regex) select split('apache hive', '\\s+'); --集合查找函數: find_in_set(str,str_array) select find_in_set('a','abc,b,ab,c,def');
Date Functions 日期函數
主要針對時間、日期數據類型進行操作,比如下面這些:
•獲取當前日期: current_date
•獲取當前時間戳: current_timestamp
•UNIX時間戳轉日期函數: from_unixtime
•獲取當前UNIX時間戳函數: unix_timestamp
•日期轉UNIX時間戳函數: unix_timestamp
•指定格式日期轉UNIX時間戳函數: unix_timestamp
•抽取日期函數: to_date
•日期轉年函數: year
•日期轉月函數: month
•日期轉天函數: day
•日期轉小時函數: hour
•日期轉分鐘函數: minute
•日期轉秒函數: second
•日期轉周函數: weekofyear
•日期比較函數: datediff
•日期增加函數: date_add
•日期減少函數: date_sub
--獲取當前日期: current_date select current_date(); --獲取當前時間戳: current_timestamp --同一查詢中對current_timestamp的所有調用均返回相同的值。 select current_timestamp(); --獲取當前UNIX時間戳函數: unix_timestamp select unix_timestamp(); --UNIX時間戳轉日期函數: from_unixtime select from_unixtime(1618238391); select from_unixtime(0, 'yyyy-MM-dd HH:mm:ss'); --日期轉UNIX時間戳函數: unix_timestamp select unix_timestamp("2011-12-07 13:01:03"); --指定格式日期轉UNIX時間戳函數: unix_timestamp select unix_timestamp('20111207 13:01:03','yyyyMMdd HH:mm:ss'); --抽取日期函數: to_date select to_date('2009-07-30 04:17:52'); --日期轉年函數: year select year('2009-07-30 04:17:52'); --日期轉月函數: month select month('2009-07-30 04:17:52'); --日期轉天函數: day select day('2009-07-30 04:17:52'); --日期轉小時函數: hour select hour('2009-07-30 04:17:52'); --日期轉分鐘函數: minute select minute('2009-07-30 04:17:52'); --日期轉秒函數: second select second('2009-07-30 04:17:52'); --日期轉周函數: weekofyear 返回指定日期所示年份第幾周 select weekofyear('2009-07-30 04:17:52'); --日期比較函數: datediff 日期格式要求'yyyy-MM-dd HH:mm:ss' or 'yyyy-MM-dd' select datediff('2012-12-08','2012-05-09'); --日期增加函數: date_add select date_add('2012-02-28',10); --日期減少函數: date_sub select date_sub('2012-01-1',10);
Mathematical Functions 數學函數
主要針對數值類型的數據進行數學計算,比如下面這些:
•取整函數: round
•指定精度取整函數: round
•向下取整函數: floor
•向上取整函數: ceil
•取隨機數函數: rand
•二進制函數: bin
•進制轉換函數: conv
•絕對值函數: abs
--取整函數: round 返回double類型的整數值部分 (遵循四捨五入) select round(3.1415926); --指定精度取整函數: round(double a, int d) 返回指定精度d的double類型 select round(3.1415926,4); --向下取整函數: floor select floor(3.1415926); select floor(-3.1415926); --向上取整函數: ceil select ceil(3.1415926); select ceil(-3.1415926); --取隨機數函數: rand 每次執行都不一樣 返回一個0到1範圍內的隨機數 select rand(); --指定種子取隨機數函數: rand(int seed) 得到一個穩定的隨機數序列 select rand(2); --二進制函數: bin(BIGINT a) select bin(18); --進制轉換函數: conv(BIGINT num, int from_base, int to_base) select conv(17,10,16); --絕對值函數: abs select abs(-3.9);
Collection Functions 集合函數
主要針對集合這樣的複雜數據類型進行操作,比如下面這些:
•集合元素size函數: size(Map<K.V>) size(Array<T>)
•取map集合keys函數: map_keys(Map<K.V>)
•取map集合values函數: map_values(Map<K.V>)
•判斷數組是否包含指定元素: array_contains(Array<T>, value)
•數組排序函數:sort_array(Array<T>)
--集合元素size函數: size(Map<K.V>) size(Array<T>) select size(`array`(11,22,33)); select size(`map`("id",10086,"name","zhangsan","age",18)); --取map集合keys函數: map_keys(Map<K.V>) select map_keys(`map`("id",10086,"name","zhangsan","age",18)); --取map集合values函數: map_values(Map<K.V>) select map_values(`map`("id",10086,"name","zhangsan","age",18)); --判斷數組是否包含指定元素: array_contains(Array<T>, value) select array_contains(`array`(11,22,33),11); select array_contains(`array`(11,22,33),66); --數組排序函數:sort_array(Array<T>) select sort_array(`array`(12,2,32));
Conditional Functions 條件函數
主要用於條件判斷、邏輯判斷轉換這樣的場合,比如:
•if條件判斷: if(boolean testCondition, T valueTrue, T valueFalseOrNull)
•空判斷函數: isnull( a )
•非空判斷函數: isnotnull ( a )
•空值轉換函數: nvl(T value, T default_value)
•非空查找函數: COALESCE(T v1, T v2, ...)
•條件轉換函數: CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END
•nullif( a, b ): 如果a = b,則返回NULL;否則返回NULL。否則返回一個
•assert_true: 如果'condition'不爲真,則引發異常,否則返回null
--使用之前課程創建好的student表數據 select * from student limit 3; --if條件判斷: if(boolean testCondition, T valueTrue, T valueFalseOrNull) select if(1=2,100,200); select if(sex ='男','M','W') from student limit 3; --空判斷函數: isnull( a ) select isnull("allen"); select isnull(null); --非空判斷函數: isnotnull ( a ) select isnotnull("allen"); select isnotnull(null); --空值轉換函數: nvl(T value, T default_value) select nvl("allen","itcast"); select nvl(null,"itcast"); --非空查找函數: COALESCE(T v1, T v2, ...) --返回參數中的第一個非空值;如果所有值都爲NULL,那麼返回NULL select COALESCE(null,11,22,33); select COALESCE(null,null,null,33); select COALESCE(null,null,null); --條件轉換函數: CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END select case 100 when 50 then 'tom' when 100 then 'mary' else 'tim' end; select case sex when '男' then 'man' else 'women' end from student limit 3; --nullif( a, b ): -- 果a = b,則返回NULL;否則返回NULL。否則返回一個 select nullif(11,11); select nullif(11,12); --assert_true(condition) --如果'condition'不爲真,則引發異常,否則返回null SELECT assert_true(11 >= 0); SELECT assert_true(-1 >= 0);
Type Conversion Functions 類型轉換函數
主要用於顯式的數據類型轉換,有下面兩種函數:
•任意數據類型之間轉換:cast
--任意數據類型之間轉換:cast select cast(12.14 as bigint); select cast(12.14 as string);
Data Masking Functions 數據脫敏函數
主要完成對數據脫敏轉換功能,屏蔽原始數據,主要如下:
•mask
•mask_first_n(string str[, int n]
•mask_last_n(string str[, int n])
•mask_show_first_n(string str[, int n])
•mask_show_last_n(string str[, int n])
•mask_hash(string|char|varchar str)
--mask --將查詢回的數據,大寫字母轉換爲X,小寫字母轉換爲x,數字轉換爲n。 select mask("abc123DEF"); select mask("abc123DEF",'-','.','^'); --自定義替換的字母 --mask_first_n(string str[, int n] --對前n個進行脫敏替換 select mask_first_n("abc123DEF",4); --mask_last_n(string str[, int n]) select mask_last_n("abc123DEF",4); --mask_show_first_n(string str[, int n]) --除了前n個字符,其餘進行掩碼處理 select mask_show_first_n("abc123DEF",4); --mask_show_last_n(string str[, int n]) select mask_show_last_n("abc123DEF",4); --mask_hash(string|char|varchar str) --返回字符串的hash編碼。 select mask_hash("abc123DEF");
Misc. Functions 其他雜項函數
•hive調用java方法: java_method(class, method[, arg1[, arg2..]])
•反射函數: reflect(class, method[, arg1[, arg2..]])
•取哈希值函數:hash
•current_user()、logged_in_user()、current_database()、version()
•SHA-1加密: sha1(string/binary)
•SHA-2家族算法加密:sha2(string/binary, int) (SHA-224, SHA-256, SHA-384, SHA-512)
•crc32加密:
•MD5加密: md5(string/binary)
--hive調用java方法: java_method(class, method[, arg1[, arg2..]]) select java_method("java.lang.Math","max",11,22); --反射函數: reflect(class, method[, arg1[, arg2..]]) select reflect("java.lang.Math","max",11,22); --取哈希值函數:hash select hash("allen"); --current_user()、logged_in_user()、current_database()、version() --SHA-1加密: sha1(string/binary) select sha1("allen"); --SHA-2家族算法加密:sha2(string/binary, int) (SHA-224, SHA-256, SHA-384, SHA-512) select sha2("allen",224); select sha2("allen",512); --crc32加密: select crc32("allen"); --MD5加密: md5(string/binary) select md5("allen");
用戶自定義函數分類
雖然說Hive內置了很多函數,但是不見得一定可以滿足於用戶各種各樣的分析需求場景。爲了解決這個問題,Hive推出來用戶自定義函數功能,讓用戶實現自己希望實現的功能函數。
用戶自定義函數簡稱UDF,源自於英文user-defined function。自定義函數總共有3類,是根據函數輸入輸出的行數來區分的,分別是:
- UDF(User-Defined-Function)普通函數,一進一出
- UDAF(User-Defined Aggregation Function)聚合函數,多進一出
- UDTF(User-Defined Table-Generating Functions)表生成函數,一進多出
UDF分類標準擴大化
雖然說UDF叫做用戶自定義函數,其分類標準主要針對的是用戶編寫開發的函數。
但是這套UDF分類標準可以擴大到Hive的所有函數中:包括內置函數和自定義函數。因爲不管是什麼類型的行數,一定滿足於輸入輸出的要求,那麼從輸入幾行和輸出幾行上來劃分沒有任何毛病。千萬不要被UD(User-Defined)這兩個字母所迷惑,照成視野的狹隘。
比如Hive官方文檔中,針對聚合函數的標準就是內置的UDAF類型。
UDF 普通函數
UDF函數通常把它叫做普通函數,最大的特點是一進一出,也就是輸入一行輸出一行。比如round這樣的取整函數,接收一行數據,輸出的還是一行數據。
UDAF 聚合函數
UDAF函數通常把它叫做聚合函數,A所代表的單詞就是Aggregation聚合的意思。最大的特點是多進一出,也就是輸入多行輸出一行。比如count、sum這樣的函數。
•count:統計檢索到的總行數。
•sum:求和
•avg:求平均
•min:最小值
•max:最大值
•數據收集函數(去重): collect_set(col)
•數據收集函數(不去重): collect_list(col)
select sex from student; select collect_set(sex) from student; select collect_list(sex) from student;
UDTF 表生成函數
UDTF函數通常把它叫做表生成函數,T所代表的單詞是Table-Generating表生成的意思。最大的特點是一進多出,也就是輸入一行輸出多行。
之所以叫做表生成函數,原因在於這類型的函數作用返回的結果類似於表(多行數據嘛),同時,UDTF函數也是我們接觸比較少的函數,陌生。比如explode函數。
3.3 案例:用戶自定義UDF
需求描述
在企業中處理數據的時候,對於敏感數據往往需要進行脫敏處理。比如手機號。我們常見的處理方式是將手機號中間4位進行****處理。
Hive中沒有這樣的函數可以直接實現功能,雖然可以通過各種函數的嵌套調用最終也能實現,但是效率不高,現要求自定義開發實現Hive函數,滿足上述需求。
1、能夠對輸入數據進行非空判斷、位數判斷處理
2、能夠實現校驗手機號格式,把滿足規則的進行****處理
3、對於不符合手機號規則的數據原封不動不處理
實現步驟
通過業務分析,可以發現我們需要實現的函數是一個輸入一行輸出一行的函數,也就是所說的UDF普通函數。
根據Hive當中的UDF開發規範,實現步驟如下:
1、寫一個java類,繼承UDF,並重載evaluate方法;
2、程序打成jar包,上傳服務器添加到hive的classpath;
hive>add JAR /home/hadoop/udf.jar;
3、註冊成爲臨時函數(給UDF命名);
create temporary function 函數名 as 'UDF類全路徑';
4、使用函數
代碼實現
開發環境準備
<dependencies> <dependency> <groupId>org.apache.hive</groupId> <artifactId>hive-exec</artifactId> <version>3.1.2</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> <version>3.1.4</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.2</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <filters> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> </configuration> </execution> </executions> </plugin> </plugins> </build>
業務代碼
package cn.itcast.hive.udf; import org.apache.commons.lang.StringUtils; import org.apache.hadoop.hive.ql.exec.UDF; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @description: hive自定義函數UDF 實現對手機號中間4位進行****加密 * @author: Itcast */ public class EncryptPhoneNumber extends UDF { /** * 重載evaluate方法 實現函數的業務邏輯 * @param phoNum 入參:未加密手機號 * @return 返回:加密後的手機號字符串 */ public String evaluate(String phoNum){ String encryptPhoNum = null; //手機號不爲空 並且爲11位 if (StringUtils.isNotEmpty(phoNum) && phoNum.trim().length() == 11 ) { //判斷數據是否滿足中國大陸手機號碼規範 String regex = "^(1[3-9]\\d{9}$)"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(phoNum); if (m.matches()) {//進入這裏都是符合手機號規則的 //使用正則替換 返回加密後數據 encryptPhoNum = phoNum.trim().replaceAll("()\\d{4}(\\d{4})","$1****$2"); }else{ //不符合手機號規則 數據直接原封不動返回 encryptPhoNum = phoNum; } }else{ //不符合11位 數據直接原封不動返回 encryptPhoNum = phoNum; } return encryptPhoNum; } }
部署實測
打jar包上傳服務器
把jar包上傳到Hiveserver2服務運行所在機器的linux系統,或者HDFS文件系統。
添加至Hive Classpath
在客戶端中使用命令把jar包添加至classpath。
註冊臨時函數
功能效果演示
第四章、Hive函數高階
4.1 UDTF之explode函數
explode語法功能
對於UDTF表生成函數,很多人難以理解什麼叫做輸入一行,輸出多行。
爲什麼叫做表生成?能夠產生表嗎?下面我們就來學習Hive當做內置的一個非常著名的UDTF函數,名字叫做explode函數,中文戲稱之爲“爆炸函數”,可以炸開數據。
explode函數接收map或者array類型的數據作爲參數,然後把參數中的每個元素炸開變成一行數據。一個元素一行。這樣的效果正好滿足於輸入一行輸出多行。
explode函數在關係型數據庫中本身是不該出現的。
因爲他的出現本身就是在操作不滿足第一範式的數據(每個屬性都不可再分)。本身已經違背了數據庫的設計原理,但是在面向分析的數據庫或者數據倉庫中,這些規範可以發生改變。
explode(a) - separates the elements of array a into multiple rows, or the elements of a map into multiple rows and columns
- explode(array)將array列表裏的每個元素生成一行;
- explode(map)將map裏的每一對元素作爲一行,其中key爲一列,value爲一列;
一般情況下,explode函數可以直接使用即可,也可以根據需要結合lateral view側視圖使用。
explode函數的使用
select explode(`array`(11,22,33)) as item; select explode(`map`("id",10086,"name","zhangsan","age",18));
案例:NBA總冠軍球隊名單
業務需求
有一份數據《The_NBA_Championship.txt》,關於部分年份的NBA總冠軍球隊名單:
第一個字段表示的是球隊名稱,第二個字段是獲取總冠軍的年份,字段之間以,分割;
獲取總冠軍年份之間以|進行分割。
需求:使用Hive建表映射成功數據,對數據拆分,要求拆分之後數據如下所示:
並且最好根據年份的倒序進行排序。
代碼實現
--step1:建表 create table the_nba_championship( team_name string, champion_year array<string> ) row format delimited fields terminated by ',' collection items terminated by '|'; --step2:加載數據文件到表中 load data local inpath '/root/hivedata/The_NBA_Championship.txt' into table the_nba_championship; --step3:驗證 select * from the_nba_championship;
下面使用explode函數:
--step4:使用explode函數對champion_year進行拆分 俗稱炸開 select explode(champion_year) from the_nba_championship; select team_name,explode(champion_year) from the_nba_championship;
explode使用限制
在select條件中,如果只有explode函數表達式,程序執行是沒有任何問題的;
但是如果在select條件中,包含explode和其他字段,就會報錯。錯誤信息爲:
org.apache.hadoop.hive.ql.parse.SemanticException:UDTF's are not supported outside the SELECT clause, nor nested in expressions
那麼如何理解這個錯誤呢?爲什麼在select的時候,explode的旁邊不支持其他字段的同時出現?
explode語法限制原因
- explode函數屬於UDTF函數,即表生成函數;
- explode函數執行返回的結果可以理解爲一張虛擬的表,其數據來源於源表;
- 在select中只查詢源表數據沒有問題,只查詢explode生成的虛擬表數據也沒問題
- 但是不能在只查詢源表的時候,既想返回源表字段又想返回explode生成的虛擬表字段
- 通俗點講,有兩張表,不能只查詢一張表但是返回分別屬於兩張表的字段;
- 從SQL層面上來說應該對兩張表進行關聯查詢
- Hive專門提供了語法lateral View側視圖,專門用於搭配explode這樣的UDTF函數,以滿足上述需要。
4.2 Lateral View側視圖
概念
Lateral View是一種特殊的語法,主要用於搭配UDTF類型功能的函數一起使用,用於解決UDTF函數的一些查詢限制的問題。
側視圖的原理是將UDTF的結果構建成一個類似於視圖的表,然後將原表中的每一行和UDTF函數輸出的每一行進行連接,生成一張新的虛擬表。這樣就避免了UDTF的使用限制問題。使用lateral view時也可以對UDTF產生的記錄設置字段名稱,產生的字段可以用於group by、order by 、limit等語句中,不需要再單獨嵌套一層子查詢。
一般只要使用UDTF,就會固定搭配lateral view使用。
官方鏈接:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+LateralView
UDTF配合側視圖使用
針對上述NBA冠軍球隊年份排名案例,使用explode函數+lateral view側視圖,可以完美解決:
--lateral view側視圖基本語法如下 select …… from tabelA lateral view UDTF(xxx) 別名 as col1,col2,col3……; select a.team_name ,b.year from the_nba_championship a lateral view explode(champion_year) b as year --根據年份倒序排序 select a.team_name ,b.year from the_nba_championship a lateral view explode(champion_year) b as year order by b.year desc;
4.3 Aggregation 聚合函數
基礎聚合
HQL提供了幾種內置的UDAF聚合函數,例如max(...),min(...)和avg(...)。這些我們把它稱之爲基礎的聚合函數。
通常情況下,聚合函數會與GROUP BY子句一起使用。 如果未指定GROUP BY子句,默認情況下,它會彙總所有行數據。
--------------基礎聚合函數------------------- --1、測試數據準備 drop table if exists student; create table student( num int, name string, sex string, age int, dept string) row format delimited fields terminated by ','; --加載數據 load data local inpath '/root/hivedata/students.txt' into table student; --驗證 select * from student; --場景1:沒有group by子句的聚合操作 select count(*) as cnt1,count(1) as cnt2 from student; --兩個一樣 --場景2:帶有group by子句的聚合操作 注意group by語法限制 select sex,count(*) as cnt from student group by sex; --場景3:select時多個聚合函數一起使用 select count(*) as cnt1,avg(age) as cnt2 from student; --場景4:聚合函數和case when條件轉換函數、coalesce函數、if函數使用 select sum(CASE WHEN sex = '男'THEN 1 ELSE 0 END) from student; select sum(if(sex = '男',1,0)) from student; --場景5:聚合參數不支持嵌套聚合函數 select avg(count(*)) from student; --聚合參數針對null的處理方式 --null null 0 select max(null), min(null), count(null); --下面這兩個不支持null select sum(null), avg(null); --場景5:聚合操作時針對null的處理 CREATE TABLE tmp_1 (val1 int, val2 int); INSERT INTO TABLE tmp_1 VALUES (1, 2),(null,2),(2,3); select * from tmp_1; --第二行數據(NULL, 2) 在進行sum(val1 + val2)的時候會被忽略 select sum(val1), sum(val1 + val2) from tmp_1; --可以使用coalesce函數解決 select sum(coalesce(val1,0)), sum(coalesce(val1,0) + val2) from tmp_1; --場景6:配合distinct關鍵字去重聚合 --此場景下,會編譯期間會自動設置只啓動一個reduce task處理數據 性能可能會不會 造成數據擁堵 select count(distinct sex) as cnt1 from student; --可以先去重 在聚合 通過子查詢完成 --因爲先執行distinct的時候 可以使用多個reducetask來跑數據 select count(*) as gender_uni_cnt from (select distinct sex from student) a; --案例需求:找出student中男女學生年齡最大的及其名字 --這裏使用了struct來構造數據 然後針對struct應用max找出最大元素 然後取值 select sex, max(struct(age, name)).col1 as age, max(struct(age, name)).col2 as name from student group by sex; select struct(age, name) from student; select struct(age, name).col1 from student; select max(struct(age, name)) from student;
增強聚合
概述與表數據環境準備
增強聚合的grouping_sets、cube、rollup這幾個函數主要適用於OLAP多維數據分析模式中,多維分析中的維指的分析問題時看待問題的維度、角度。
下面我們來準備一下數據,通過案例更好的理解函數的功能含義
字段:月份、天、用戶cookieid
--表創建並且加載數據 CREATE TABLE cookie_info( month STRING, day STRING, cookieid STRING ) ROW FORMAT DELIMITED FIELDS TERMINATED BY ','; load data local inpath '/root/hivedata/cookie_info.txt' into table cookie_info; select * from cookie_info;
Grouping sets
grouping sets是一種將多個group by邏輯寫在一個sql語句中的便利寫法。
等價於將不同維度的GROUP BY結果集進行UNION ALL。
GROUPING__ID表示結果屬於哪一個分組集合。
---group sets--------- SELECT month, day, COUNT(DISTINCT cookieid) AS nums, GROUPING__ID FROM cookie_info GROUP BY month,day GROUPING SETS (month,day) ORDER BY GROUPING__ID; --grouping_id表示這一組結果屬於哪個分組集合, --根據grouping sets中的分組條件month,day,1是代表month,2是代表day --等價於 SELECT month,NULL,COUNT(DISTINCT cookieid) AS nums,1 AS GROUPING__ID FROM cookie_info GROUP BY month UNION ALL SELECT NULL as month,day,COUNT(DISTINCT cookieid) AS nums,2 AS GROUPING__ID FROM cookie_info GROUP BY day; --再比如 SELECT month, day, COUNT(DISTINCT cookieid) AS nums, GROUPING__ID FROM cookie_info GROUP BY month,day GROUPING SETS (month,day,(month,day)) ORDER BY GROUPING__ID; --等價於 SELECT month,NULL,COUNT(DISTINCT cookieid) AS nums,1 AS GROUPING__ID FROM cookie_info GROUP BY month UNION ALL SELECT NULL,day,COUNT(DISTINCT cookieid) AS nums,2 AS GROUPING__ID FROM cookie_info GROUP BY day UNION ALL SELECT month,day,COUNT(DISTINCT cookieid) AS nums,3 AS GROUPING__ID FROM cookie_info GROUP BY month,day;
Cube
cube的語法功能指的是:根據GROUP BY的維度的所有組合進行聚合。
對於cube,如果有n個維度,則所有組合的總個數是:2^n。
比如Cube有a,b,c3個維度,則所有組合情況是:
((a,b,c),(a,b),(b,c),(a,c),(a),(b),(c),())。
------cube--------------- SELECT month, day, COUNT(DISTINCT cookieid) AS nums, GROUPING__ID FROM cookie_info GROUP BY month,day WITH CUBE ORDER BY GROUPING__ID; --等價於 SELECT NULL,NULL,COUNT(DISTINCT cookieid) AS nums,0 AS GROUPING__ID FROM cookie_info UNION ALL SELECT month,NULL,COUNT(DISTINCT cookieid) AS nums,1 AS GROUPING__ID FROM cookie_info GROUP BY month UNION ALL SELECT NULL,day,COUNT(DISTINCT cookieid) AS nums,2 AS GROUPING__ID FROM cookie_info GROUP BY day UNION ALL SELECT month,day,COUNT(DISTINCT cookieid) AS nums,3 AS GROUPING__ID FROM cookie_info GROUP BY month,day;
Rollup
cube的語法功能指的是:根據GROUP BY的維度的所有組合進行聚合。
rollup是Cube的子集,以最左側的維度爲主,從該維度進行層級聚合。
比如ROLLUP有a,b,c3個維度,則所有組合情況是:
((a,b,c),(a,b),(a),())。
--rollup------------- --比如,以month維度進行層級聚合: SELECT month, day, COUNT(DISTINCT cookieid) AS nums, GROUPING__ID FROM cookie_info GROUP BY month,day WITH ROLLUP ORDER BY GROUPING__ID; --把month和day調換順序,則以day維度進行層級聚合: SELECT day, month, COUNT(DISTINCT cookieid) AS uv, GROUPING__ID FROM cookie_info GROUP BY day,month WITH ROLLUP ORDER BY GROUPING__ID;
4.4 Window functions 窗口函數
窗口函數概述
窗口函數(Window functions)是一種SQL函數,非常適合於數據分析,因此也叫做OLAP函數,其最大特點是:輸入值是從SELECT語句的結果集中的一行或多行的“窗口”中獲取的。你也可以理解爲窗口有大有小(行有多有少)。
通過OVER子句,窗口函數與其他SQL函數有所區別。如果函數具有OVER子句,則它是窗口函數。如果它缺少OVER子句,則它是一個普通的聚合函數。
窗口函數可以簡單地解釋爲類似於聚合函數的計算函數,但是通過GROUP BY子句組合的常規聚合會隱藏正在聚合的各個行,最終輸出一行,窗口函數聚合後還可以訪問當中的各個行,並且可以將這些行中的某些屬性添加到結果集中。
爲了更加直觀感受窗口函數,我們通過sum聚合函數進行普通常規聚合和窗口聚合,一看效果。
----sum+group by普通常規聚合操作------------ select sum(salary) as total from employee group by dept;
----sum+窗口函數聚合操作------------ select id,name,deg,salary,dept,sum(salary) over(partition by dept) as total from employee;
窗口函數語法
Function(arg1,..., argn) OVER ([PARTITION BY <...>] [ORDER BY <....>] [<window_expression>]) --其中Function(arg1,..., argn) 可以是下面分類中的任意一個 --聚合函數:比如sum max avg等 --排序函數:比如rank row_number等 --分析函數:比如lead lag first_value等 --OVER [PARTITION BY <...>] 類似於group by 用於指定分組 每個分組你可以把它叫做窗口 --如果沒有PARTITION BY 那麼整張表的所有行就是一組 --[ORDER BY <....>] 用於指定每個分組內的數據排序規則 支持ASC、DESC --[<window_expression>] 用於指定每個窗口中 操作的數據範圍 默認是窗口中所有行
案例:網站用戶頁面瀏覽次數分析
在網站訪問中,經常使用cookie來標識不同的用戶身份,通過cookie可以追蹤不同用戶的頁面訪問情況,有下面兩份數據:
字段含義:cookieid 、訪問時間、pv數(頁面瀏覽數)
字段含義:cookieid、訪問時間、訪問頁面url
在Hive中創建兩張表表,把數據加載進去用於窗口分析。
---建表並且加載數據 create table website_pv_info( cookieid string, createtime string, --day pv int ) row format delimited fields terminated by ','; create table website_url_info ( cookieid string, createtime string, --訪問時間 url string --訪問頁面 ) row format delimited fields terminated by ','; load data local inpath '/root/hivedata/website_pv_info.txt' into table website_pv_info; load data local inpath '/root/hivedata/website_url_info.txt' into table website_url_info; select * from website_pv_info; select * from website_url_info;
窗口聚合函數
從Hive v2.2.0開始,支持DISTINCT與窗口函數中的聚合函數一起使用。
這裏以sum()函數爲例,其他聚合函數使用類似。
-----窗口聚合函數的使用----------- --1、求出每個用戶總pv數 sum+group by普通常規聚合操作 select cookieid,sum(pv) as total_pv from website_pv_info group by cookieid; --2、sum+窗口函數 總共有四種用法 注意是整體聚合 還是累積聚合 --sum(...) over( )對錶所有行求和 --sum(...) over( order by ... ) 連續累積求和 --sum(...) over( partition by... ) 同組內所有行求和 --sum(...) over( partition by... order by ... ) 在每個分組內,連續累積求和 --需求:求出網站總的pv數 所有用戶所有訪問加起來 --sum(...) over( )對錶所有行求和 select cookieid,createtime,pv, sum(pv) over() as total_pv from website_pv_info; --需求:求出每個用戶總pv數 --sum(...) over( partition by... ),同組內所行求和 select cookieid,createtime,pv, sum(pv) over(partition by cookieid) as total_pv from website_pv_info; --需求:求出每個用戶截止到當天,累積的總pv數 --sum(...) over( partition by... order by ... ),在每個分組內,連續累積求和 select cookieid,createtime,pv, sum(pv) over(partition by cookieid order by createtime) as current_total_pv from website_pv_info;
窗口表達式
我們知道,在sum(...) over( partition by... order by ... )語法完整的情況下,進行的累積聚合操作,默認累積聚合行爲是:從第一行聚合到當前行。
Window expression窗口表達式給我們提供了一種控制行範圍的能力,比如向前2行,向後3行。
語法如下:
關鍵字是rows between,包括下面這幾個選項
- preceding:往前
- following:往後
- current row:當前行
- unbounded:邊界
- unbounded preceding 表示從前面的起點
- unbounded following:表示到後面的終點
---窗口表達式 --第一行到當前行 select cookieid,createtime,pv, sum(pv) over(partition by cookieid order by createtime rows between unbounded preceding and current row) as pv2 from website_pv_info; --向前3行至當前行 select cookieid,createtime,pv, sum(pv) over(partition by cookieid order by createtime rows between 3 preceding and current row) as pv4 from website_pv_info; --向前3行 向後1行 select cookieid,createtime,pv, sum(pv) over(partition by cookieid order by createtime rows between 3 preceding and 1 following) as pv5 from website_pv_info; --當前行至最後一行 select cookieid,createtime,pv, sum(pv) over(partition by cookieid order by createtime rows between current row and unbounded following) as pv6 from website_pv_info; --第一行到最後一行 也就是分組內的所有行 select cookieid,createtime,pv, sum(pv) over(partition by cookieid order by createtime rows between unbounded preceding and unbounded following) as pv6 from website_pv_info;
窗口排序函數
窗口排序函數用於給每個分組內的數據打上排序的標號。注意窗口排序函數不支持窗口表達式。總共有4個函數需要掌握:
- row_number:在每個分組中,爲每行分配一個從1開始的唯一序列號,遞增,不考慮重複;
- rank: 在每個分組中,爲每行分配一個從1開始的序列號,考慮重複,擠佔後續位置;
- dense_rank: 在每個分組中,爲每行分配一個從1開始的序列號,考慮重複,不擠佔後續位置;
-----窗口排序函數 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 website_pv_info WHERE cookieid = 'cookie1';
上述這三個函數用於分組TopN的場景非常適合。
--需求:找出每個用戶訪問pv最多的Top3 重複並列的不考慮 SELECT * from (SELECT cookieid, createtime, pv, ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY pv DESC) AS seq FROM website_pv_info) tmp where tmp.seq <4;
還有一個函數,叫做ntile函數,其功能爲:將每個分組內的數據分爲指定的若干個桶裏(分爲若干個部分),並且爲每一個桶分配一個桶編號。
如果不能平均分配,則優先分配較小編號的桶,並且各個桶中能放的行數最多相差1。
有時會有這樣的需求:如果數據排序後分爲三部分,業務人員只關心其中的一部分,如何將這中間的三分之一數據拿出來呢?NTILE函數即可以滿足。
--把每個分組內的數據分爲3桶 SELECT cookieid, createtime, pv, NTILE(3) OVER(PARTITION BY cookieid ORDER BY createtime) AS rn2 FROM website_pv_info ORDER BY cookieid,createtime;
--需求:統計每個用戶pv數最多的前3分之1天。 --理解:將數據根據cookieid分 根據pv倒序排序 排序之後分爲3個部分 取第一部分 SELECT * from (SELECT cookieid, createtime, pv, NTILE(3) OVER(PARTITION BY cookieid ORDER BY pv DESC) AS rn FROM website_pv_info) tmp where rn =1;
窗口分析函數
LAG(col,n,DEFAULT) 用於統計窗口內往上第n行值
第一個參數爲列名,第二個參數爲往上第n行(可選,默認爲1),第三個參數爲默認值(當往上第n行爲NULL時候,取默認值,如不指定,則爲NULL);
LEAD(col,n,DEFAULT) 用於統計窗口內往下第n行值
第一個參數爲列名,第二個參數爲往下第n行(可選,默認爲1),第三個參數爲默認值(當往下第n行爲NULL時候,取默認值,如不指定,則爲NULL);
FIRST_VALUE 取分組內排序後,截止到當前行,第一個值;
LAST_VALUE 取分組內排序後,截止到當前行,最後一個值;
-----------窗口分析函數---------- --LAG 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 website_url_info; --LEAD 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_1_time, LEAD(createtime,2) OVER(PARTITION BY cookieid ORDER BY createtime) AS next_2_time FROM website_url_info; --FIRST_VALUE 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 website_url_info; --LAST_VALUE 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 website_url_info;
4.5 Sampling 抽樣函數
抽樣概述
當數據量過大時,我們可能需要查找數據子集以加快數據處理速度分析。 這就是抽樣、採樣,一種用於識別和分析數據中的子集的技術,以發現整個數據集中的模式和趨勢。
在HQL中,可以通過三種方式採樣數據:隨機採樣,存儲桶表採樣和塊採樣。
Random隨機抽樣
隨機抽樣使用rand()函數和LIMIT關鍵字來獲取數據。 使用了DISTRIBUTE和SORT關鍵字,可以確保數據也隨機分佈在mapper和reducer之間,使得底層執行有效率。
ORDER BY 和rand()語句也可以達到相同的目的,但是表現不好。因爲ORDER BY是全局排序,只會啓動運行一個Reducer。
--數據表 select * from student; --需求:隨機抽取2個學生的情況進行查看 SELECT * FROM student DISTRIBUTE BY rand() SORT BY rand() LIMIT 2; --使用order by+rand也可以實現同樣的效果 但是效率不高 SELECT * FROM student ORDER BY rand() LIMIT 2;
Block塊抽樣
Block塊採樣允許select隨機獲取n行數據,即數據大小或n個字節的數據。
採樣粒度是HDFS塊大小。
---block抽樣 --根據行數抽樣 SELECT * FROM student TABLESAMPLE(1 ROWS); --根據數據大小百分比抽樣 SELECT * FROM student TABLESAMPLE(50 PERCENT); --根據數據大小抽樣 --支持數據單位 b/B, k/K, m/M, g/G SELECT * FROM student TABLESAMPLE(1k);
Bucket table分桶表抽樣
這是一種特殊的採樣方法,針對分桶表進行了優化。
---bucket table抽樣 --根據整行數據進行抽樣 SELECT * FROM t_usa_covid19_bucket TABLESAMPLE(BUCKET 1 OUT OF 2 ON rand()); --根據分桶字段進行抽樣 效率更高 describe formatted t_usa_covid19_bucket; SELECT * FROM t_usa_covid19_bucket TABLESAMPLE(BUCKET 1 OUT OF 2 ON state);