1. 程式人生 > 程式設計 >Hive 系列(七)—— Hive 常用 DML 操作

Hive 系列(七)—— Hive 常用 DML 操作

一、載入檔案資料到表

1.1 語法

LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] 
INTO TABLE tablename [PARTITION (partcol1=val1,partcol2=val2 ...)]
複製程式碼
  • LOCAL 關鍵字代表從本地檔案系統載入檔案,省略則代表從 HDFS 上載入檔案:
  • 從本地檔案系統載入檔案時, filepath 可以是絕對路徑也可以是相對路徑 (建議使用絕對路徑);

  • 從 HDFS 載入檔案時候,filepath 為檔案完整的 URL 地址:如 hdfs://namenode:port/user/hive/project/ data1

  • filepath 可以是檔案路徑 (在這種情況下 Hive 會將檔案移動到表中),也可以目錄路徑 (在這種情況下,Hive 會將該目錄中的所有檔案移動到表中);

  • 如果使用 OVERWRITE 關鍵字,則將刪除目標表(或分割槽)的內容,使用新的資料填充;不使用此關鍵字,則資料以追加的方式加入;

  • 載入的目標可以是表或分割槽。如果是分割槽表,則必須指定載入資料的分割槽;

  • 載入檔案的格式必須與建表時使用 STORED AS 指定的儲存格式相同。

使用建議:

不論是本地路徑還是 URL 都建議使用完整的。雖然可以使用不完整的 URL 地址,此時 Hive 將使用 hadoop 中的 fs.default.name 配置來推斷地址,但是為避免不必要的錯誤,建議使用完整的本地路徑或 URL 地址;

載入物件是分割槽表時建議顯示指定分割槽。在 Hive 3.0 之後,內部將載入 (LOAD) 重寫為 INSERT AS SELECT,此時如果不指定分割槽,INSERT AS SELECT 將假設最後一組列是分割槽列,如果該列不是表定義的分割槽,它將丟擲錯誤。為避免錯誤,還是建議顯示指定分割槽。

1.2 示例

新建分割槽表:

  CREATE TABLE emp_ptn(
    empno INT,ename STRING,job STRING,mgr INT,hiredate TIMESTAMP,sal DECIMAL(7,2),comm DECIMAL(7,2)
    )
    PARTITIONED BY
(deptno INT) -- 按照部門編號進行分割槽 ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"; 複製程式碼

從 HDFS 上載入資料到分割槽表:

LOAD DATA  INPATH "hdfs://hadoop001:8020/mydir/emp.txt" OVERWRITE INTO TABLE emp_ptn PARTITION (deptno=20);
複製程式碼

emp.txt 檔案可在本倉庫的 resources 目錄中下載

載入後表中資料如下,分割槽列 deptno 全部賦值成 20:

https://github.com/heibaiying

二、查詢結果插入到表

2.1 語法

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

INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1,partcol2=val2 ...)] 
select_statement1 FROM from_statement;
複製程式碼
  • Hive 0.13.0 開始,建表時可以通過使用 TBLPROPERTIES(“immutable”=“true”)來建立不可變表 (immutable table) ,如果不可以變表中存在資料,則 INSERT INTO 失敗。(注:INSERT OVERWRITE 的語句不受 immutable 屬性的影響);

  • 可以對錶或分割槽執行插入操作。如果表已分割槽,則必須通過指定所有分割槽列的值來指定表的特定分割槽;

  • 從 Hive 1.1.0 開始,TABLE 關鍵字是可選的;

  • 從 Hive 1.2.0 開始 ,可以採用 INSERT INTO tablename(z,x,c1) 指明插入列;

  • 可以將 SELECT 語句的查詢結果插入多個表(或分割槽),稱為多表插入。語法如下:

    FROM from_statement
    INSERT OVERWRITE TABLE tablename1 
    [PARTITION (partcol1=val1,partcol2=val2 ...) [IF NOT EXISTS]] select_statement1
    [INSERT OVERWRITE TABLE tablename2 [PARTITION ... [IF NOT EXISTS]] select_statement2]
    [INSERT INTO TABLE tablename2 [PARTITION ...] select_statement2] ...;
    複製程式碼

2.2 動態插入分割槽

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

INSERT INTO TABLE tablename PARTITION (partcol1[=val1],partcol2[=val2] ...) 
select_statement FROM from_statement;
複製程式碼

在向分割槽表插入資料時候,分割槽列名是必須的,但是列值是可選的。如果給出了分割槽列值,我們將其稱為靜態分割槽,否則它是動態分割槽。動態分割槽列必須在 SELECT 語句的列中最後指定,並且與它們在 PARTITION() 子句中出現的順序相同。

注意:Hive 0.9.0 之前的版本動態分割槽插入是預設禁用的,而 0.9.0 之後的版本則預設啟用。以下是動態分割槽的相關配置:

配置 預設值 說明
hive.exec.dynamic.partition true 需要設定為 true 才能啟用動態分割槽插入
hive.exec.dynamic.partition.mode strict 在嚴格模式 (strict) 下,使用者必須至少指定一個靜態分割槽,以防使用者意外覆蓋所有分割槽,在非嚴格模式下,允許所有分割槽都是動態的
hive.exec.max.dynamic.partitions.pernode 100 允許在每個 mapper/reducer 節點中建立的最大動態分割槽數
hive.exec.max.dynamic.partitions 1000 允許總共建立的最大動態分割槽數
hive.exec.max.created.files 100000 作業中所有 mapper/reducer 建立的 HDFS 檔案的最大數量
hive.error.on.empty.partition false 如果動態分割槽插入生成空結果,是否丟擲異常

2.3 示例

  1. 新建 emp 表,作為查詢物件表
CREATE TABLE emp(
    empno INT,deptno INT)
    ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t";
    
 -- 載入資料到 emp 表中 這裡直接從本地載入
load data local inpath "/usr/file/emp.txt" into table emp;
複製程式碼

​ 完成後 emp 表中資料如下:

https://github.com/heibaiying

  1. 為清晰演示,先清空 emp_ptn 表中載入的資料:
TRUNCATE TABLE emp_ptn;
複製程式碼
  1. 靜態分割槽演示:從 emp 表中查詢部門編號為 20 的員工資料,並插入 emp_ptn 表中,語句如下:
INSERT OVERWRITE TABLE emp_ptn PARTITION (deptno=20) 
SELECT empno,ename,job,mgr,hiredate,sal,comm FROM emp WHERE deptno=20;
複製程式碼

​ 完成後 emp_ptn 表中資料如下:

https://github.com/heibaiying

  1. 接著演示動態分割槽:
-- 由於我們只有一個分割槽,且還是動態分割槽,所以需要關閉嚴格預設。因為在嚴格模式下,使用者必須至少指定一個靜態分割槽
set hive.exec.dynamic.partition.mode=nonstrict;

-- 動態分割槽   此時查詢語句的最後一列為動態分割槽列,即 deptno
INSERT OVERWRITE TABLE emp_ptn PARTITION (deptno) 
SELECT empno,comm,deptno FROM emp WHERE deptno=30;
複製程式碼

​ 完成後 emp_ptn 表中資料如下:

https://github.com/heibaiying

三、使用SQL語句插入值

INSERT INTO TABLE tablename [PARTITION (partcol1[=val1],partcol2[=val2] ...)] 
VALUES ( value [,value ...] )
複製程式碼
  • 使用時必須為表中的每個列都提供值。不支援只向部分列插入值(可以為預設值的列提供空值來消除這個弊端);
  • 如果目標表表支援 ACID 及其事務管理器,則插入後自動提交;
  • 不支援支援複雜型別 (array,map,struct,union) 的插入。

四、更新和刪除資料

4.1 語法

更新和刪除的語法比較簡單,和關係型資料庫一致。需要注意的是這兩個操作都只能在支援 ACID 的表,也就是事務表上才能執行。

-- 更新
UPDATE tablename SET column = value [,column = value ...] [WHERE expression]

--刪除
DELETE FROM tablename [WHERE expression]
複製程式碼

4.2 示例

1. 修改配置

首先需要更改 hive-site.xml,新增如下配置,開啟事務支援,配置完成後需要重啟 Hive 服務。

<property>
    <name>hive.support.concurrency</name>
    <value>true</value>
</property>
<property>
    <name>hive.enforce.bucketing</name>
    <value>true</value>
</property>
<property>
    <name>hive.exec.dynamic.partition.mode</name>
    <value>nonstrict</value>
</property>
<property>
    <name>hive.txn.manager</name>
    <value>org.apache.hadoop.hive.ql.lockmgr.DbTxnManager</value>
</property>
<property>
    <name>hive.compactor.initiator.on</name>
    <value>true</value>
</property>
<property>
    <name>hive.in.test</name>
    <value>true</value>
</property>
複製程式碼

2. 建立測試表

建立用於測試的事務表,建表時候指定屬性 transactional = true 則代表該表是事務表。需要注意的是,按照官方檔案 的說明,目前 Hive 中的事務表有以下限制:

  • 必須是 buckets Table;
  • 僅支援 ORC 檔案格式;
  • 不支援 LOAD DATA ...語句。
CREATE TABLE emp_ts(  
  empno int,ename String
)
CLUSTERED BY (empno) INTO 2 BUCKETS STORED AS ORC
TBLPROPERTIES ("transactional"="true");
複製程式碼

3. 插入測試資料

INSERT INTO TABLE emp_ts  VALUES (1,"ming"),(2,"hong");
複製程式碼

插入資料依靠的是 MapReduce 作業,執行成功後資料如下:

https://github.com/heibaiying

4. 測試更新和刪除

--更新資料
UPDATE emp_ts SET ename = "lan"  WHERE  empno=1;

--刪除資料
DELETE FROM emp_ts WHERE empno=2;
複製程式碼

更新和刪除資料依靠的也是 MapReduce 作業,執行成功後資料如下:

https://github.com/heibaiying

五、查詢結果寫出到檔案系統

5.1 語法

INSERT OVERWRITE [LOCAL] DIRECTORY directory1
  [ROW FORMAT row_format] [STORED AS file_format] 
  SELECT ... FROM ...
複製程式碼
  • OVERWRITE 關鍵字表示輸出檔案存在時,先刪除後再重新寫入;

  • 和 Load 語句一樣,建議無論是本地路徑還是 URL 地址都使用完整的;

  • 寫入檔案系統的資料被序列化為文字,其中列預設由^A 分隔,行由換行符分隔。如果列不是基本型別,則將其序列化為 JSON 格式。其中行分隔符不允許自定義,但列分隔符可以自定義,如下:

    -- 定義列分隔符為'\t' 
    insert overwrite local directory './test-04' 
    row format delimited 
    FIELDS TERMINATED BY '\t'
    COLLECTION ITEMS TERMINATED BY ','
    MAP KEYS TERMINATED BY ':'
    select * from src;
    複製程式碼

5.2 示例

這裡我們將上面建立的 emp_ptn 表匯出到本地檔案系統,語句如下:

INSERT OVERWRITE LOCAL DIRECTORY '/usr/file/ouput'
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
SELECT * FROM emp_ptn;
複製程式碼

匯出結果如下:

https://github.com/heibaiying

參考資料

  1. Hive Transactions
  2. Hive Data Manipulation Language

更多大資料系列文章可以參見 GitHub 開源專案大資料入門指南