Hive原理總結(完整版)


目錄

課程大綱(HIVE增強) 3

1. Hive基本概念 4

1.1 Hive簡介 4

1.1.1 什么是Hive 4

1.1.2 為什么使用Hive 4

1.1.3 Hive的特點 4

1.2 Hive架構 5

1.2.1 架構圖 5

1.2.2 基本組成 5

1.2.3 各組件的基本功能 5

1.3 HiveHadoop的關系 6

1.4 Hive與傳統數據庫對比 6

1.5 Hive的數據存儲 6

2. Hive基本操作 7

2.1 DDL操作 7

2.1.1 創建表 7

2.1.2 修改表 9

2.1.3 顯示命令 11

2.2 DML操作 11

2.2.1 Load 11

2.2.2 Insert 13

2.2.3 SELECT 15

2.3 Hive Join 18

2.5 Hive Shell使用進階 21

2.5.1 Hive命令行 21

2.5.2. Hive參數配置方式 23

4. Hive函數 24

4.1 內置運算符 24

4.2 內置函數 24

4.3 Hive自定義函數和Transform 24

4.3.1 自定義函數類別 24

4.3.2 UDF開發實例 24

4.3.3 Transform實現 25

5. Hive執行過程實例分析 26

5.1 JOIN 26

5.2 GROUP BY 26

5.3 DISTINCT 27

6. Hive使用注意點(各種小細節) 27

6.1 字符集 27

6.2 壓縮 28

6.3 count(distinct) 28

6.4 子查詢 28

6.5 Join中處理null值的語義區別 28

6.6 分號字符 29

6.7 Insert 29

6.7.1新增數據 29

6.7.2 插入次序 30

6.7.3 初始值 30

7. Hive優化技巧 31

7.1 HADOOP計算框架特性 31

7.2 優化的常用手段概述 31

7.3 全排序 32

7.3.1 1 32

7.3.2 2 34

7.4 怎樣寫exist/in子句 36

7.5 怎樣決定reducer個數 36

7.6 合並MapReduce操作 36

7.7 Bucket  Sampling 37

7.8  Partition優化 38

7.9 JOIN優化 39

7.9.1 JOIN原則 39

7.9.2  Map Join 39

7.10 數據傾斜 40

7.10.1 空值數據傾斜 40

7.10.2 不同數據類型關聯產生數據傾斜 41

7.10.3 大表Join的數據偏斜 41

7.11 合並小文件 42

7.12 Group By 優化 43

7.12.1 Map端部分聚合: 43

7.12.2 有數據傾斜的時候進行負載均衡 43

8. Hive實戰 44

Hive 實戰案例1——數據ETL 44

需求: 44

數據示例: 44

實現步驟: 45

Hive 實戰案例2——訪問時長統計 47

需求: 47

實現步驟: 47

Hive實戰案例3——級聯求和 48

需求: 48

實現步驟 48

 

 

課程大綱(HIVE增強)

 

Hive增強

HIVE基本概念

HIVE架構及運行機制

HQL-DDL基本語法

HQL-DML基本語法

HIVEjoin

HIVE UDF函數

HIVE shell基本操作

HIVE 參數配置

HIVE 自定義函數和Transform

HIVE 執行HQL的實例分析

HIVE最佳實踐注意點

HIVE優化策略

HIVE實戰案例1

HIVE實戰案例2

HIVE實戰案例3

 

 

學習目標:

1、熟練掌握hive的使用

2、熟練掌握hql的編寫

3、理解hive的工作原理

4、具備hive應用實戰能力

 

1. Hive基本概念

1.1  Hive簡介

1.1.1 什么是Hive

Hive是基於Hadoop的一個數據倉庫工具,可以將結構化的數據文件映射為一張數據庫表,並提供類SQL查詢功能。

1.1.2 為什么使用Hive

  • 直接使用hadoop所面臨的問題

人員學習成本太高

項目周期要求太短

MapReduce實現復雜查詢邏輯開發難度太大

 

  • 為什么要使用Hive

操作接口采用類SQL語法,提供快速開發的能力。

避免了去寫MapReduce,減少開發人員的學習成本。

擴展功能很方便。

1.1.3 Hive的特點

  • 可擴展

Hive可以自由的擴展集群的規模,一般情況下不需要重啟服務。

 

  • 延展性

Hive支持用戶自定義函數,用戶可以根據自己的需求來實現自己的函數。

 

  • 容錯

良好的容錯性,節點出現問題SQL仍可完成執行。

1.2  Hive架構

1.2.1 架構圖

 

Jobtracker是hadoop1.x中的組件,它的功能相當於: Resourcemanager+AppMaster

 

TaskTracker 相當於:  Nodemanager  +  yarnchild

 

 

 

 

1.2.2 基本組成

  • 用戶接口包括 CLI、JDBC/ODBC、WebGUI。
  • 元數據存儲通常是存儲在關系數據庫如 mysql , derby
  • 解釋器、編譯器、優化器、執行器
  • 用戶接口主要由三個:CLI、JDBC/ODBC和WebGUI。其中,CLIshell命令行;JDBC/ODBCHiveJAVA實現,與傳統數據庫JDBC類似;WebGUI是通過瀏覽器訪問Hive
  • 元數據存儲:Hive 將元數據存儲在數據庫中。Hive 中的元數據包括表的名字,表的列和分區及其屬性,表的屬性(是否為外部表等),表的數據所在目錄等
  • 解釋器、編譯器、優化器完成 HQL 查詢語句從詞法分析、語法分析、編譯、優化以及查詢計划的生成。生成的查詢計划存儲在 HDFS 中,並在隨后有 MapReduce 調用執行

1.2.3 各組件的基本功能

1.3 HiveHadoop關系 

Hive利用HDFS存儲數據,利用MapReduce查詢數據

 

 

 

1.4 Hive與傳統數據庫對比

 

 

總結hive具有sql數據庫的外表但應用場景完全不同hive只適合用來做批量數據統計分析

1.5 Hive的數據存儲

1Hive中所有的數據都存儲在 HDFS 沒有專門的數據存儲格式(可支持TextSequenceFileParquetFileRCFILE等)

2只需要在創建表的時候告訴 Hive 數據中的列分隔符和行分隔符,Hive 就可以解析數據。

3Hive 中包含以下數據模型:DBTableExternal TablePartitionBucket

² db:在hdfs中表現為${hive.metastore.warehouse.dir}目錄下一個文件夾

² table:在hdfs中表現所屬db目錄下一個文件夾

² external table外部表, table類似,不過其數據存放位置可以在任意指定路徑

普通表: 刪除表后, hdfs上的文件都刪了

External外部表刪除后, hdfs上的文件沒有刪除, 只是把文件刪除了

² partition:在hdfs中表現為table目錄下的子目錄

² bucket, hdfs中表現為同一個表目錄下根據hash散列之后的多個文件, 會根據不同的文件把數據放到不同的文件中

 

 

1.6 HIVE的安裝部署

1.6.1 安裝

單機版:

元數據庫mysql版:

 

1.6.2 使用方式

Hive交互shell

bin/hive

 

 

Hive thrift服務

 

啟動方式,(假如是在hadoop01上):

啟動為前台:bin/hiveserver2

啟動為后台:nohup bin/hiveserver2 1>/var/log/hiveserver.log 2>/var/log/hiveserver.err &

 

啟動成功后,可以在別的節點上用beeline去連接

方式(1

hive/bin/beeline  回車,進入beeline的命令界面

輸入命令連接hiveserver2

beeline> !connect jdbc:hive2//mini1:10000

hadoop01hiveserver2所啟動的那台主機名,端口默認是10000

方式(2

或者啟動就連接:

bin/beeline -u jdbc:hive2://mini1:10000 -n hadoop

 

接下來就可以做正常sql查詢了

 

 

Hive命令

[hadoop@hdp-node-02 ~]$ hive  -e  ‘sql’

 

 

2. Hive基本操作

2.1  DDL操作

2.1.1 創建表

建表語法

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name

   [(col_name data_type [COMMENT col_comment], ...)]

   [COMMENT table_comment]

   [PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]

   [CLUSTERED BY (col_name, col_name, ...)

   [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]

   [ROW FORMAT row_format]

   [STORED AS file_format]

   [LOCATION hdfs_path]

 

說明:

1、 CREATE TABLE 創建一個指定名字的表。如果相同名字的表已經存在,則拋出異常;用戶可以用 IF NOT EXISTS 選項來忽略這個異常

2、 EXTERNAL關鍵字可以讓用戶創建一個外部表,在建表的同時指定一個指向實際數據的路徑(LOCATION),Hive 創建內部表時,會將數據移動到數據倉庫指向的路徑;若創建外部表,僅記錄數據所在的路徑,不對數據的位置做任何改變。在刪除表的時候,內部表的元數據和數據會被一起刪除,而外部表只刪除元數據,不刪除數據。

3、 LIKE 允許用戶復制現有的表結構,但是不復制數據。

4、 ROW FORMAT

DELIMITED [FIELDS TERMINATED BY char] [COLLECTION ITEMS TERMINATED BY char]

        [MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]

   | SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value, property_name=property_value, ...)]

用戶在建表的時候可以自定義 SerDe 或者使用自帶的 SerDe。如果沒有指定 ROW FORMAT 或者 ROW FORMAT DELIMITED,將會使用自帶的 SerDe。在建表的時候,用戶還需要為表指定列,用戶在指定表的列的同時也會指定自定義的 SerDe,Hive通過 SerDe 確定表的具體的列的數據。

5、 STORED AS

SEQUENCEFILE|TEXTFILE|RCFILE

如果文件數據是純文本,可以使用 STORED AS TEXTFILE。如果數據需要壓縮,使用 STORED AS SEQUENCEFILE。

 

6、CLUSTERED BY

對於每一個表(table)或者分區, Hive可以進一步組織成桶,也就是說桶是更為細粒度的數據范圍划分。Hive也是 針對某一列進行桶的組織。Hive采用對列值哈希,然后除以桶的個數求余的方式決定該條記錄存放在哪個桶當中。

把表(或者分區)組織成桶(Bucket)有兩個理由:

1)獲得更高的查詢處理效率。桶為表加上了額外的結構,Hive 在處理有些查詢時能利用這個結構。具體而言,連接兩個在(包含連接列的)相同列上划分了桶的表,可以使用 Map 端連接 (Map-side join)高效的實現。比如JOIN操作。對於JOIN操作兩個表有一個相同的列,如果對這兩個表都進行了桶操作。那么將保存相同列值的桶進行JOIN操作就可以,可以大大較少JOIN的數據量。

2)使取樣(sampling)更高效。在處理大規模數據集時,在開發和修改查詢的階段,如果能在數據集的一小部分數據上試運行查詢,會帶來很多方便。

 

 

具體實例

1、 創建內部表mytable

 

 

2、 創建外部表pageview

 

 

3、 創建分區表invites

create table student_p(Sno int,Sname string,Sex string,Sage int,Sdept string) partitioned by(part string) row format delimited fields terminated by ','stored as textfile;

 

 

 

4、 創建帶桶的表student

 

2.1.2 修改表

增加/刪除分區

ü 語法結構

ALTER TABLE table_name ADD [IF NOT EXISTS] partition_spec [ LOCATION 'location1' ] partition_spec [ LOCATION 'location2' ] ...

partition_spec:

: PARTITION (partition_col = partition_col_value, partition_col = partiton_col_value, ...)

 

ALTER TABLE table_name DROP partition_spec, partition_spec,...

ü 具體實例

alter table student_p add partition(part='a') partition(part='b');

 

 

 

 

重命名表

ü 語法結構

ALTER TABLE table_name RENAME TO new_table_name

ü 具體實例

 

增加/更新列

ü 語法結構

ALTER TABLE table_name ADD|REPLACE COLUMNS (col_name data_type [COMMENT col_comment], ...)

 

注:ADD是代表新增一字段,字段位置在所有列后面(partition列前)REPLACE則是表示替換表中所有字段。

 

ALTER TABLE table_name CHANGE [COLUMN] col_old_name col_new_name column_type [COMMENT col_comment] [FIRST|AFTER column_name]

ü 具體實例

 

2.1.3 顯示命令

show tables

show databases

show partitions

show functions

desc extended t_name;

desc formatted table_name;

2.2  DML操作

2.2.1 Load

 語法結構

LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO

TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]

 

說明:

1、 Load 操作只是單純的復制/移動操作,將數據文件移動到 Hive 表對應的位置。

2、 filepath

相對路徑,例如:project/data1

絕對路徑,例如:/user/hive/project/data1

包含模式的完整 URI,列如:

hdfs://namenode:9000/user/hive/project/data1

3、 LOCAL關鍵字

如果指定了 LOCALload 命令會去查找本地文件系統中的 filepath

如果沒有指定 LOCAL 關鍵字,則根據inpath中的uri查找文件

 

 

4、 OVERWRITE 關鍵字

如果使用了 OVERWRITE 關鍵字,則目標表(或者分區)中的內容會被刪除,然后再將 filepath 指向的文件/目錄中的內容添加到表/分區中。

如果目標表(分區)已經有一個文件,並且文件名和 filepath 中的文件名沖突,那么現有的文件會被新文件所替代。

 

 具體實例

1、 加載相對路徑數據。

 

 

2、 加載絕對路徑數據。

 

 

3、 加載包含模式數據。

 

 

4、 OVERWRITE關鍵字使用。

 

2.2.2 Insert

 將查詢結果插入Hive

ü 語法結構

INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1 FROM from_statement

 

Multiple inserts:

FROM from_statement

INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1

[INSERT OVERWRITE TABLE tablename2 [PARTITION ...] select_statement2] ...

 

Dynamic partition inserts:

INSERT OVERWRITE TABLE tablename PARTITION (partcol1[=val1], partcol2[=val2] ...) select_statement FROM from_statement

 

ü 具體實例

1、基本模式插入。

 

 

 

 

 

 

 

 

 

 

2、多插入模式。

 

 

3、自動分區模式。

 

 

v 導出表數據

ü 語法結構

INSERT OVERWRITE [LOCAL] DIRECTORY directory1 SELECT ... FROM ...

 

 

multiple inserts:

FROM from_statement

INSERT OVERWRITE [LOCAL] DIRECTORY directory1 select_statement1

[INSERT OVERWRITE [LOCAL] DIRECTORY directory2 select_statement2] ...

 

ü 具體實例

1、導出文件到本地。

 

 

說明:

數據寫入到文件系統時進行文本序列化,且每列用^A來區分,\n為換行符。用more命令查看時不容易看出分割符,可以使用: sed -e 's/\x01/|/g' filename來查看。

 

2、導出數據到HDFS

 

2.2.3 SELECT

 基本的Select操作

ü 語法結構

SELECT [ALL | DISTINCT] select_expr, select_expr, ...

FROM table_reference

[WHERE where_condition]

[GROUP BY col_list [HAVING condition]]

[CLUSTER BY col_list

  | [DISTRIBUTE BY col_list] [SORT BY| ORDER BY col_list]

]

[LIMIT number]

 

注:1order by 會對輸入做全局排序,因此只有一個reducer,會導致當輸入規模較大時,需要較長的計算時間。

2sort by不是全局排序,其在數據進入reducer前完成排序。因此,如果用sort by進行排序,並且設置mapred.reduce.tasks>1,則sort by只保證每個reducer的輸出有序,不保證全局有序。

3distribute by根據distribute by指定的內容將數據分到同一個reducer

4Cluster by 除了具有Distribute by的功能外,還會對該字段進行排序。因此,常常認為cluster by = distribute by + sort by

 

 

ü 具體實例

1、獲取年齡大的3個學生。

 

 

2、查詢學生信息按年齡,降序排序。

 

 

 

 

 

3、按學生名稱匯總學生年齡。

 

 

2.3 Hive Join

 語法結構

join_table:

  table_reference JOIN table_factor [join_condition]

  | table_reference {LEFT|RIGHT|FULL} [OUTER] JOIN table_reference join_condition

  | table_reference LEFT SEMI JOIN table_reference join_condition

Hive 支持等值連接(equality joins)、外連接(outer joins)和(left/right joins)。Hive 不支持非等值的連接,因為非等值連接非常難轉化到 map/reduce 任務。

另外,Hive 支持多於 2 個表的連接。

join 查詢時,需要注意幾個關鍵點:

1. 只支持等值join

例如:

  SELECT a.* FROM a JOIN b ON (a.id = b.id)

  SELECT a.* FROM a JOIN b

    ON (a.id = b.id AND a.department = b.department)

是正確的,然而:

  SELECT a.* FROM a JOIN b ON (a.id>b.id)

是錯誤的。

 

2. 可以 join 多於 2 個表。

例如

  SELECT a.val, b.val, c.val FROM a JOIN b

    ON (a.key = b.key1) JOIN c ON (c.key = b.key2)

如果join中多個表的 join key 是同一個,則 join 會被轉化為單個 map/reduce 任務,例如:

  SELECT a.val, b.val, c.val FROM a JOIN b

    ON (a.key = b.key1) JOIN c

    ON (c.key = b.key1)

被轉化為單個 map/reduce 任務,因為 join 中只使用了 b.key1 作為 join key。

SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1)

  JOIN c ON (c.key = b.key2)

而這一 join 被轉化為 2 個 map/reduce 任務。因為 b.key1 用於第一次 join 條件,而 b.key2 用於第二次 join。

   

3join 時,每次 map/reduce 任務的邏輯:

    reducer 會緩存 join 序列中除了最后一個表的所有表的記錄,再通過最后一個表將結果序列化到文件系統。這一實現有助於在 reduce 端減少內存的使用量。實踐中,應該把最大的那個表寫在最后(否則會因為緩存浪費大量內存)。例如:

 SELECT a.val, b.val, c.val FROM a

    JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)

所有表都使用同一個 join key(使用 1 次 map/reduce 任務計算)。Reduce 端會緩存 a 表和 b 表的記錄,然后每次取得一個 c 表的記錄就計算一次 join 結果,類似的還有:

  SELECT a.val, b.val, c.val FROM a

    JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)

這里用了 2 次 map/reduce 任務。第一次緩存 a 表,用 b 表序列化;第二次緩存第一次 map/reduce 任務的結果,然后用 c 表序列化。

 

4.LEFT,RIGHT 和 FULL OUTER 關鍵字用於處理 join 中空記錄的情況

例如:

  SELECT a.val, b.val FROM

a LEFT OUTER  JOIN b ON (a.key=b.key)

對應所有 a 表中的記錄都有一條記錄輸出。輸出的結果應該是 a.val, b.val,當 a.key=b.key 時,而當 b.key 中找不到等值的 a.key 記錄時也會輸出:

a.val, NULL

所以 a 表中的所有記錄都被保留了;

“a RIGHT OUTER JOIN b”會保留所有 b 表的記錄。

 

Join 發生在 WHERE 子句之前。如果你想限制 join 的輸出,應該在 WHERE 子句中寫過濾條件——或是在 join 子句中寫。這里面一個容易混淆的問題是表分區的情況:

  SELECT a.val, b.val FROM a

  LEFT OUTER JOIN b ON (a.key=b.key)

  WHERE a.ds='2009-07-07' AND b.ds='2009-07-07'

join a 表到 b 表(OUTER JOIN),列出 a.val 和 b.val 的記錄。WHERE 從句中可以使用其他列作為過濾條件。但是,如前所述,如果 b 表中找不到對應 a 表的記錄,b 表的所有列都會列出 NULL,包括 ds 列。也就是說,join 會過濾 b 表中不能找到匹配 a 表 join key 的所有記錄。這樣的話,LEFT OUTER 就使得查詢結果與 WHERE 子句無關了。解決的辦法是在 OUTER JOIN 時使用以下語法:

  SELECT a.val, b.val FROM a LEFT OUTER JOIN b

  ON (a.key=b.key AND

      b.ds='2009-07-07' AND

      a.ds='2009-07-07')

這一查詢的結果是預先在 join 階段過濾過的,所以不會存在上述問題。這一邏輯也可以應用於 RIGHT 和 FULL 類型的 join 中。

 

Join 是不能交換位置的。無論是 LEFT 還是 RIGHT join,都是左連接的。

  SELECT a.val1, a.val2, b.val, c.val

  FROM a

  JOIN b ON (a.key = b.key)

  LEFT OUTER JOIN c ON (a.key = c.key)

join a 表到 b 表,丟棄掉所有 join key 中不匹配的記錄,然后用這一中間結果和 c 表做 join。這一表述有一個不太明顯的問題,就是當一個 key 在 a 表和 c 表都存在,但是 b 表中不存在的時候:整個記錄在第一次 join,即 a JOIN b 的時候都被丟掉了(包括a.val1,a.val2和a.key),然后我們再和 c 表 join 的時候,如果 c.key 與 a.key 或 b.key 相等,就會得到這樣的結果:NULL, NULL, NULL, c.val

 

 具體實例

1、 獲取已經分配班級的學生姓名。

 

 

2、 獲取尚未分配班級的學生姓名。

 

 

3、 LEFT  SEMI  JOININ/EXISTS的高效實現。

 

 

 

3 Hive Shell參數

3.1 Hive命令行

 語法結構

hive [-hiveconf x=y]* [<-i filename>]* [<-f filename>|<-e query-string>] [-S]

說明:

1、 -i 從文件初始化HQL

2、 -e從命令行執行指定的HQL

3、 -f 執行HQL腳本

4、 -v 輸出執行的HQL語句到控制台

5、 -p <port> connect to Hive Server on port number

6、 -hiveconf x=y Use this to set hive/hadoop configuration variables.

 具體實例

1、運行一個查詢。

 

 

2、運行一個文件。

 

 

3、運行參數文件。

 

 

3.2 Hive參數配置方式

Hive參數大全:

https://cwiki.apache.org/confluence/display/Hive/Configuration+Properties

 

開發Hive應用時,不可避免地需要設定Hive的參數。設定Hive的參數可以調優HQL代碼的執行效率,或幫助定位問題。然而實踐中經常遇到的一個問題是,為什么設定的參數沒有起作用?這通常是錯誤的設定方式導致的。

 

對於一般參數,有以下三種設定方式:

配置文件 

命令行參數 

參數聲明 

 

配置文件Hive的配置文件包括

用戶自定義配置文件:$HIVE_CONF_DIR/hive-site.xml

默認配置文件:$HIVE_CONF_DIR/hive-default.xml

用戶自定義配置會覆蓋默認配置。

另外,Hive也會讀入Hadoop的配置,因為Hive是作為Hadoop的客戶端啟動的,Hive的配置會覆蓋Hadoop的配置。

配置文件的設定對本機啟動的所有Hive進程都有效。

 

命令行參數:啟動Hive(客戶端或Server方式)時,可以在命令行添加-hiveconf param=value來設定參數,例如:

bin/hive -hiveconf hive.root.logger=INFO,console

這一設定對本次啟動的Session(對於Server方式啟動,則是所有請求的Sessions)有效。

 

參數聲明:可以在HQL中使用SET關鍵字設定參數,例如:

set mapred.reduce.tasks=100;

這一設定的作用域也是session級的。

 

上述三種設定方式的優先級依次遞增。即參數聲明覆蓋命令行參數,命令行參數覆蓋配置文件設定。注意某些系統級的參數,例如log4j相關的設定,必須用前兩種方式設定,因為那些參數的讀取在Session建立以前已經完成了。

 

 

 

4. Hive函數

4.1 內置運算符

內容較多,見《Hive官方文檔

 

4.2 內置函數

內容較多,見《Hive官方文檔

 

 

 

4.3 Hive自定義函數和Transform

Hive提供的內置函數無法滿足你的業務處理需要時,此時就可以考慮使用用戶自定義函數(UDFuser-defined function)。

4.3.1 自定義函數類別

UDF  作用於單個數據行,產生一個數據行作為輸出。(數學函數,字符串函數)

UDAF(用戶定義聚集函數):接收多個輸入數據行,並產生一個輸出數據行。(countmax

 

4.3.2 UDF開發實例

1、先開發一個java類,繼承UDF,並重載evaluate方法

package cn.itcast.bigdata.udf

import org.apache.hadoop.hive.ql.exec.UDF;

import org.apache.hadoop.io.Text;

 

public final class Lower extends UDF{

public Text evaluate(final Text s){

if(s==null){return null;}

return new Text(s.toString().toLowerCase());

}

}

 

2、打成jar包上傳到服務器

3、將jar包添加到hiveclasspath

hive>add JAR /home/hadoop/udf.jar;

4、創建臨時函數與開發好的java class關聯

Hive>create temporary function toprovince as 'cn.itcast.bigdata.udf.ToProvince';

 

5、即可在hql中使用自定義的函數strip 

Select strip(name),age from t_test;

4.3.3 Transform實現

HiveTRANSFORM 關鍵字提供了在SQL中調用自寫腳本的功能

適合實現Hive中沒有的功能又不想寫UDF的情況

 

使用示例1下面這句sql就是借用了weekday_mapper.py對數據進行了處理.

CREATE TABLE u_data_new (

  movieid INT,

  rating INT,

  weekday INT,

  userid INT)

ROW FORMAT DELIMITED

FIELDS TERMINATED BY '\t';

 

add FILE weekday_mapper.py;

 

INSERT OVERWRITE TABLE u_data_new

SELECT

  TRANSFORM (movieid, rating, unixtime,userid)

  USING 'python weekday_mapper.py'

  AS (movieid, rating, weekday,userid)

FROM u_data;

 

其中weekday_mapper.py內容如下

#!/bin/python

import sys

import datetime

 

for line in sys.stdin:

  line = line.strip()

  movieid, rating, unixtime,userid = line.split('\t')

  weekday = datetime.datetime.fromtimestamp(float(unixtime)).isoweekday()

  print '\t'.join([movieid, rating, str(weekday),userid])

 

使用示例2:下面的例子則是使用了shell的cat命令來處理數據

FROM invites a INSERT OVERWRITE TABLE events SELECT TRANSFORM(a.foo, a.bar) AS (oof, rab) USING '/bin/cat' WHERE a.ds > '2008-08-09';

5. Hive實戰

Hive 實戰案例1——數據ETL

需求:

ü web點擊流日志基礎數據表進行etl(按照倉庫模型設計)

ü 按各時間維度統計來源域名top10

已有數據表 “t_orgin_weblog” 

+------------------+------------+----------+--+

|     col_name     | data_type  | comment  |

+------------------+------------+----------+--+

| valid            | string     |          |

| remote_addr      | string     |          |

| remote_user      | string     |          |

| time_local       | string     |          |

| request          | string     |          |

| status           | string     |          |

| body_bytes_sent  | string     |          |

| http_referer     | string     |          |

| http_user_agent  | string     |          |

+------------------+------------+----------+--+

 

 

 

 

數據示例:

| true|1.162.203.134| - | 18/Sep/2013:13:47:35| /images/my.jpg                        | 200| 19939 | "http://www.angularjs.cn/A0d9"                      | "Mozilla/5.0 (Windows   |

 

| true|1.202.186.37 | - | 18/Sep/2013:15:39:11| /wp-content/uploads/2013/08/windjs.png| 200| 34613 | "http://cnodejs.org/topic/521a30d4bee8d3cb1272ac0f" | "Mozilla/5.0 (Macintosh;|

 

 

 

 

實現步驟:

1、對原始數據進行抽取轉換

--將來訪url分離出host  path  query  query id

drop table if exists t_etl_referurl;

create table t_etl_referurl as

SELECT a.*,b.*

FROM t_orgin_weblog a LATERAL VIEW parse_url_tuple(regexp_replace(http_referer, "\"", ""), 'HOST', 'PATH','QUERY', 'QUERY:id') b as host, path, query, query_id

 

 

3、從前述步驟進一步分離出日期時間形成ETL明細表“t_etl_detail”    day tm   

drop table if exists t_etl_detail;

create table t_etl_detail as

select b.*,substring(time_local,0,11) as daystr,

substring(time_local,13) as tmstr,

substring(time_local,4,3) as month,

substring(time_local,0,2) as day,

substring(time_local,13,2) as hour

from t_etl_referurl b;

 

 

 

3、對etl數據進行分區(包含所有數據的結構化信息)

drop table t_etl_detail_prt;

create table t_etl_detail_prt(

valid                   string,

remote_addr            string,

remote_user            string,

time_local               string,

request                 string,

status                  string,

body_bytes_sent         string,

http_referer             string,

http_user_agent         string,

host                   string,

path                   string,

query                  string,

query_id               string,

daystr                 string,

tmstr                  string,

month                  string,

day                    string,

hour                   string)

partitioned by (mm string,dd string);

 

 

 

 

導入數據

insert into table t_etl_detail_prt partition(mm='Sep',dd='18')

select * from t_etl_detail where daystr='18/Sep/2013';

 

insert into table t_etl_detail_prt partition(mm='Sep',dd='19')

select * from t_etl_detail where daystr='19/Sep/2013';

 

分個時間維度統計各referer_host的訪問次數並排序

create table t_refer_host_visit_top_tmp as

select referer_host,count(*) as counts,mm,dd,hh from t_display_referer_counts group by hh,dd,mm,referer_host order by hh asc,dd asc,mm asc,counts desc;

 

 

4、來源訪問次數topn各時間維度URL

取各時間維度的referer_host訪問次數topn

select * from (select referer_host,counts,concat(hh,dd),row_number() over (partition by concat(hh,dd) order by concat(hh,dd) asc) as od from t_refer_host_visit_top_tmp) t where od<=3;

 

 

 

 

 

 

Hive 實戰案例2——訪問時長統計

需求:

web日志中統計每日訪客平均停留時間

實現步驟:

1、 由於要從大量請求中分辨出用戶的各次訪問,邏輯相對復雜,通過hive直接實現有困難,因此編寫一個mr程序來求出訪客訪問信息(詳見代碼)

啟動mr程序獲取結果:

[hadoop@hdp-node-01 ~]$ hadoop jar weblog.jar cn.itcast.bigdata.hive.mr.UserStayTime /weblog/input /weblog/stayout

 

 

2、 mr的處理結果導入hive

drop table t_display_access_info_tmp;

create table t_display_access_info_tmp(remote_addr string,firt_req_time string,last_req_time string,stay_long bigint)

row format delimited fields terminated by '\t';

 

load data inpath '/weblog/stayout4' into table t_display_access_info_tmp;

 

3、得出訪客訪問信息表 "t_display_access_info"

由於有一些訪問記錄是單條記錄,mr程序處理處的結果給的時長是0,所以考慮給單次請求的停留時間一個默認市場30

drop table t_display_access_info;

create table t_display_access_info as

select remote_addr,firt_req_time,last_req_time,

case stay_long

when 0 then 30000

else stay_long

end as stay_long

from t_display_access_info_tmp;

 

 

4、統計所有用戶停留時間平均值

select avg(stay_long) from t_display_access_info;

 

 

 

 

Hive實戰案例3——級聯求和

需求:

有如下訪客訪問次數統計表 t_access_times

訪客

月份

訪問次數

A

2015-01-02

5

A

2015-01-03

15

B

2015-01-01

5

A

2015-01-04

8

B

2015-01-05

25

A

2015-01-06

5

A

2015-02-02

4

A

2015-02-06

6

B

2015-02-06

10

B

2015-02-07

5

……

……

……

 

需要輸出報表:t_access_times_accumulate

訪客

月份

月訪問總計

累計訪問總計

A

2015-01

33

33

A

2015-02

10

43

…….

…….

…….

…….

B

2015-01

30

30

B

2015-02

15

45

…….

…….

…….

…….

 

實現步驟

可以用一個hql語句即可實現:

select A.username,A.month,max(A.salary) as salary,sum(B.salary) as accumulate

from

(select username,month,sum(salary) as salary from t_access_times group by username,month) A

inner join

(select username,month,sum(salary) as salary from t_access_times group by username,month) B

on

A.username=B.username

where B.month <= A.month

group by A.username,A.month

order by A.username,A.month;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM