1. 程式人生 > 實用技巧 >HIVE理論學習筆記

HIVE理論學習筆記

概述

參加了新的公司新的工作新的環境之後,本人必須學習更多的知識,所以穩固之前的知識和學習新的知識是重中之重,新的公司把hadoop大部分的元件都進行了架構原始碼深度改造,所以使用過程確實遇到一些麻煩,而寫這篇隨筆的目的就是記錄之前學習的知識,並且作為學習新的架構的基礎。就是本文說的hive元件。

HIVE架構

hive是建立在hadoop之上資料倉庫基礎架構,它提供了一系列的工具,可以用來進行資料提取轉化載入ETL,這是一種可以儲存、查詢和分析儲存在hadoop中的大規模資料機制。hive定義了簡單的類SQL語言,稱為QL,允許熟悉SQL的使用者查詢資料。hive就是SQL解析引擎,將sql轉換Map/Reducer job 然後在hadoop中執行,hive表就是hdfs目錄,按表名把資料夾分開。如果是分割槽表,則分割槽值是子資料夾,可以直接在Map/Reduce job使用這些資料。hive把sql語句轉換成MR任務之後,採取批處理的方式對資料進行提取,轉換,載入的工具。

同時,這個語言也允許熟悉MapReduce開發者的自定義的mapper和reducer來處理內建的mapper和reducer無法完成的複雜的分析工作。見下圖:

見上圖:hive的體系分為以下幾個部分:

1,使用者介面主要有三個:CLI,Client和WUI,其中最常見的是CLI,cli啟動的時候會同時啟動一個hive副本。client是hive的客戶端,使用者連線到hive server。在啟動client模式的時候,需要指出hive server所在節點,並且在該節點啟動hive server。WUI是通過瀏覽器訪問Hive。

2,Hive將元資料儲存在資料庫表中,如mysql、derby。hive中的元資料包括表的名字,表的列和分割槽及其屬性,表的屬性(是否為外部表等),表的資料所在目錄等。

3,直譯器、編譯器、優化器完成HQL查詢語句從詞法分析,語法分析,編譯,優化以及查詢計劃的生成。生成的查詢計劃儲存在hdfs中,並在隨後有mapreduce呼叫執行。

4,hive的資料儲存在hdfs中,大部分的查詢,計算由mapreduce完成(包含* 的查詢,不會生成mapreduce任務)。

在看一個詳細的架構圖:

簡單來說hive就是一個查詢引擎,接收到一個sql,而後面做的事情就是上面描述的,下面說明一下:

詞法分析/語法分析:使用antlr將SQL語句解析成抽象語法樹(AST)。

語義分析:從Megastore獲取模式資訊,驗證SQL語句中隊表名,列名,以及資料型別的檢查和隱士轉換。以及hive提供的函式和使用者自定義的函式(UDF/UAF)。

邏輯計劃生成:生成邏輯計劃--運算元樹。

邏輯計劃優化:隊運算元樹進行優化,包括列剪枝,分割槽剪枝,謂詞下推等。

物理計劃生成:將邏輯計劃生成包含由MapReduce任務組成的DAG的物理計劃。

物理計劃執行:將DAG傳送到hadoop叢集進行執行。

最後把查詢結果返回

hive的三種執行模式:內嵌模式,本地模式,遠端模式。

建立表時:

解析使用者提交的Hive語句-->對其進行解析-->分解為表、欄位、分割槽等Hive物件。根據解析到的資訊構建對應的表、欄位、分割槽等物件,從SEQUENCE_TABLE中獲取構建物件的最新的ID,與構建物件資訊(名稱、型別等等)一同通過DAO方法寫入元資料庫的表中,成功後將SEQUENCE_TABLE中對應的最新ID+5.實際上常見的RDBMS都是通過這種方法進行組織的,其系統表中和Hive元資料一樣顯示了這些ID資訊。通過這些元資料可以很容易的讀取到資料。

hive編譯器:

hive編譯流程:

HIVE元資料儲存

儲存模式

hive將元資料儲存在RDBMS中,有三種模式可以連線到資料庫:

1,單使用者模式:此模式連線到一個In-memory的資料庫derby,一般用於Unit Test。

2,多使用者模式:通過網路連線到一個數據庫中,是經常使用到的模式。

3,遠端伺服器模式:用於非java客戶端訪問元資料庫在服務端啟動MetaStoreServer,客戶端利用Thrift協議通過MetaStoreServer訪問元資料庫。

對於資料儲存,Hive沒有專門的資料儲存格式,也沒有為資料建立索引,使用者可以非常自由的組織Hive中的表,只需要在建立表的時候告訴Hive資料中的列分隔符和行分隔符,Hive就可以解析資料。Hive中所有的資料都儲存在HDFS中,儲存結構主要包括資料庫、檔案、表和檢視。Hive中包含以下資料模型:Table內部表,External Table外部表,Partition分割槽,Bucket桶。Hive預設可以直接載入文字檔案,還支援sequence file 、RCFile。

總結

元資料儲存優化

大部分公司我相信元資料都是存在了mysql中,但是隨著業務的增長,mysql內已經出現單表資料量,兩千多萬的情況,當用戶出現在MetaStore密集操作的情況,往往會出現緩慢甚至超時的現象,極大的影響了任務的穩定性,所以優化hive的元資料趨勢勢在必行。

在去年,我們做過資料治理,Hive 表生命週期管理,定期去刪除元資料,期望能夠減少 MySQL 的資料量,緩解元資料庫的壓力。但是經過實踐,發現該方案有以下缺點:

  1. 資料的增長遠比刪除的要快,治標不治本;

  2. 在刪除超大分割槽表(分割槽數上百萬)的分割槽時,會對 MySQL 造成一定的壓力,只能單執行緒去做,否則會影響其他正常的 Hive 查詢,效率極其低下;

  3. 在知乎,元資訊刪除是伴隨資料一起刪除的(刪除 HDFS 過期資料,節約成本),Hive 的使用者可能存在建表不規範的情況,將分割槽路徑掛錯,導致誤刪資料。

因此,我們需要尋找新的技術方案來解決這個問題。

已有方案:

主要有兩種方案可以選擇:

1,對mysql進行分庫分表處理,將一臺的mysql的壓力分攤到mysql叢集;

2,對hive metastore進行federation,採用多套hive metastore+mysql的架構,在metastore前方設定代理,按照一定的規則,對請求進行分發。

但是上面方案有缺陷:

1,對 MySQL 進行分庫分表,首先面臨的直接問題就是需要修改 Metastore 操作 MySQL 的介面,涉及到大量高風險的改動,後續對 Hive 的升級也會更加複雜;,

2,對 Hive Metastore 進行 Federation,儘管不需要對 Metastore 進行任何改動,但是需要額外維護一套路由元件,並且對路由規則的設定需要仔細考慮,切分現有的 MySQL 儲存到不同的 MySQL 上,並且可能存在切分不均勻,導致各個子叢集的負載不均衡的情況;

3,我們每天都會同步一份 MySQL 的資料到 Hive,用作資料治理,生命週期管理等,同步是利用內部的資料同步平臺,如果採用上面兩種方案,資料同步平臺也需要對同步邏輯做額外的處理

知乎的方案:

其實問題主要在於,當資料量增加時,MySQL 受限於單機效能,很難有較好的表現,而將單臺 MySQL 擴充套件為叢集,複雜度將會呈幾何倍上升。如果能夠找到一款相容 MySQL 協議的分散式資料庫,就能完美解決這個問題。因此,我們選擇了TiDB。

TiDB 是 PingCAP 開源的分散式 NewSQL 資料庫,它支援水平彈性擴充套件、ACID 事務、標準 SQL、MySQL 語法和 MySQL 協議,具有資料強一致的高可用特性,是一個不僅適合 OLTP 場景還適 OLAP 場景的混合資料庫。

HIVE基礎命令

建表語句:

1  CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name      
2  [(col_name data_type [COMMENT col_comment], ...)]      
3  [COMMENT table_comment]                                 
4  [PARTITIONED BY(col_name data_type [COMMENT col_comment], ...)]
5  [CLUSTERED BY (col_name, col_name, ...)
6  [SORTED BY(col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]
7  [ROW FORMAT row_format] 
8  [STORED AS file_format]
9  [LOCATION hdfs_path]  

引數說明:

  • CREATE TABLE 建立一個指定名字的表。如果相同名字的表已經存在,則丟擲異常;使用者可以用 IF NOT EXISTS 選項來忽略這個異常。

  • EXTERNAL 關鍵字可以讓使用者建立一個外部表,預設是內部表。外部表在建表的必須同時指定一個指向實際資料的路徑(LOCATION),Hive 建立內部表時,會將資料移動到資料倉庫指向的路徑;若建立外部表,僅記錄資料所在的路徑,不對資料的位置做任何改變。在刪除表的時候,內部表的元資料和資料會被一起刪除,而外部表只刪除元資料,不刪除資料。

  • COMMENT 是給表字段或者表內容添加註釋說明的。

  • PARTITIONED BY 給表做分割槽,決定了表是否是分割槽表。

  • CLUSTERED BY 對於每一個表(table)或者分割槽, Hive 可以進一步組織成桶,也就是說桶是更為細粒度的資料範圍劃分,Hive採用對列值雜湊,然後除以桶的個數求餘的方式決定該條記錄存放在哪個桶當中。

  • ROW FORMAT DELIMITED FIELDS TERMINATED BY ',', 這裡指定表儲存中列的分隔符,預設是 \001,這裡指定的是逗號分隔符,還可以指定其他列的分隔符。

  • STORED AS SEQUENCEFILE|TEXTFILE|RCFILE,如果檔案資料是純文字,可以使用 STORED AS TEXTFILE,如果資料需要壓縮,使用 STORED AS SEQUENCEFILE。

  • LOCATION 定義 hive 表的資料在 hdfs 上的儲存路徑,一般管理表(內部表不不要自定義),但是如果定義的是外部表,則需要直接指定一個路徑。

基本DDL

 1 // 檢視資料庫
 2 show databases;
 3 
 4 // 使用資料庫
 5 use srm;
 6 
 7 // 顯示所有的函式
 8 show functions;
 9 
10 // 檢視函式用法
11 describe function substr;
12 
13 // 檢視當前資料庫下
14 show tables;
15 
16 // 查看錶結構
17 desc invoice_lines;
18 
19 // 檢視某個表的分割槽情況
20 show partitions invoice_lines;
21 
22 // 建立表
23 CREATE TABLE IF NOT EXISTS srm.invoice_lines_temp2(
24 SOURCE_SYS_KEY string comment '' ,
25 LEGAL_COMPANY string comment '' ,
26 VENDOR_NAME string comment '' ,
27 INVOICE_UNIT_PRICE double comment '' ,
28 PREPAY_UNAPPLIED double comment '' ,
29 GR_NON_VALUATED string comment '' 
30 )partitioned by(jobid string) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
31 // LOCATION 用於指定表的資料檔案路徑
32 # LOCATION 'hdfs://cdh5/tmp/invoice/'; 
33 
34 // 根據某張表,建立一張機構一樣的表
35 create table invoice_lines_temp2 like invoice_lines;
36 
37 // 建立外部表
38 CREATE EXTERNAL TABLE tinvoice_lines(id STRING, name STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LOCATION '/data/test/test_table';
39 
40 // 刪除表,如果是外部表,只會刪除元資料(表結構),不會刪除外部檔案中
41 drop table invoice_lines;
42 
43 // 刪除表的某個分割槽
44 alter table srm.invoice_lines_temp2 drop partition(jobid='JOBID');
45 
46 // 刪除外部表資料檔案以及目錄
47 DFS -rm -r /data/test/test_table;
48 
49 // 更新表
50 ALTER TABLE invoice_lines RENAME TO invoice_lines2;
51 ALTER TABLE invoice_lines ADD COLUMNS (new_col2 INT COMMENT '內容');
52 
53 // 清空表,比delete快很多,在mysql中會連索引記錄都清空。delete會記錄日誌,truncate 不會記錄日誌?
54 truncate table invoice_lines;
55 
56 // 刪除記錄
57 delete from invoice [where xxx = yyy]

內部表和外部表的區別:

Hive 建立內部表時,會將資料移動到資料倉庫指向的路徑;

Hive 建立外部表,僅記錄資料所在的路徑, 不對資料的位置做任何改變;

在刪除表的時候,內部表的元資料和資料會被一起刪除, 而外部表只刪除元資料,不刪除資料。這樣外部表相對來說更加安全些,資料組織也更加靈活,方便共享源資料。

cli基本引數

和資料匯入相關:

在load data時,如果載入的檔案在HDFS上,此檔案會被移動到表路徑中;

在load data時,如果載入的檔案在本地,此檔案會被複制到HDFS的表路徑中;

在load data時,會為每一個待匯入的檔案,啟動一個MR任務進行匯入;

 1 -----------------------------------------有關於資料匯入------------------------------------------
 2 
 3 // 匯入本地檔案資料到Hive表
 4 load data local inpath '/apps/data/test1.txt'  into table invoice_lines;
 5 
 6 // 匯入HDFS檔案資料到Hive表
 7 load data inpath '/hdfs/app/data/test.txt'  into table invoice_lines;
 8 
 9 // 從別的表中查詢出相應的資料並匯入到Hive表中,注意列數目一定要相同
10 insert into table invoice_lines select * from invoice_lines_temp2;
11 // 匯入到指定分割槽表,注意列數目一定要相同
12 insert into table invoice_lines partition(jobid='106') select xx1,xx2,xx3 from invoice_lines_temp2 where jobid='106';
13 // 匯入到指定分割槽表,採用動態分割槽的方式,注意列數目一定要相同
14 insert into table invoice_lines partition(jobid) select * from invoice_lines_temp2;
15 // Hive還支援多表插入,即把FROM 寫到前面
16 FROM invoice insert into table invoice_temp1 select xx,xx2 insert into table invoice_temp2 select xx4,xx6;
17 
18 // 專案上用到的一些寫法
19 INSERT OVERWRITE TABLE srm.invoice_lines_temp2 PARTITION(jobid) SELECT sour_t.* FROM srm.invoice_lines_temp2 sour_t WHERE jobid = '106';
20 INSERT INTO TABLE srm.invoice_lines SELECT * FROM srm.invoice_lines_temp2 WHERE jobid = '106';
21 INSERT OVERWRITE TABLE srm.invoice_lines_temp2 PARTITION(jobid) SELECT * FROM srm.invoice_lines_temp2 WHERE jobid='106' AND 1 = 1;
22 INSERT OVERWRITE TABLE srm.invoice_lines_temp2 PARTITION(jobid) 
23 SELECT temp.* FROM srm.invoice_lines_temp2 temp JOIN 
24 (
25 SELECT
26     source_sys_key,
27     legal_company,
28     count( DISTINCT concat_ws( '', concat( invoice_line_type ), concat( invoice_head_id ) ) ) 
29 FROM
30     srm.invoice_lines_temp2 
31 WHERE jobid = '106' 
32 GROUP BY
33     source_sys_key,
34     legal_company 
35 HAVING
36     count( DISTINCT concat_ws( '', concat( invoice_line_type ), concat( invoice_head_id ) ) ) = 1 
37 ) t0 ON (temp.source_sys_key = t0.source_sys_key AND temp.legal_company = t0.legal_company )
38 where temp.jobid = '106';
39 
40 // 在建立表的時候通過從別的表中查詢出相應的記錄並插入到所建立的表中
41 create table invoice_temp1 AS select xx1,xx2,xx3 from invoice;
42 
43 -----------------------------------------有關於資料匯入------------------------------------------
44 
45 
46 // 刪除表中資料,但要保持表的結構定義
47 dfs -rmr /user/hive/warehouse/srm/invoice_lines;
48 
49 // 建立外部表
50 CREATE EXTERNAL TABLE tinvoice_lines(id STRING, name STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LOCATION '/data/test/test_table';
51 // 匯入資料到表中(檔案會被移動到倉庫目錄/data/test/test_table)
52 load data inpath '/test_tmp_data.txt' INTO TABLE tinvoice_lines;
53 
54 hive -e "load data local inpath '${SOURCE_PATH}/${SourceFileNameNochar}' overwrite into table srm.invoice_lines_temp1 partition(jobid='${JOBID}');"

sqoop匯入匯出

 1 // 測試資料庫連線
 2 sqoop eval --connect jdbc:mysql://192.168.180.11/angel --username root--password root
 3 
 4 // MySQL匯入到Hive
 5 sqoop import --connect jdbc:mysql://localhost:3306/test --username root --password 123456 --table person -m 1 --hive-import
 6 
 7 // 匯出該某Hive表所有資料到MySQL
 8 sqoop export --connect jdbc:mysql://192.168.11.172:16408/ztsrm  --username srm --password handhand  --table invoice_lines  --export-dir /apps/hive/warehouse/srm.db/invoice_lines_temp2/jobid=106 --input-fields-terminated-by ','  --input-null-string "\\\\N" --input-null-non-string "\\\\N"
 9 
10 // 匯出該某Hive表指定分割槽資料到MySQL
11 sqoop export --connect jdbc:mysql://192.168.11.172:16408/ztsrm  --username srm --password handhand  --table invoice_lines  --export-dir /apps/hive/warehouse/srm.db/invoice_lines_temp2 --input-fields-terminated-by ','  --input-null-string "\\\\N" --input-null-non-string "\\\\N"

INTO 和 OVERWRITE

insert into 與 insert overwrite 都可以向hive表中插入資料,但是insert into直接追加到表中資料的尾部,而insert overwrite會重寫資料,既先進行刪除,再寫入。如果存在分割槽的情況,insert overwrite會只重寫當前分割槽資料。

建立hive指令碼python

 1 import  pymysql  
 2 import codecs
 3 
 4   
 5 def getSingleSQL(table,schema = 'srm',ispartition = False):  
 6     # table =  為表名,mysql, hive表名一致 
 7     # schema = 為hive中的庫名 
 8     # ispartition : 是否分割槽預設為分割槽 
 9 
10     create_head = 'CREATE TABLE IF NOT EXISTS {0}.{1}('.format(schema,table) + '\n'
11     create_tail = 'ROW FORMAT DELIMITED FIELDS TERMINATED BY \',\' ; \n\n'
12     connection=pymysql.connect(host='192.168.11.172', port=16408, user='srm', password='handhand', db='srm', charset='utf8')  
13     try:  
14         with connection.cursor(cursor=pymysql.cursors.DictCursor) as cursor:  
15             sql='SHOW FULL FIELDS FROM  {0}'.format(table)  
16             cursor.execute(sql) 
17             try:  
18                 for row in cursor: 
19                     if 'bigint' in row['Type']:  
20                         row['Type'] = "bigint"  
21                     elif 'int' in row['Type'] or 'tinyint' in row['Type'] or 'smallint' in row['Type'] or 'mediumint' in row['Type'] or 'integer' in row['Type']:  
22                         row['Type'] = "int"  
23                     elif 'double' in row['Type'] or 'float' in row['Type'] or 'decimal' in row['Type']:  
24                         row['Type'] = "double"  
25                     else:  
26                         row['Type'] = "string"  
27                     create_head += row['Field'] + ' '+ row['Type'] +' comment \'' + row['Comment'] + '\' ,\n'       
28             except:  
29                 print('程式異常!')    
30     finally:  
31         connection.close()  
32     singleSQL = create_head[:-2] + '\n' + ')'+ create_tail
33     return singleSQL     
34 
35 
36 
37 def getTotalSQL():
38     connection=pymysql.connect(host='192.168.11.172', port=16408, user='srm', password='handhand', db='srm', charset='utf8')
39     try:  
40         with connection.cursor(cursor=pymysql.cursors.DictCursor) as cursor:  
41             sql='SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=\'SRM\' AND TABLE_TYPE=\'BASE TABLE\' ' 
42             cursor.execute(sql)
43             try:
44                 for row in cursor:
45                     print(row)
46                     tableName = row['TABLE_NAME']
47                     singleSQL = getSingleSQL(tableName)
48                     f = open('create_hive_table.sql', 'a', encoding='utf-8')
49                     f.write(singleSQL) 
50             except:  
51                 print('程式異常了哦!')   
52     finally:  
53         connection.close()  
54 
55 getTotalSQL()

HIVE重要的知識點

謂詞下推:

就是將SQL語句中的where謂詞邏輯都儘可能提前執行,減少下游處理的資料量。Hive中有謂詞下推優化的配置項hive.optimize.ppd,預設值true,與它對應的邏輯優化器是PredicatePushDown。該優化器就是將OperatorTree中的FilterOperator向上提,見下圖。

group by

(1) map端預聚合

group by時,如果先起一個combiner在map端做部分預聚合,可以有效減少shuffle資料量。預聚合的配置項是hive.map.aggr,預設值true。通過hive.groupby.mapaggr.checkinterval引數也可以設定map端預聚合的行數閾值,超過該值就會分拆job,預設值100000。

(2) 傾斜均衡配置項

group by時如果某些key對應的資料量過大,就會發生資料傾斜。配置均衡資料傾斜的配置項hive.groupby.skewindata=true。

其實現方法是在group by時啟動兩個MR job。第一個job會將map端資料隨機輸入reducer,每個reducer做部分聚合,相同的key就會分佈在不同的reducer中。第二個job再將前面預處理過的資料按key聚合並輸出結果,這樣就起到了均衡的效果。

join

1、多表join時key相同

如果多表的join時候用的key相同,只會啟動一個MR job來處理。

2、利用map join

Map join特別適合大小表join的情況。Hive會將大小表在map端直接完成join過程,避免shuffle過程和reduce端計算,大大的提高效率。

map join,配置hive.auto.convert.join=true。還有一些引數用來控制map join的行為,比如hive.mapjoin.smalltable.filesize,當小表大小小於該值就會啟用map join,預設值25000000(25MB)。還有hive.mapjoin.cache.numrows,表示快取小表的多少行資料到記憶體,預設值25000。

3、傾斜均衡配置項

配置hive.optimize.skewjoin=true

如果開啟了,在join過程中Hive會將計數超過閾值hive.skewjoin.key(預設100000)的傾斜key對應的行臨時寫進檔案中,然後再啟動另一個job做mapjoin生成結果。通過hive.skewjoin.mapjoin.map.tasks引數還可以控制第二個job的mapper數量,預設10000。

4、優化sql處理join的資料傾斜

(1) 空值或者無意義值

若不需要空值資料,就提前寫where語句過濾掉。需要保留的話,將空值key用隨機方式打散

(2) 單獨處理資料傾斜key

這其實是上面處理空值方法的拓展,不過傾斜的key變成了有意義的。我們可以將它們抽樣出來,對應的行單獨存入臨時表中,然後打上一個較小的隨機數字首(比如0~9),最後再進行聚合。SQL語句與上面的相仿

(3) 不同資料型別

舉個例子,假如我們有一舊一新兩張日曆記錄表,舊錶的記錄型別欄位是(event_type int),新表的是(event_type string)。為了相容舊版記錄,新表的event_type也會以字串形式儲存舊版的值,比如'17'。當這兩張表join時,經常要耗費很長時間。其原因就是如果不轉換型別,計算key的hash值時預設是以int型做的,這就導致所有“真正的”string型key都分配到一個reducer上。

(4) 小表過大

小表會大到無法直接使用map join的地步,而使用普通join又有資料分佈不均的問題。這時就要充分利用大表的限制條件,削減小表的資料量,再使用map join解決。代價就是需要進行兩次join。

問題:Hive中Beeline提交的SQL查詢同Hive客戶端提交的SQL查詢處理流程有何異同?

據我所知,Beeline是通過JDBC向Thrift-Server提交查詢請求。Hive客戶端是通過自己的Driver來提交。

1、hive客戶端是在本地做sql的編譯,然後將hql翻譯成mr任務提交到hadoop。而beeline實際上是對SQLLine的封裝,實際上是呼叫hiveserver2來進行查詢的。

2、從許可權控制角度來講,目前hive的許可權控制有兩種,一種是基於對應hdfs操作許可權的控制機制,一種是符合SQL規範的控制機制,前者適合於提供給RD的許可權控制(可以防止別人誤刪你的表),後者適合於提供給hive的BI使用者的許可權控制(可以控制到表或欄位可見級別)。後者更細緻,更符合資料倉庫的許可權控制。但是後者只能用在beeline方式下,不能用在命令列中。

3、hive推薦使用beeline。

HIVE十大特點

1.分割槽表:

Hive分割槽是提高較大表的查詢效能的有效方法。分割槽允許您將資料儲存在表位置下的單獨子目錄中。它極大地幫助了在分割槽鍵上查詢的查詢。雖然分割槽鍵的選擇始終是一個敏感的決定,但它應該始終是一個低基數屬性,例如,如果您的資料與時間維度相關聯,那麼date可能是一個好的分割槽鍵。同樣,如果資料與位置(如國家或州)相關聯,則最好使用國家/州等分層分割槽。

2.使資料去標準化:

規範化是一個標準流程,用於使用某些規則對資料表建模,以處理資料和異常的冗餘。簡單來說,如果規範化資料集,最終會建立多個關係表,這些表可以在執行時連線以生成結果。連線是昂貴且難以執行的操作,並且是效能問題的常見原因之一。因此,避免高度規範化的表結構是一個好主意,因為它們需要連線查詢來獲得所需的指標。

3.壓縮對映/減少輸出(壓縮MAP/減少REDUCE):

壓縮技術顯著減少了中間資料量,從而減少了MAP和REDUCE之間的資料傳輸量。所有這些通常都發生在網路上也就是利用hiveserver2連結Hive伺服器的時候。壓縮可以單獨應用於mapper和reducer輸出。請記住,gzip壓縮檔案不可拆分。這意味著應該謹慎應用。壓縮檔案大小不應大於幾百兆位元組(推文)。否則可能導致工作失衡。壓縮編解碼器的其他選項可能是snappy,lzo,bzip等。

對於map輸出壓縮,將mapred.compress.map.output設定為true

對於job輸出壓縮,將mapred.output.compress設定為true

4.對映連線:

如果連線另一側的表足夠小以適應記憶體,則對映連線非常有效。Hive支援一個引數hive.auto.convert.join,當它設定為“true”時,Hive會嘗試自動對映連線。使用此引數時,請確保在Hive環境中啟用了自動轉換。

5.分桶:

Hive的分桶可以大大提高儲存和查詢的效能。Hive中的分桶根據個桶上key值的雜湊結果將資料分配到不同的桶中。如果程序發生在相同的鍵上,它還會減少連線過程中的I / O掃描。

此外,每次在將資料寫入分桶表之前確保已經設定了分桶引數(SET hive.enforce.bucketing = true;)這非常重要。要在表操作中利用bucketing,我們應該設定hive.optimize.bucketmapjoin = true。此設定提示Hive在MAP階段加入期間執行桶級操作。它還減少了掃描週期以查詢特定的key值,因為儲存確保key存在於某個儲存桶中。

6.輸入格式選擇:

輸入格式在Hive效能中起著關鍵作用。例如,輸入格式的文字型別JSON對於資料量非常高的大型生產系統來說不是一個好的選擇。這些型別的可讀格式實際上佔用了大量空間並且有一些解析開銷(例如JSON解析)。為解決這些問題,Hive提供了RCFile,ORC等列式輸入格式。柱狀格式允許您通過允許單獨訪問每個列來減少分析查詢中的讀取操作。還有其他一些二進位制格式,如Avro,序列檔案,Thrift和ProtoBuf,它們在各種用例中也很有用。

7.並行執行:

Hadoop可以並行執行MapReduce作業,在Hive上執行的幾個查詢會自動使用這種並行性。但是,單個複雜的Hive查詢通常會轉換為預設執行的許多MapReduce作業。但是,一些查詢的MapReduce階段通常不是相互依賴的,可以並行執行。然後,他們可以利用群集上的備用容量並提高群集利用率,同時減少總體查詢執行時間。Hive中用於更改此行為的配置僅僅是切換單個標誌SET hive.exec.parallel = true。

8.向量化:

Vectorization允許Hive一起處理一批行,而不是一次處理一行。每個批次都包含一個列向量,它通常是一個基本型別的陣列。對整個列向量執行操作,這改進了指令管道和快取記憶體使用。要啟用向量化,請將此配置引數設定為SET hive.vectorized.execution.enabled = true。

9.單元測試:

簡單來說,單元測試可以確定程式碼中最小的可測試部分是否與您期望的完全一致。單元測試提供了一些好處,即儘早檢測問題,更容易更改和重構程式碼,作為一種解釋程式碼如何工作的文件形式,僅舉幾例。

在Hive中,您可以對UDF,SerDes,流式指令碼,Hive查詢等進行單元測試。在很大程度上,可以通過執行快速本地單元測試來驗證整個HiveQL查詢的正確性,而無需觸及Hadoop叢集。因為在本地模式下執行HiveQL查詢需要幾秒鐘,相比之下,如果它在Hadoop模式下執行,則分鐘,小時或天數肯定會節省大量的開發時間。

有幾種工具可以幫助您測試Hive查詢。其中一些你可能想看看HiveRunner,Hive_test和Beetest。

10.抽樣:

取樣允許使用者獲取資料集的子集並對其進行分析,而無需分析整個資料集。如果使用代表性樣本,則查詢可以返回有意義的結果,並且可以更快地完成並消耗更少的計算資源。

Hive提供了一個內建的TABLESAMPLE子句,允許您對錶進行取樣。TABLESAMPLE可以在不同的粒度級別進行取樣 - 它只能返回桶的子集(桶取樣)或HDFS塊(塊取樣),或者只返回每個輸入拆分的前N個記錄。或者,您可以實現自己的UDF,根據您的取樣演算法過濾掉記錄。

HIVE視窗函式

視窗函式是用於分析用的一類函式,要理解視窗函式要先從聚合函式說起。 大家都知道聚合函式是將某列中多行的值合併為一行,比如sum、count等。 而視窗函式則可以在本行內做運算,得到多行的結果,即每一行對應一行的值。 通用的視窗函式可以用下面的語法來概括:

Function() Over (Partition By Column1,Column2,Order By Column3)

視窗函式又分為以下三類:聚合型視窗函式分析型視窗函式 * 取值型視窗函式

接下來我們將通過幾個實際的例子來介紹下視窗函式

準備資料

CREATE TABLE user_match_temp (
user_name string,
opponent string,
result int,
create_time timestamp);

INSERT INTO TABLE user_match_temp values
('vpspringcloud','vpspringboot',1,'2019-07-18 23:19:00'),
('vpspringboot','vpspringcloud',0,'2019-07-18 23:19:00'),
('vpspringcloud','vpspringdata',0,'2019-07-18 23:20:00'),
('vpspringdata','vpspringcloud',1,'2019-07-18 23:20:00'),
('vpspringcloud','vpspringroo',1,'2019-07-19 22:19:00'),
('vpspringroo','vpspringcloud',0,'2019-07-19 22:19:00'),
('vpspringdata','vpspringboot',0,'2019-07-19 23:19:00'),
('vpspringboot','vpspringdata',1,'2019-07-19 23:19:00');

資料包含4列,分別為 user_name,opponent,result,create_time。 我們將基於這些資料來介紹下視窗函式的一些使用場景。

聚合性視窗函式

聚合型即SUM(), MIN(),MAX(),AVG(),COUNT()這些常見的聚合函式。 聚合函式配合視窗函式使用可以使計算更加靈活,例如以下場景: * 至今累計分數:

hive> SELECT *, SUM(result) OVER (PARTITION BY user_name ORDER BY create_time) AS result_sums
hive> FROM user_match_temp;

+----------------+----------------+---------+------------------------+--------------+--+
|   user_name    |    opponent    | result  |      create_time       | result_sums  |
+----------------+----------------+---------+------------------------+--------------+--+
| vpspringdata   | vpspringcloud  | 1       | 2019-07-18 23:20:00.0  | 1            |
| vpspringdata   | vpspringboot   | 0       | 2019-07-19 23:19:00.0  | 1            |
| vpspringdata   | vpspringcloud  | 1       | 2019-07-21 23:20:00.0  | 2            |
| vpspringdata   | vpspringboot   | 0       | 2019-07-23 23:19:00.0  | 2            |
| vpspringcloud  | vpspringboot   | 1       | 2019-07-18 23:19:00.0  | 1            |
| vpspringcloud  | vpspringdata   | 0       | 2019-07-18 23:20:00.0  | 1            |
| vpspringcloud  | vpspringroo    | 1       | 2019-07-19 22:19:00.0  | 2            |
| vpspringcloud  | vpspringboot   | 1       | 2019-07-20 23:19:00.0  | 3            |
| vpspringcloud  | vpspringdata   | 0       | 2019-07-21 23:20:00.0  | 3            |
| vpspringcloud  | vpspringroo    | 1       | 2019-07-22 22:19:00.0  | 4            |
| vpspringroo    | vpspringcloud  | 0       | 2019-07-19 22:19:00.0  | 0            |
| vpspringroo    | vpspringcloud  | 0       | 2019-07-22 22:19:00.0  | 0            |
| vpspringboot   | vpspringcloud  | 0       | 2019-07-18 23:19:00.0  | 0            |
| vpspringboot   | vpspringdata   | 1       | 2019-07-19 23:19:00.0  | 1            |
| vpspringboot   | vpspringcloud  | 0       | 2019-07-20 23:19:00.0  | 1            |
| vpspringboot   | vpspringdata   | 1       | 2019-07-23 23:19:00.0  | 2            |
+----------------+----------------+---------+------------------------+--------------+--+

之前3場平均勝場

hive> SELECT *,avg(result) over (partition by user_name order by create_time rows between 3 preceding and current row) as recently_wins
hive> From user_match_temp;
+----------------+----------------+---------+------------------------+---------------------+--+
|   user_name    |    opponent    | result  |      create_time       |    recently_wins    |
+----------------+----------------+---------+------------------------+---------------------+--+
| vpspringdata   | vpspringcloud  | 1       | 2019-07-18 23:20:00.0  | 1.0                 |
| vpspringdata   | vpspringboot   | 0       | 2019-07-19 23:19:00.0  | 0.5                 |
| vpspringdata   | vpspringcloud  | 1       | 2019-07-21 23:20:00.0  | 0.6666666666666666  |
| vpspringdata   | vpspringboot   | 0       | 2019-07-23 23:19:00.0  | 0.5                 |
| vpspringcloud  | vpspringboot   | 1       | 2019-07-18 23:19:00.0  | 1.0                 |
| vpspringcloud  | vpspringdata   | 0       | 2019-07-18 23:20:00.0  | 0.5                 |
| vpspringcloud  | vpspringroo    | 1       | 2019-07-19 22:19:00.0  | 0.6666666666666666  |
| vpspringcloud  | vpspringboot   | 1       | 2019-07-20 23:19:00.0  | 0.75                |
| vpspringcloud  | vpspringdata   | 0       | 2019-07-21 23:20:00.0  | 0.5                 |
| vpspringcloud  | vpspringroo    | 1       | 2019-07-22 22:19:00.0  | 0.75                |
| vpspringroo    | vpspringcloud  | 0       | 2019-07-19 22:19:00.0  | 0.0                 |
| vpspringroo    | vpspringcloud  | 0       | 2019-07-22 22:19:00.0  | 0.0                 |
| vpspringboot   | vpspringcloud  | 0       | 2019-07-18 23:19:00.0  | 0.0                 |
| vpspringboot   | vpspringdata   | 1       | 2019-07-19 23:19:00.0  | 0.5                 |
| vpspringboot   | vpspringcloud  | 0       | 2019-07-20 23:19:00.0  | 0.3333333333333333  |
| vpspringboot   | vpspringdata   | 1       | 2019-07-23 23:19:00.0  | 0.5                 |
+----------------+----------------+---------+------------------------+---------------------+--+

我們通過rows between 即可定義視窗的範圍,這裡我們定義了視窗的範圍為之前3行到該行。

累計遇到的對手數量 需要注意的是count(distinct xxx)在視窗函式裡是不允許使用的,不過我們也可以用size(collect_set() over(partition by order by))來替代實現我們的需求。

hive> SELECT *,size(collect_set(opponent) over (partition by user_name order by create_time)) as recently_wins
hive> From user_match_temp;

+----------------+----------------+---------+------------------------+------------------+--+
|   user_name    |    opponent    | result  |      create_time       | opponent_counts  |
+----------------+----------------+---------+------------------------+------------------+--+
| vpspringdata   | vpspringcloud  | 1       | 2019-07-18 23:20:00.0  | 1                |
| vpspringdata   | vpspringboot   | 0       | 2019-07-19 23:19:00.0  | 2                |
| vpspringdata   | vpspringcloud  | 1       | 2019-07-21 23:20:00.0  | 2                |
| vpspringdata   | vpspringboot   | 0       | 2019-07-23 23:19:00.0  | 2                |
| vpspringcloud  | vpspringboot   | 1       | 2019-07-18 23:19:00.0  | 1                |
| vpspringcloud  | vpspringdata   | 0       | 2019-07-18 23:20:00.0  | 2                |
| vpspringcloud  | vpspringroo    | 1       | 2019-07-19 22:19:00.0  | 3                |
| vpspringcloud  | vpspringboot   | 1       | 2019-07-20 23:19:00.0  | 3                |
| vpspringcloud  | vpspringdata   | 0       | 2019-07-21 23:20:00.0  | 3                |
| vpspringcloud  | vpspringroo    | 1       | 2019-07-22 22:19:00.0  | 3                |
| vpspringroo    | vpspringcloud  | 0       | 2019-07-19 22:19:00.0  | 1                |
| vpspringroo    | vpspringcloud  | 0       | 2019-07-22 22:19:00.0  | 1                |
| vpspringboot   | vpspringcloud  | 0       | 2019-07-18 23:19:00.0  | 1                |
| vpspringboot   | vpspringdata   | 1       | 2019-07-19 23:19:00.0  | 2                |
| vpspringboot   | vpspringcloud  | 0       | 2019-07-20 23:19:00.0  | 2                |
| vpspringboot   | vpspringdata   | 1       | 2019-07-23 23:19:00.0  | 2                |
+----------------+----------------+---------+------------------------+------------------+--+

collect_set()也是一個聚合函式,作用是將多行聚合進一行的某個set內,再用size()統計集合內的元素個數,即可實現我們的需求。

分析型視窗函式

分析型即RANk(),ROW_NUMBER(),DENSE_RANK()等常見的排序用的視窗函式,不過他們也是有區別的。

hive> SELECT *,
hive> rank() over (order by create_time) as user_rank,
hive> row_number() over (order by create_time) as user_row_number,
hive> dense_rank() over (order by create_time) as user_dense_rank
hive> FROM user_match_temp;

+----------------+----------------+---------+------------------------+------------+------------------+------------------+--+
|   user_name    |    opponent    | result  |      create_time       | user_rank  | user_row_number  | user_dense_rank  |
+----------------+----------------+---------+------------------------+------------+------------------+------------------+--+
| vpspringcloud  | vpspringboot   | 1       | 2019-07-18 23:19:00.0  | 1          | 1                | 1                |
| vpspringboot   | vpspringcloud  | 0       | 2019-07-18 23:19:00.0  | 1          | 2                | 1                |
| vpspringcloud  | vpspringdata   | 0       | 2019-07-18 23:20:00.0  | 3          | 3                | 2                |
| vpspringdata   | vpspringcloud  | 1       | 2019-07-18 23:20:00.0  | 3          | 4                | 2                |
| vpspringroo    | vpspringcloud  | 0       | 2019-07-19 22:19:00.0  | 5          | 5                | 3                |
| vpspringcloud  | vpspringroo    | 1       | 2019-07-19 22:19:00.0  | 5          | 6                | 3                |
| vpspringdata   | vpspringboot   | 0       | 2019-07-19 23:19:00.0  | 7          | 7                | 4                |
| vpspringboot   | vpspringdata   | 1       | 2019-07-19 23:19:00.0  | 7          | 8                | 4                |
| vpspringcloud  | vpspringboot   | 1       | 2019-07-20 23:19:00.0  | 9          | 9                | 5                |
| vpspringboot   | vpspringcloud  | 0       | 2019-07-20 23:19:00.0  | 9          | 10               | 5                |
| vpspringcloud  | vpspringdata   | 0       | 2019-07-21 23:20:00.0  | 11         | 11               | 6                |
| vpspringdata   | vpspringcloud  | 1       | 2019-07-21 23:20:00.0  | 11         | 12               | 6                |
| vpspringcloud  | vpspringroo    | 1       | 2019-07-22 22:19:00.0  | 13         | 13               | 7                |
| vpspringroo    | vpspringcloud  | 0       | 2019-07-22 22:19:00.0  | 13         | 14               | 7                |
| vpspringdata   | vpspringboot   | 0       | 2019-07-23 23:19:00.0  | 15         | 15               | 8                |
| vpspringboot   | vpspringdata   | 1       | 2019-07-23 23:19:00.0  | 15         | 16               | 8                |
+----------------+----------------+---------+------------------------+------------+------------------+------------------+--+

如上所示:row_number函式:生成連續的序號(相同元素序號相同);rank函式:如兩元素排序相同則序號相同,並且會跳過下一個序號; * rank函式:如兩元素排序相同則序號相同,不會跳過下一個序號;

除了這三個排序用的函式,還有CUME_DIST函式 :小於等於當前值的行在所有行中的佔比PERCENT_RANK() :小於當前值的行在所有行中的佔比 * NTILE() :如果把資料按行數分為n份,那麼該行所屬的份數是第幾份 這三種視窗函式 效果如下:

hive2> SELECT *,
hive2> CUME_DIST() over (order by create_time) as user_CUME_DIST,
hive2> PERCENT_RANK() over (order by create_time) as user_PERCENT_RANK,
hive2> NTILE(3) over (order by create_time) as user_NTILE
hive2> FROM user_match_temp;

+----------------+----------------+---------+------------------------+-----------------+----------------------+-------------+--+
|   user_name    |    opponent    | result  |      create_time       | user_CUME_DIST  |  user_PERCENT_RANK   | user_NTILE  |
+----------------+----------------+---------+------------------------+-----------------+----------------------+-------------+--+
| vpspringcloud  | vpspringboot   | 1       | 2019-07-18 23:19:00.0  | 0.125           | 0.0                  | 1           |
| vpspringboot   | vpspringcloud  | 0       | 2019-07-18 23:19:00.0  | 0.125           | 0.0                  | 1           |
| vpspringcloud  | vpspringdata   | 0       | 2019-07-18 23:20:00.0  | 0.25            | 0.13333333333333333  | 1           |
| vpspringdata   | vpspringcloud  | 1       | 2019-07-18 23:20:00.0  | 0.25            | 0.13333333333333333  | 1           |
| vpspringcloud  | vpspringroo    | 1       | 2019-07-19 22:19:00.0  | 0.375           | 0.26666666666666666  | 1           |
| vpspringroo    | vpspringcloud  | 0       | 2019-07-19 22:19:00.0  | 0.375           | 0.26666666666666666  | 1           |
| vpspringdata   | vpspringboot   | 0       | 2019-07-19 23:19:00.0  | 0.5             | 0.4                  | 2           |
| vpspringboot   | vpspringdata   | 1       | 2019-07-19 23:19:00.0  | 0.5             | 0.4                  | 2           |
| vpspringcloud  | vpspringboot   | 1       | 2019-07-20 23:19:00.0  | 0.625           | 0.5333333333333333   | 2           |
| vpspringboot   | vpspringcloud  | 0       | 2019-07-20 23:19:00.0  | 0.625           | 0.5333333333333333   | 2           |
| vpspringcloud  | vpspringdata   | 0       | 2019-07-21 23:20:00.0  | 0.75            | 0.6666666666666666   | 2           |
| vpspringdata   | vpspringcloud  | 1       | 2019-07-21 23:20:00.0  | 0.75            | 0.6666666666666666   | 3           |
| vpspringcloud  | vpspringroo    | 1       | 2019-07-22 22:19:00.0  | 0.875           | 0.8                  | 3           |
| vpspringroo    | vpspringcloud  | 0       | 2019-07-22 22:19:00.0  | 0.875           | 0.8                  | 3           |
| vpspringdata   | vpspringboot   | 0       | 2019-07-23 23:19:00.0  | 1.0             | 0.9333333333333333   | 3           |
| vpspringboot   | vpspringdata   | 1       | 2019-07-23 23:19:00.0  | 1.0             | 0.9333333333333333   | 3           |
+----------------+----------------+---------+------------------------+-----------------+----------------------+-------------+--+

取值型視窗函式

這幾個函式可以通過字面意思記得,LAG是遲滯的意思,也就是對某一列進行往後錯行;LEAD是LAG的反義詞,也就是對某一列進行提前幾行;FIRST_VALUE是對該列到目前為止的首個值,而LAST_VALUE是到目前行為止的最後一個值。

LAG()和LEAD() 可以帶3個引數,第一個是返回的值,第二個是前置或者後置的行數,第三個是預設值。

下一個對手,上一個對手,最近3局的第一個對手及最後一個對手,如下:

hive> SELECT *,
hive>     lag(opponent,1) 
hive>         over (partition by user_name order by create_time) as lag_opponent,
hive>     lead(opponent,1) over 
hive>         (partition by user_name order by create_time) as lead_opponent,
hive>     first_value(opponent) over (partition by user_name order by create_time rows hive>         between 3 preceding and 3 following) as first_opponent,
hive>     last_value(opponent) over (partition by user_name order by create_time rows hive>         between 3 preceding and 3 following) as last_opponent
hive> From user_match_temp;
+----------------+----------------+---------+------------------------+----------------+----------------+-----------------+----------------+--+
|   user_name    |    opponent    | result  |      create_time       |  lag_opponent  | lead_opponent  | first_opponent  | last_opponent  |
+----------------+----------------+---------+------------------------+----------------+----------------+-----------------+----------------+--+
| vpspringdata   | vpspringcloud  | 1       | 2019-07-18 23:20:00.0  | NULL           | vpspringboot   | vpspringcloud   | vpspringboot   |
| vpspringdata   | vpspringboot   | 0       | 2019-07-19 23:19:00.0  | vpspringcloud  | vpspringcloud  | vpspringcloud   | vpspringboot   |
| vpspringdata   | vpspringcloud  | 1       | 2019-07-21 23:20:00.0  | vpspringboot   | vpspringboot   | vpspringcloud   | vpspringboot   |
| vpspringdata   | vpspringboot   | 0       | 2019-07-23 23:19:00.0  | vpspringcloud  | NULL           | vpspringcloud   | vpspringboot   |
| vpspringcloud  | vpspringboot   | 1       | 2019-07-18 23:19:00.0  | NULL           | vpspringdata   | vpspringboot    | vpspringboot   |
| vpspringcloud  | vpspringdata   | 0       | 2019-07-18 23:20:00.0  | vpspringboot   | vpspringroo    | vpspringboot    | vpspringdata   |
| vpspringcloud  | vpspringroo    | 1       | 2019-07-19 22:19:00.0  | vpspringdata   | vpspringboot   | vpspringboot    | vpspringroo    |
| vpspringcloud  | vpspringboot   | 1       | 2019-07-20 23:19:00.0  | vpspringroo    | vpspringdata   | vpspringboot    | vpspringroo    |
| vpspringcloud  | vpspringdata   | 0       | 2019-07-21 23:20:00.0  | vpspringboot   | vpspringroo    | vpspringdata    | vpspringroo    |
| vpspringcloud  | vpspringroo    | 1       | 2019-07-22 22:19:00.0  | vpspringdata   | NULL           | vpspringroo     | vpspringroo    |
| vpspringroo    | vpspringcloud  | 0       | 2019-07-19 22:19:00.0  | NULL           | vpspringcloud  | vpspringcloud   | vpspringcloud  |
| vpspringroo    | vpspringcloud  | 0       | 2019-07-22 22:19:00.0  | vpspringcloud  | NULL           | vpspringcloud   | vpspringcloud  |
| vpspringboot   | vpspringcloud  | 0       | 2019-07-18 23:19:00.0  | NULL           | vpspringdata   | vpspringcloud   | vpspringdata   |
| vpspringboot   | vpspringdata   | 1       | 2019-07-19 23:19:00.0  | vpspringcloud  | vpspringcloud  | vpspringcloud   | vpspringdata   |
| vpspringboot   | vpspringcloud  | 0       | 2019-07-20 23:19:00.0  | vpspringdata   | vpspringdata   | vpspringcloud   | vpspringdata   |
| vpspringboot   | vpspringdata   | 1       | 2019-07-23 23:19:00.0  | vpspringcloud  | NULL           | vpspringcloud   | vpspringdata   |
+----------------+----------------+---------+------------------------+----------------+----------------+-----------------+----------------+--+

HIVE常用函式

函式比較多在這裡就說一些常用的:

日期函式

1、UNIX時間戳轉日期函式: from_unixtime ***

語法: from_unixtime(bigint unixtime[, string format])
返回值: string
說明: 轉化UNIX時間戳(從1970-01-01 00:00:00 UTC到指定時間的秒數)到當前時區的時間格式

hive> select from_unixtime(1323308943,'yyyyMMdd') from tableName;

20111208

2、獲取當前UNIX時間戳函式: unix_timestamp ***

語法: unix_timestamp()
返回值: bigint
說明: 獲得當前時區的UNIX時間戳

hive> select unix_timestamp() from tableName;

1323309615

3、日期轉UNIX時間戳函式: unix_timestamp ***

語法: unix_timestamp(string date)
返回值: bigint
說明: 轉換格式為"yyyy-MM-dd HH:mm:ss"的日期到UNIX時間戳。如果轉化失敗,則返回0。

hive> select unix_timestamp('2011-12-07 13:01:03') from tableName;

1323234063

4、指定格式日期轉UNIX時間戳函式: unix_timestamp ***

語法: unix_timestamp(string date, string pattern)
返回值: bigint
說明: 轉換pattern格式的日期到UNIX時間戳。如果轉化失敗,則返回0。

hive> select unix_timestamp('20111207 13:01:03','yyyyMMdd HH:mm:ss') from tableName;

1323234063

5、日期時間轉日期函式: to_date ***

語法: to_date(string timestamp)
返回值: string
說明: 返回日期時間欄位中的日期部分。

hive> select to_date('2011-12-08 10:03:01') from tableName;

2011-12-08

6、日期轉年函式: year ***

語法: year(string date)
返回值: int
說明: 返回日期中的年。

hive> select year('2011-12-08 10:03:01') from tableName;

2011

hive> select year('2012-12-08') from tableName;

2012

7、日期轉月函式: month ***

語法: month (string date)
返回值: int
說明: 返回日期中的月份。

hive> select month('2011-12-08 10:03:01') from tableName;

12

hive> select month('2011-08-08') from tableName;

8

8、日期轉天函式: day ****

語法: day (string date)
返回值: int
說明: 返回日期中的天。

hive> select day('2011-12-08 10:03:01') from tableName;

8

hive> select day('2011-12-24') from tableName;

24

9、日期轉小時函式: hour ***

語法: hour (string date)
返回值: int
說明: 返回日期中的小時。

hive> select hour('2011-12-08 10:03:01') from tableName;

10

10、日期轉分鐘函式: minute

語法: minute (string date)
返回值: int
說明: 返回日期中的分鐘。

hive> select minute('2011-12-08 10:03:01') from tableName;

3

11、日期轉秒函式: second

語法: second (string date)
返回值: int
說明: 返回日期中的秒。

hive> select second('2011-12-08 10:03:01') from tableName;

1

12、日期轉周函式: weekofyear

語法: weekofyear (string date)
返回值: int
說明: 返回日期在當前的週數。

hive> select weekofyear('2011-12-08 10:03:01') from tableName;

49

13、日期比較函式: datediff ***

語法: datediff(string enddate, string startdate)
返回值: int
說明: 返回結束日期減去開始日期的天數。

hive> select datediff('2012-12-08','2012-05-09') from tableName;

213

14、日期增加函式: date_add ***

語法: date_add(string startdate, int days)
返回值: string
說明: 返回開始日期startdate增加days天后的日期。

hive> select date_add('2012-12-08',10) from tableName;

2012-12-18

15、日期減少函式: date_sub ***

語法: date_sub (string startdate, int days)
返回值: string
說明: 返回開始日期startdate減少days天后的日期。

hive> select date_sub('2012-12-08',10) from tableName;

2012-11-28

條件函式

1、If函式: if ***

語法: if(boolean testCondition, T valueTrue, T valueFalseOrNull)
返回值: T
說明: 當條件testCondition為TRUE時,返回valueTrue;否則返回valueFalseOrNull

hive> select if(1=2,100,200) from tableName;

200

hive> select if(1=1,100,200) from tableName;

100

2、非空查詢函式: COALESCE

語法: COALESCE(T v1, T v2, …)
返回值: T
說明: 返回引數中的第一個非空值;如果所有值都為NULL,那麼返回NULL

hive> select COALESCE(null,'100','50') from tableName;

100

3、條件判斷函式:CASE ***

語法: CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END
返回值: T
說明:如果a等於b,那麼返回c;如果a等於d,那麼返回e;否則返回f

hive> Select case 100 when 50 then 'tom' when 100 then 'mary' else 'tim' end from tableName;

mary

hive> Select case 200 when 50 then 'tom' when 100 then 'mary' else 'tim' end from tableName;

tim

4、條件判斷函式:CASE ****

語法: CASE WHEN a THEN b [WHEN c THEN d]* [ELSE e] END
返回值: T
說明:如果a為TRUE,則返回b;如果c為TRUE,則返回d;否則返回e

hive> select case when 1=2 then 'tom' when 2=2 then 'mary' else 'tim' end from tableName;

mary

hive> select case when 1=1 then 'tom' when 2=2 then 'mary' else 'tim' end from tableName;

tom

字串函式

1、字串長度函式:length

語法: length(string A)
返回值: int
說明:返回字串A的長度

hive> select length('abcedfg') from tableName;

7

2、字串反轉函式:reverse

語法: reverse(string A)
返回值: string
說明:返回字串A的反轉結果

hive> select reverse('abcedfg') from tableName;

gfdecba

3、字串連線函式:concat ***

語法: concat(string A, string B…)
返回值: string
說明:返回輸入字串連線後的結果,支援任意個輸入字串

hive> select concat('abc','def','gh') from tableName;

abcdefgh

4、帶分隔符字串連線函式:concat_ws ***

語法: concat_ws(string SEP, string A, string B…)
返回值: string
說明:返回輸入字串連線後的結果,SEP表示各個字串間的分隔符

hive> select concat_ws(',','abc','def','gh')from tableName;

abc,def,gh

5、字串擷取函式:substr,substring ****

語法: substr(string A, int start),substring(string A, int start)
返回值: string
說明:返回字串A從start位置到結尾的字串

hive> select substr('abcde',3) from tableName;

cde

hive> select substring('abcde',3) from tableName;

cde

hive> select substr('abcde',-1) from tableName; (和ORACLE相同)

e

6、字串擷取函式:substr,substring ****

語法: substr(string A, int start, int len),substring(string A, int start, int len)
返回值: string
說明:返回字串A從start位置開始,長度為len的字串

hive> select substr('abcde',3,2) from tableName;

cd

hive> select substring('abcde',3,2) from tableName;

cd

hive>select substring('abcde',-2,2) from tableName;

de

7、字串轉大寫函式:upper,ucase ****

語法: upper(string A) ucase(string A)
返回值: string
說明:返回字串A的大寫格式

hive> select upper('abSEd') from tableName;

ABSED

hive> select ucase('abSEd') from tableName;

ABSED

8、字串轉小寫函式:lower,lcase ***

語法: lower(string A) lcase(string A)
返回值: string
說明:返回字串A的小寫格式

hive> select lower('abSEd') from tableName;

absed

hive> select lcase('abSEd') from tableName;

absed

9、去空格函式:trim ***

語法: trim(string A)
返回值: string
說明:去除字串兩邊的空格

hive> select trim(' abc ') from tableName;

abc

10、左邊去空格函式:ltrim

語法: ltrim(string A)
返回值: string
說明:去除字串左邊的空格

hive> select ltrim(' abc ') from tableName;

abc

11、右邊去空格函式:rtrim

語法: rtrim(string A)
返回值: string
說明:去除字串右邊的空格

hive> select rtrim(' abc ') from tableName;

abc

12、正則表示式替換函式:regexp_replace

語法: regexp_replace(string A, string B, string C)
返回值: string
說明:將字串A中的符合java正則表示式B的部分替換為C。注意,在有些情況下要使用轉義字元,類似oracle中的regexp_replace函式。

hive> select regexp_replace('foobar', 'oo|ar', '') from tableName;

fb

13、正則表示式解析函式:regexp_extract

語法: regexp_extract(string subject, string pattern, int index)
返回值: string
說明:將字串subject按照pattern正則表示式的規則拆分,返回index指定的字元。

hive> select regexp_extract('foothebar', 'foo(.*?)(bar)', 1) from tableName;

the

hive> select regexp_extract('foothebar', 'foo(.*?)(bar)', 2) from tableName;

bar

hive> select regexp_extract('foothebar', 'foo(.*?)(bar)', 0) from tableName;

foothebar

strong>注意,在有些情況下要使用轉義字元,下面的等號要用雙豎線轉義,這是java正則表示式的規則。

select data_field,

regexp_extract(data_field,'.*?bgStart\\=([^&]+)',1) as aaa,

regexp_extract(data_field,'.*?contentLoaded_headStart\\=([^&]+)',1) as bbb,

regexp_extract(data_field,'.*?AppLoad2Req\\=([^&]+)',1) as ccc

from pt_nginx_loginlog_st

where pt = '2012-03-26' limit 2;

14、URL解析函式:parse_url ****

語法: parse_url(string urlString, string partToExtract [, string keyToExtract])
返回值: string
說明:返回URL中指定的部分。partToExtract的有效值為:HOST, PATH, QUERY, REF, PROTOCOL, AUTHORITY, FILE, and USERINFO.

hive> select parse_url

('https://www.tableName.com/path1/p.php?k1=v1&k2=v2#Ref1', 'HOST')

from tableName;

hive> select parse_url

('https://www.tableName.com/path1/p.php?k1=v1&k2=v2#Ref1', 'QUERY', 'k1')

from tableName;

v1

15、json解析函式:get_json_object ****

語法: get_json_object(string json_string, string path)
返回值: string
說明:解析json的字串json_string,返回path指定的內容。如果輸入的json字串無效,那麼返回NULL。

hive> select get_json_object('{"store":{"fruit":\[{"weight":8,"type":"apple"},{"weight":9,"type":"pear"}], "bicycle":{"price":19.95,"color":"red"} },"email":"amy@only_for_json_udf_test.net","owner":"amy"}','$.owner') from tableName;

16、空格字串函式:space

語法: space(int n)
返回值: string
說明:返回長度為n的字串

hive> select space(10) from tableName;

hive> select length(space(10)) from tableName;

10

17、重複字串函式:repeat ***

語法: repeat(string str, int n)
返回值: string
說明:返回重複n次後的str字串

hive> select repeat('abc',5) from tableName;

abcabcabcabcabc

18、首字元ascii函式:ascii

語法: ascii(string str)
返回值: int
說明:返回字串str第一個字元的ascii碼

hive> select ascii('abcde') from tableName;

97

19、左補足函式:lpad

語法: lpad(string str, int len, string pad)
返回值: string
說明:將str進行用pad進行左補足到len位

hive> select lpad('abc',10,'td') from tableName;

tdtdtdtabc

注意:與GP,ORACLE不同,pad 不能預設

20、右補足函式:rpad

語法: rpad(string str, int len, string pad)
返回值: string
說明:將str進行用pad進行右補足到len位

hive> select rpad('abc',10,'td') from tableName;

abctdtdtdt

21、分割字串函式: split ****

語法: split(string str, string pat)
返回值: array
說明: 按照pat字串分割str,會返回分割後的字串陣列

hive> select split('abtcdtef','t') from tableName;

["ab","cd","ef"]

22、集合查詢函式: find_in_set

語法: find_in_set(string str, string strList)
返回值: int
說明: 返回str在strlist第一次出現的位置,strlist是用逗號分割的字串。如果沒有找該str字元,則返回0

hive> select find_in_set('ab','ef,ab,de') from tableName;

2

hive> select find_in_set('at','ef,ab,de') from tableName;

0

集合統計函式

1、個數統計函式: count ***

語法: count(*), count(expr), count(DISTINCT expr[, expr_.])
返回值: int
說明: count(*)統計檢索出的行的個數,包括NULL值的行;count(expr)返回指定欄位的非空值的個數;count(DISTINCT expr[, expr_.])返回指定欄位的不同的非空值的個數

hive> select count(*) from tableName;

20

hive> select count(distinct t) from tableName;

10

2、總和統計函式: sum ***

語法: sum(col), sum(DISTINCT col)
返回值: double
說明: sum(col)統計結果集中col的相加的結果;sum(DISTINCT col)統計結果中col不同值相加的結果

hive> select sum(t) from tableName;

100

hive> select sum(distinct t) from tableName;

70

3、平均值統計函式: avg ***

語法: avg(col), avg(DISTINCT col)
返回值: double
說明: avg(col)統計結果集中col的平均值;avg(DISTINCT col)統計結果中col不同值相加的平均值

hive> select avg(t) from tableName;

50

hive> select avg (distinct t) from tableName;

30

4、最小值統計函式: min ***

語法: min(col)
返回值: double
說明: 統計結果集中col欄位的最小值

hive> select min(t) from tableName;

20

5、最大值統計函式: max ***

語法: maxcol)
返回值: double
說明: 統計結果集中col欄位的最大值

hive> select max(t) from tableName;

120

6、非空集合總體變數函式: var_pop

語法: var_pop(col)
返回值: double
說明: 統計結果集中col非空集合的總體變數(忽略null)

7、非空集合樣本變數函式: var_samp

語法: var_samp (col)
返回值: double
說明: 統計結果集中col非空集合的樣本變數(忽略null)

8、總體標準偏離函式: stddev_pop

語法: stddev_pop(col)
返回值: double
說明: 該函式計算總體標準偏離,並返回總體變數的平方根,其返回值與VAR_POP函式的平方根相同

9、樣本標準偏離函式: stddev_samp

語法: stddev_samp (col)
返回值: double
說明: 該函式計算樣本標準偏離

10.中位數函式: percentile

語法: percentile(BIGINT col, p)
返回值: double
說明: 求準確的第pth個百分位數,p必須介於0和1之間,但是col欄位目前只支援整數,不支援浮點數型別

11、中位數函式: percentile

語法: percentile(BIGINT col, array(p1 [, p2]…))
返回值: array<double>
說明: 功能和上述類似,之後後面可以輸入多個百分位數,返回型別也為array<double>,其中為對應的百分位數。

select percentile(score,&lt;0.2,0.4>) from tableName; 取0.2,0.4位置的資料

12、近似中位數函式: percentile_approx

語法: percentile_approx(DOUBLE col, p [, B])
返回值: double
說明: 求近似的第pth個百分位數,p必須介於0和1之間,返回型別為double,但是col欄位支援浮點型別。引數B控制記憶體消耗的近似精度,B越大,結果的準確度越高。預設為10,000。當col欄位中的distinct值的個數小於B時,結果為準確的百分位數

13、近似中位數函式: percentile_approx

法: percentile_approx(DOUBLE col, array(p1 [, p2]…) [, B])
返回值: array<double>
說明: 功能和上述類似,之後後面可以輸入多個百分位數,返回型別也為array<double>,其中為對應的百分位數。

14、直方圖: histogram_numeric

語法: histogram_numeric(col, b)
返回值: array<struct {‘x’,‘y’}>
說明: 以b為基準計算col的直方圖資訊。

hive> select histogram_numeric(100,5) from tableName;

[{"x":100.0,"y":1.0}]

複合型別構建操作

1、Map型別構建: map ****

語法: map (key1, value1, key2, value2, …)
說明:根據輸入的key和value對構建map型別

hive> Create table mapTable as select map('100','tom','200','mary') as t from tableName;

hive> describe mapTable;

t map<string ,string>

hive> select t from tableName;

{"100":"tom","200":"mary"}

2、Struct型別構建: struct

語法: struct(val1, val2, val3, …)
說明:根據輸入的引數構建結構體struct型別

hive> create table struct_table as select struct('tom','mary','tim') as t from tableName;

hive> describe struct_table;

t struct<col1:string ,col2:string,col3:string>

hive> select t from tableName;

{"col1":"tom","col2":"mary","col3":"tim"}

3、array型別構建: array

語法: array(val1, val2, …)
說明:根據輸入的引數構建陣列array型別

hive> create table arr_table as select array("tom","mary","tim") as t from tableName;

hive> describe tableName;

t array<string>

hive> select t from tableName;

["tom","mary","tim"]

複雜型別訪問操作 ****

1、array型別訪問: A[n]

語法: A[n]
操作型別: A為array型別,n為int型別
說明:返回陣列A中的第n個變數值。陣列的起始下標為0。比如,A是個值為['foo', 'bar']的陣列型別,那麼A[0]將返回'foo',而A[1]將返回'bar'

hive> create table arr_table2 as select array("tom","mary","tim") as t

from tableName;

hive> select t[0],t[1] from arr_table2;

tom mary tim

2、map型別訪問: M[key]

語法: M[key]
操作型別: M為map型別,key為map中的key值
說明:返回map型別M中,key值為指定值的value值。比如,M是值為{'f' -> 'foo', 'b' -> 'bar', 'all' -> 'foobar'}的map型別,那麼M['all']將會返回'foobar'

hive> Create table map_table2 as select map('100','tom','200','mary') as t from tableName;

hive> select t['200'],t['100'] from map_table2;

mary tom

3、struct型別訪問: S.x

語法: S.x
操作型別: S為struct型別
說明:返回結構體S中的x欄位。比如,對於結構體struct foobar {int foo, int bar},foobar.foo返回結構體中的foo欄位

hive> create table str_table2 as select struct('tom','mary','tim') as t from tableName;

hive> describe tableName;

t struct<col1:string ,col2:string,col3:string>

hive> select t.col1,t.col3 from str_table2;

tom tim

複雜型別長度統計函式 ****

1.Map型別長度函式: size(Map<k .V>)

語法: size(Map<k .V>)
返回值: int
說明: 返回map型別的長度

hive> select size(t) from map_table2;

2.array型別長度函式: size(Array<T>)

語法: size(Array<T>)
返回值: int
說明: 返回array型別的長度

hive> select size(t) from arr_table2;

3.型別轉換函式 ***

型別轉換函式: cast
語法: cast(expr as <type>)
返回值: Expected "=" to follow "type"
說明: 返回轉換後的資料型別

hive> select cast('1' as bigint) from tableName;

總結

感謝大神的分享:

https://zhuanlan.zhihu.com/p/102502175

https://www.zhihu.com/question/49969423

https://www.zhihu.com/question/38389095/answer/76156388

https://www.jianshu.com/p/4f60f3c923fe

https://www.jianshu.com/p/d68272609bf8

https://cloud.tencent.com/developer/news/362488