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:

二、查詢結果插入到表

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,
    ename STRING,
    job STRING,
    mgr INT,
    hiredate TIMESTAMP,
    sal DECIMAL(7,2),
    comm DECIMAL(7,2),
    deptno INT)
    ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t";
    
 -- 載入資料到 emp 表中 這裡直接從本地載入
load data local inpath "/usr/file/emp.txt" into table emp;

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

  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 表中資料如下:

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

-- 動態分割槽   此時查詢語句的最後一列為動態分割槽列,即 deptno
INSERT OVERWRITE TABLE emp_ptn PARTITION (deptno) 
SELECT empno,ename,job,mgr,hiredate,sal,comm,deptno FROM emp WHERE deptno=30;

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

三、使用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 作業,執行成功後資料如下:

4. 測試更新和刪除

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

--刪除資料
DELETE FROM emp_ts WHERE empno=2;

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

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

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;

匯出結果如下:

參考資料

  1. Hive Transactions
  2. Hive Data Manipulation Language

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