Hive參數配置與函數、運算符使用

第一章、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&amp;useSSL=false&amp;useUnicode=true&amp;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);

 

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