目錄java
課程大綱(HIVE加強) 3node
1. Hive基本概念 4python
1.1 Hive簡介 4mysql
1.1.1 什麼是Hive 4angularjs
1.1.2 爲何使用Hive 4web
1.1.3 Hive的特色 4sql
1.2 Hive架構 5shell
1.2.1 架構圖 5數據庫
1.2.2 基本組成 5apache
1.2.3 各組件的基本功能 5
1.3 Hive與Hadoop的關係 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架構及運行機制 |
|
HQL-DDL基本語法 |
|
HQL-DML基本語法 |
|
HIVE的join |
|
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應用實戰能力
Hive是基於Hadoop的一個數據倉庫工具,能夠將結構化的數據文件映射爲一張數據庫表,並提供類SQL查詢功能。
人員學習成本過高
項目週期要求過短
MapReduce實現複雜查詢邏輯開發難度太大
操做接口採用類SQL語法,提供快速開發的能力。
避免了去寫MapReduce,減小開發人員的學習成本。
擴展功能很方便。
Hive能夠自由的擴展集羣的規模,通常狀況下不須要重啓服務。
Hive支持用戶自定義函數,用戶能夠根據本身的需求來實現本身的函數。
良好的容錯性,節點出現問題SQL仍可完成執行。
Jobtracker是hadoop1.x中的組件,它的功能至關於: Resourcemanager+AppMaster
TaskTracker 至關於: Nodemanager + yarnchild
Hive利用HDFS存儲數據,利用MapReduce查詢數據
總結:hive具備sql數據庫的外表,但應用場景徹底不一樣,hive只適合用來作批量數據統計分析
1、Hive中全部的數據都存儲在 HDFS 中,沒有專門的數據存儲格式(可支持Text,SequenceFile,ParquetFile,RCFILE等)
2、只須要在建立表的時候告訴 Hive 數據中的列分隔符和行分隔符,Hive 就能夠解析數據。
3、Hive 中包含如下數據模型:DB、Table,External Table,Partition,Bucket。
² db:在hdfs中表現爲${hive.metastore.warehouse.dir}目錄下一個文件夾
² table:在hdfs中表現所屬db目錄下一個文件夾
² external table:外部表, 與table相似,不過其數據存放位置能夠在任意指定路徑
普通表: 刪除表後, hdfs上的文件都刪了
External外部表刪除後, hdfs上的文件沒有刪除, 只是把文件刪除了
² partition:在hdfs中表現爲table目錄下的子目錄
² bucket:桶, 在hdfs中表現爲同一個表目錄下根據hash散列以後的多個文件, 會根據不一樣的文件把數據放到不一樣的文件中
單機版:
元數據庫mysql版:
bin/hive
啓動方式,(假如是在hadoop01上):
啓動爲前臺:bin/hiveserver2
啓動爲後臺:nohup bin/hiveserver2 1>/var/log/hiveserver.log 2>/var/log/hiveserver.err &
啓動成功後,能夠在別的節點上用beeline去鏈接
v 方式(1)
hive/bin/beeline 回車,進入beeline的命令界面
輸入命令鏈接hiveserver2
beeline> !connect jdbc:hive2//mini1:10000
(hadoop01是hiveserver2所啓動的那臺主機名,端口默認是10000)
v 方式(2)
或者啓動就鏈接:
bin/beeline -u jdbc:hive2://mini1:10000 -n hadoop
接下來就能夠作正常sql查詢了
[hadoop@hdp-node-02 ~]$ hive -e ‘sql’
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]
說明:
一、 CREATE TABLE 建立一個指定名字的表。若是相同名字的表已經存在,則拋出異常;用戶能夠用 IF NOT EXISTS 選項來忽略這個異常。
二、 EXTERNAL關鍵字可讓用戶建立一個外部表,在建表的同時指定一個指向實際數據的路徑(LOCATION),Hive 建立內部表時,會將數據移動到數據倉庫指向的路徑;若建立外部表,僅記錄數據所在的路徑,不對數據的位置作任何改變。在刪除表的時候,內部表的元數據和數據會被一塊兒刪除,而外部表只刪除元數據,不刪除數據。
三、 LIKE 容許用戶複製現有的表結構,可是不復制數據。
四、 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 肯定表的具體的列的數據。
五、 STORED AS
SEQUENCEFILE|TEXTFILE|RCFILE
若是文件數據是純文本,可使用 STORED AS TEXTFILE。若是數據須要壓縮,使用 STORED AS SEQUENCEFILE。
六、CLUSTERED BY
對於每個表(table)或者分區, Hive能夠進一步組織成桶,也就是說桶是更爲細粒度的數據範圍劃分。Hive也是 針對某一列進行桶的組織。Hive採用對列值哈希,而後除以桶的個數求餘的方式決定該條記錄存放在哪一個桶當中。
把表(或者分區)組織成桶(Bucket)有兩個理由:
(1)得到更高的查詢處理效率。桶爲表加上了額外的結構,Hive 在處理有些查詢時能利用這個結構。具體而言,鏈接兩個在(包含鏈接列的)相同列上劃分了桶的表,可使用 Map 端鏈接 (Map-side join)高效的實現。好比JOIN操做。對於JOIN操做兩個表有一個相同的列,若是對這兩個表都進行了桶操做。那麼將保存相同列值的桶進行JOIN操做就能夠,能夠大大較少JOIN的數據量。
(2)使取樣(sampling)更高效。在處理大規模數據集時,在開發和修改查詢的階段,若是能在數據集的一小部分數據上試運行查詢,會帶來不少方便。
一、 建立內部表mytable。
二、 建立外部表pageview。
三、 建立分區表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; |
四、 建立帶桶的表student。
ü 語法結構
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]
ü 具體實例
show tables
show databases
show partitions
show functions
desc extended t_name;
desc formatted table_name;
語法結構
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO
TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
說明:
一、 Load 操做只是單純的複製/移動操做,將數據文件移動到 Hive 表對應的位置。
二、 filepath:
相對路徑,例如:project/data1
絕對路徑,例如:/user/hive/project/data1
包含模式的完整 URI,列如:
hdfs://namenode:9000/user/hive/project/data1
三、 LOCAL關鍵字
若是指定了 LOCAL, load 命令會去查找本地文件系統中的 filepath。
若是沒有指定 LOCAL 關鍵字,則根據inpath中的uri查找文件
四、 OVERWRITE 關鍵字
若是使用了 OVERWRITE 關鍵字,則目標表(或者分區)中的內容會被刪除,而後再將 filepath 指向的文件/目錄中的內容添加到表/分區中。
若是目標表(分區)已經有一個文件,而且文件名和 filepath 中的文件名衝突,那麼現有的文件會被新文件所替代。
具體實例
一、 加載相對路徑數據。
二、 加載絕對路徑數據。
三、 加載包含模式數據。
四、 OVERWRITE關鍵字使用。
將查詢結果插入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。
基本的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]
注:1、order by 會對輸入作全局排序,所以只有一個reducer,會致使當輸入規模較大時,須要較長的計算時間。
2、sort by不是全局排序,其在數據進入reducer前完成排序。所以,若是用sort by進行排序,而且設置mapred.reduce.tasks>1,則sort by只保證每一個reducer的輸出有序,不保證全局有序。
3、distribute by根據distribute by指定的內容將數據分到同一個reducer。
4、Cluster by 除了具備Distribute by的功能外,還會對該字段進行排序。所以,經常認爲cluster by = distribute by + sort by
ü 具體實例
1、獲取年齡大的3個學生。
2、查詢學生信息按年齡,降序排序。
3、按學生名稱彙總學生年齡。
語法結構
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。
3.join 時,每次 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
具體實例
一、 獲取已經分配班級的學生姓名。
二、 獲取還沒有分配班級的學生姓名。
三、 LEFT SEMI JOIN是IN/EXISTS的高效實現。
語法結構
hive [-hiveconf x=y]* [<-i filename>]* [<-f filename>|<-e query-string>] [-S]
說明:
一、 -i 從文件初始化HQL。
二、 -e從命令行執行指定的HQL
三、 -f 執行HQL腳本
四、 -v 輸出執行的HQL語句到控制檯
五、 -p <port> connect to Hive Server on port number
六、 -hiveconf x=y Use this to set hive/hadoop configuration variables.
具體實例
1、運行一個查詢。
2、運行一個文件。
3、運行參數文件。
Hive參數大全:
https://cwiki.apache.org/confluence/display/Hive/Configuration+Properties
開發Hive應用時,不可避免地須要設定Hive的參數。設定Hive的參數能夠調優HQL代碼的執行效率,或幫助定位問題。然而實踐中常常遇到的一個問題是,爲何設定的參數沒有起做用?這一般是錯誤的設定方式致使的。
對於通常參數,有如下三種設定方式:
l 配置文件
l 命令行參數
l 參數聲明
配置文件:Hive的配置文件包括
l 用戶自定義配置文件:$HIVE_CONF_DIR/hive-site.xml
l 默認配置文件:$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創建之前已經完成了。
內容較多,見《Hive官方文檔》
內容較多,見《Hive官方文檔》
當Hive提供的內置函數沒法知足你的業務處理須要時,此時就能夠考慮使用用戶自定義函數(UDF:user-defined function)。
UDF 做用於單個數據行,產生一個數據行做爲輸出。(數學函數,字符串函數)
UDAF(用戶定義彙集函數):接收多個輸入數據行,併產生一個輸出數據行。(count,max)
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包添加到hive的classpath
hive>add JAR /home/hadoop/udf.jar;
四、建立臨時函數與開發好的java class關聯
Hive>create temporary function toprovince as 'cn.itcast.bigdata.udf.ToProvince'; |
五、便可在hql中使用自定義的函數strip
Select strip(name),age from t_test;
Hive的 TRANSFORM 關鍵字提供了在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'; |
ü 對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;
|
從web日誌中統計每日訪客平均停留時間
一、 因爲要從大量請求中分辨出用戶的各次訪問,邏輯相對複雜,經過hive直接實現有困難,所以編寫一個mr程序來求出訪客訪問信息(詳見代碼)
啓動mr程序獲取結果:
[hadoop@hdp-node-01 ~]$ hadoop jar weblog.jar cn.itcast.bigdata.hive.mr.UserStayTime /weblog/input /weblog/stayout |
二、 將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;
有以下訪客訪問次數統計表 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; |