1. 程式人生 > >study-notes(9 Hive)

study-notes(9 Hive)

這篇文章是將自己所學技術按模組劃分總結而成的筆記,包含了 JavaSE、JavaWeb(SpringMVC、Spring、MyBatis、SpringBoot、SpringCloud 等)、Linux、Hadoop、MapReduce、Hive、Scala、Spark 等,希望通過這些筆記的總結,不僅能讓自己對這些技術的掌握更加深刻,同時也希望能幫助一些其他熱愛技術的人,這些筆記後續會繼續更新,以後自己學習的其他最新技術,也都會以這樣筆記的形式來保留,這些筆記已經共享到 Github,大家可以在那裡下載到 Markdown 檔案,如果大家在看的時候有什麼問題或疑問,可以通過郵箱與我取得聯絡,或者在下面的評論區留言,同時也可以在 Github 上與我進行互動,希望能與大家一起相互學習,相互進步,共同成長。

9 Hive

在 Hive 中,當使用 local 時,表示是本地路徑,當不使用 local 時,表示 HDFS 路徑,當使用 into 時,表示追加寫,當使用 overwrite 時,表示覆蓋寫

9.1 原理

9.1.1 資料倉庫和資料庫的區別

1、資料庫是面向事務而設計,資料倉庫是面向主題而設計

2、資料庫主要用來儲存業務資料,資料倉庫主要用來儲存歷史資料

3、資料庫主要用於捕獲資料,例如捕獲 JavaEE 中頁面傳過來的資料,進行處理後然後進行響應,資料倉庫主要用於分析資料,從資料倉庫中獲取資料,然後進行分析

4、資料庫應儘量避免資料冗餘,資料倉庫有時為了資料分析的方便,會有意地引入資料冗餘

9.2 DDL

CREATE TABLE employee (
NAME string,
salary FLOAT,
subordinated array < string >,
deductions map < string, FLOAT >,
address struct < province:string, city:string, state:string, zip:INT > 
)
partitioned by (province string, state string)
clustered by (salary)
into 4 buckets
ROW
format delimited FIELDS TERMINATED BY '\t' collection items TERMINATED BY ',' map KEYS TERMINATED BY '='; 測試資料 : John Doe 10000.0 Mary Sith,Todd Jones Federal Taxes=0.2,State Taxes=0.1,Insurance=0.1 1 Michigan Ave.,Chicago,IL,60600 Mary Smith 80000.0 Bill King Federal Taxes=0.2,State Taxes=0.05,Insurance=0.1 100 Ontario St.,Chicago,IL,60601 Todd Jones 70000.0 Federal Taxes=0.15,State Taxes=0.03,Insurance=0.1 200 Chicago Ave.,Oak Park,NY,60700 Bill King 60000.0 Federal Taxes=0.15,State Taxes=0.03,Insurance=0.1 300 Obscure Dr.,Obscur,CA,6010

9.2.1 分割槽表

9.2.1.1 分割槽表的好處

分割槽表主要用於輔助查詢,縮小查詢範圍,提高檢索速度,同時可以按照一定的規格和條件對資料進行管理,分割槽表中的每一個分割槽對應的都是一個資料夾,分割槽中的資料對應於資料夾中的資料

9.2.1.2 分割槽表的常用操作

1、將資料從檔案中載入入分割槽表

// 將資料從檔案 file 載入到表 tableName 的分割槽值分別為 partitionValue1、partitionValue2 的分割槽 partitionName1、partitionName2 中
load data local inpath 'file' into table tableName partition(partitionName1='partitionValue1', partitionName2='partitionValue2')

2、將資料動態的插入到分割槽表

// 從表 tableName2 中查詢資料並將其插入到表 tableName2 中的指定分割槽,其中表 tableName1 中的欄位包括 field1、field2,分割槽值分別為 partitionName1、partitionName2
insert into table tableName1 partition (partitionName1, partitionName2) select field1, field2, field3 as partitionName1, field4 as partitionName2 from tableName2;

9.2.2 桶表

9.2.3 桶表的好處

糞桶表可以用於對資料的抽樣調查,同時由於桶表的內部機制,可以減少 join 的次數,從而提高效率,桶表相當於 MapReduce 中的分割槽,每一桶對應於一個檔案,每一桶中的資料對應於每一個檔案中的資料,桶表中通過將桶表中分桶欄位的值與桶的個數進行模運算,從而確定每一條資料處於哪一個桶中

9.2.4 桶表的常用操作

1、在建立桶表時,需要先開啟分桶

set hive.enforce.bucketing = true;

2、設定 reduce 的個數(當在建立桶表的時候指定了桶的個數時也可以不用設定這個引數值,此時 reduce 的個數就等於桶的個數)

set mapreduce.job.reduces=4;

3、將資料插入到桶表

// 從表 tableName2 中將資料查詢出來並將其插入到 tableName1 中
insert into tableName1 select * from tableName2 cluster by (clusterName);

9.2.3 內部表和外部表

9.2.3 內部表和外部表的區別

1、刪除表時,刪除內部表,會將元資料和資料目錄一起刪除,刪除外部表,只會刪除元資料,而資料目錄不會被刪除

2、建立表時,建立內部表會出現在資料庫目錄中,建立外部表不會出現在資料庫目錄中

9.2.4 常用 DDL 命令

9.2.4.1 修改表

1、增加分割槽

alter table tableName add partition(partitionName1=partitionValue1) location '/user/hive/warehouse/databaseName/tableName/partitionName1=partitionValue1' partition(partitionName2=partitionValue2) location '/user/hive/warehouse/databaseName/tableName/partitionName2=partitionValue2'

2、刪除分割槽

alter table tableName drop if exists partition(partitionName1=partitionValue1, partitionName2=partitionValue2)

3、修改分割槽

alter table tableName partition(partitionName=partitionValue) rename to partition(partitionName=newPartitionValue)

4、新增列

alter table tableName add columns(name string)

5、修改列

alter table tableName change id int

alter table tableName change id int after name

alter table tableName change id int first

6、表重新命名

alter table tableName rename to newTableName

7、like

// 建立表 tableName1,其結構與 tableName2 一樣,但沒有資料
create table tableName1 like tableName2

// 建立 tableName1,其結構與 tableName2 一樣,同時資料也和 tableName2 一樣
create table tableName1 as select * from tableName2

9.2 DML

9.2.1 常用 DML 命令

1、insert

// 將從 tableName2 中查到的資料插入到 tableName1 中,其中表 tableName2 查詢結果的結構與表 tableName1 一樣
insert into table tableName1 select * from tableName2

// 將從 tableName1 中查詢到的 id 插入到 tableName2 中,將從 tableName1 中查詢到的 name 插入到 tableName3 中
from tableName1
insert into table tableName2
select id
insert into table tableName3
select name

// 將從 tableName 中查到的資料寫入到本地資料夾 file 中
insert into local directory 'file' select * from tableName

// 將從 tableName1 中查到的 id 寫入到本地資料夾 file1 中,將從 tableName2 中查到的 name 寫入到本地資料夾 file2 中
from tableName1
insert into local directory 'file1'
select id
insert into local directory 'file2'
select name

2、select

// order by : 所有資料進入同一個 reducer 進行處理,並在 reducer 中對資料進行全域性排序,由於只有一個 reducer,所以對於大量資料,將會消耗很長時間去執行
// sort by : 為每一個 reducer 進行排序,保證了資料的區域性有序,接下來再通過一次歸併排序就可以實現全域性有序,可以為全域性排序提高效率
// distribute by : 指定資料在 reducer 端是如何劃分的,例如一個表有 mid、name兩個欄位,當使用 distribute by (mid) 時,所有的 mid 相同的資料會被放到相同的 reducer 中進行處理,一般可以結合 sort by 一起使用
// cluster by : 相當於 distribute by 和 sort by 結合在一起,例如 cluster by (id) 就相當於 distribute by (id) sort by (id)
select * from tableName order by id asc
select * from tableName distribute by (id) sort by (salary)
select * from tableName cluster by (id)

9.3 內建函式

9.3.1 regexp_replace

# 對字串中指定的字串使用指定的分隔符進行替換
select regexp_replace('"http://www.taobao.com/3c/items?id=001&name=book"', '\"', '');

執行結果 :
+--------------------------------------------------+--+
|                       _c0                        |
+--------------------------------------------------+--+
| http://www.taobao.com/3c/items?id=001&name=book  |
+--------------------------------------------------+--+

9.3.2 split

# 將字串以指定的分隔符進行分割
select split('beijing,shanghai,guangzhou,shenzhen', ',');

執行結果 :
+------------------------------------------------+--+
|                      _c0                       |
+------------------------------------------------+--+
| ["beijing","shanghai","guangzhou","shenzhen"]  |
+------------------------------------------------+--+

9.3.3 array

# 生成陣列
select array('a','b','c');

執行結果 :
+----------------+--+
|      _c0       |
+----------------+--+
| ["a","b","c"]  |
+----------------+--+

9.3.4 explode

# 將一個數組中的每一個元素分行顯示
select explode(split('beijing,shanghai,guangzhou,shenzhen', ','));

執行結果 :
+------------+--+
|    col     |
+------------+--+
| beijing    |
| shanghai   |
| guangzhou  |
| shenzhen   |
+------------+--+

9.3.5 parse_url_tuple

# 從一個 url 字串中查詢出主機名、請求路徑、請求引數等資訊
select  parse_url_tuple('http://www.taobao.com/3c/items?id=001&name=book','HOST','PATH', 'QUERY', 'QUERY:name') as (host,path,query,name);

執行結果 :
+-----------------+------------+-------------------+-------+--+
|      host       |    path    |       query       | name  |
+-----------------+------------+-------------------+-------+--+
| www.taobao.com  | /3c/items  | id=001&name=book  | book  |
+-----------------+------------+-------------------+-------+--+

9.3.6 union

# 將兩個表中的資料聯合起來放在一個表中
select 'http://www.taobao.com/3c/items?id=001&name=book' as url union select 'http://www.tmall.com/3c/items?id=001&name=book&date=2018' as url;

+-----------------------------------------------------------+--+
|                          _u2.url                          |
+-----------------------------------------------------------+--+
| http://www.taobao.com/3c/items?id=001&name=book           |
| http://www.tmall.com/3c/items?id=001&name=book&date=2018  |
+-----------------------------------------------------------+--+

9.3.7 lateral view

# 將一個表中的每一條資料都和另一個表中的相應資料連線起來
select a.name, b.* from (select 'zhangsan' as name, 'beijing,shanghai' as location union select 'lisi' as name, '廣州,shenzhen,海南' as location) a lateral view explode(split(location, ',')) b as kkk;

執行結果 :
+-----------+-----------+--+
|  a.name   |   b.kkk   |
+-----------+-----------+--+
| lisi      | 廣州        |
| lisi      | shenzhen  |
| lisi      | 海南        |
| zhangsan  | beijing   |
| zhangsan  | shanghai  |
+-----------+-----------+--+

9.4 UDF

9.4.1 自定義 UDF 函式

  1. 在 pm.xml 中新增相應的依賴
<dependency>
    <groupId>org.apache.hive</groupId>
    <artifactId>hive-jdbc</artifactId>
</dependency>

<dependency>
    <groupId>org.apache.hive</groupId>
    <artifactId>hive-exec</artifactId>
</dependency>
  1. 建立一個類,讓其繼承 UDF,然後重寫 evaluate 方法
/**
 * @author Grayson
 * @date 2018/8/28 21:11
 */
public class DateStartUDF extends UDF {

    /**
     * 計算某天的起始時刻(毫秒數)
     * @return
     */

    public long evaluate() {
        return evaluate(new Date());
    }

    /**
     * 獲取某天的起始時刻(毫秒數)
     * @param date
     * @return
     */

    public long evaluate(Date date) {
        return DateUtil.getStartTimeLong(date);
    }

    /**
     * 獲取某天的起始時刻
     * @param dateString
     * @return
     */

    public long evaluate(String dateString) {
        return evaluate(DateUtil.getDateFromString1(dateString));
    }

    /**
     * 獲取某天的起始時刻
     * @param dateString
     * @param dateFormatString
     * @return
     */

    public long evaluate(String dateString, String dateFormatString) {
        return evaluate(DateUtil.getDateFromStringDefined(dateString, dateFormatString));
    }

}
  1. 將專案打包成 jar 包,然後上傳至伺服器中

  1. 將 jar 包新增至 hive 的 classpath
add jar /usr/local/distribute/hive/udf/app-logs-hive-1.0-SNAPSHOT.jar
  1. 建立函式 5.1 建立臨時函式
# getstartday 為要建立的方法名稱,app.logs.udf.DateStartUDF 為 DateStartUDF 的全限定類名(包括包名和類名)
 create function getstartday as 'app.logs.udf.DateStartUDF'

5.2 建立永久函式 5.2.1 因為 hive 倉庫在 hdfs 上,所以在建立永久函式時,需要將 jar 包上傳到 hdfs 上

#建立目錄
hdfs dfs -mkdir /file/hiveUDF
#將 jar 包上傳到指定目錄
hdfs dfs -put app-logs-hive-1.0-SNAPSHOT.jar /file/hiveUDF

5.2.2 建立永久函式

create function getstartday as 'app.logs.udf.DateStartUDF' using jar 'hdfs:///file/hiveUDF/app-logs-hive-1.0-SNAPSHOT.jar';
  1. 使用函式
select getstartday();

結果為 :

OK
_c0
1535558400000
Time taken: 3.749 seconds, Fetched: 1 row(s)