1. 程式人生 > >2018-11-13#Hive外表建立和載入資料

2018-11-13#Hive外表建立和載入資料

hive 關聯表和外表的區別:

1. 外部表需要external關鍵之,location是資料檔案預設存放位置,不管是不管是select 還是load的資料都存放在這裡。匯入資料到外部表,資料並沒有mv到資料倉庫目錄,而是在loacation目錄。

2.內部表建表時也能加上location,作用和外部表一樣,都是表資料的存放路徑,不同的是drop table時內部表會將hdfs上的資料也刪掉,外部表僅僅是刪除表的元資料,原始資料不會刪除。

Hive 外表的優點:

1.安全,外部表不用擔心表刪除帶來的風險。在Hive當中,對於外部表來說,我們在刪除表資料的時候,刪除的僅僅是表的元資料資訊,但是卻不能刪除掉表中的真實資料。
2.靈活,方便資料共享,使用更加靈活。

外部資料

hive> dfs -ls /dw/im/prod/sessionContent;
Found 7 items
drwxr-xr-x   - icosc  hadoop          0 2018-11-07 23:55 /dw/im/prod/sessionContent/2018-11-07
drwxr-x--x   - hadoop hadoop          0 2018-11-08 23:55 /dw/im/prod/sessionContent/2018-11-08
drwxr-x--x   - hadoop hadoop          0 2018-11-09 23:55 /dw/im/prod/sessionContent/2018-11-09
drwxr-x--x   - hadoop hadoop          0 2018-11-10 23:55 /dw/im/prod/sessionContent/2018-11-10
drwxr-x--x   - hadoop hadoop          0 2018-11-11 23:55 /dw/im/prod/sessionContent/2018-11-11
drwxr-x--x   - hadoop hadoop          0 2018-11-12 23:55 /dw/im/prod/sessionContent/2018-11-12
drwxr-x--x   - hadoop hadoop          0 2018-11-13 13:55 /dw/im/prod/sessionContent/2018-11-13
hive>

建立Hive外表

根據資料的存放位置,我在建表 sql 中指定 location

use temp;
create external table tmp_im_session_content(
  `eventType` string comment "會話型別",
  `channelId` int comment "渠道 id",
  `sourceType` int comment "",
  `sessionId` string COMMENT "會話session id",
  `cId` string COMMENT "會話 id",
  `userId` string COMMENT "使用者id",
  `vccId` string COMMENT "企業 id",
  `total` int COMMENT "",
  `index` int COMMENT '標識本次是第幾次傳送會話內容,從1開始 (每次最多傳送10條聊天內容)',
  `content` array<struct<`from`:int,`to`:int,content:string,msgtype:int,`sequence`:bigint,createtime:bigint,errorcode:int,errorstring:string,status:int>> COMMENT '會話內容'
  )
  PARTITIONED BY (`date` string)
  location "/dw/im/prod/sessionContent"
  TBLPROPERTIES ("comment"="IM 會話內容 by gz");

資料裝載和驗證

我們在建表的時候,已經指定了location,但是我們去查的時候,發現並沒有資料。

hive> select
    > a.*
    > from temp.tmp_im_session_content a
    > where `date` = '2018-11-07'
    > limit 40;
OK
Time taken: 0.107 seconds
hive>

為什麼???????????????????

這是因為雖然在HDFS當中資料已經存在了,但是在Hive的元資料倉庫中並沒有,所以我們查不到資料。

給Hive 外表資料倉庫裝載資料

-- 建立分割槽並指定 location
alter table temp.tmp_im_session_content add if not exists partition (`date`='2018-11-07') location '/dw/im/prod/sessionContent/2018-11-07';

-- 驗證資料
select
eventType,
channelId,
sourceType,
sessionId,
cId,
userId,
vccId,
total,
index,
content
from temp.tmp_im_session_content a 
where `date` = '2018-11-07' 
limit 40;

select
a.*
from temp.tmp_im_session_content a 
where `date` = '2018-11-07' 
limit 40;
-- 驗證 ok

修復分割槽

Hive提供了一個"Recover Partition"的功能。原理相當簡單,執行後,Hive會檢測如果HDFS目錄下存在,但表的metastore中不存在的partition元資訊,更新到metastore中。如下:

msck repair table temp.tmp_im_session_content;

問題又來了,查詢:

hive> select
    > a.*
    > from temp.tmp_im_session_content a
    > where `date` = '2018-11-08'
    > limit 40;
OK
Time taken: 0.107 seconds
hive>

還是沒資料。這裡就不得不說源資料存放的格式了。我建立的外表分割槽欄位是 date,但是我們的原始檔路徑是/dw/im/prod/sessionContent/2018-11-08,按照分割槽目錄的格式應該是/dw/im/prod/sessionContent/date=2018-11-08。因此,用修復命令沒起作用。這就要求在寫 HDFS 的時候做好格式約定,避免後續各種意想不到的驚喜 ☹。

這個問題,可以通過下面 laod data inpath 一節瞭解更詳細的內容

laod data inpath 裝載資料

命令如下:

laod data inpath '/dw/im/prod/sessionContent/2018-11-08' overwrite into table temp.tmp_im_session_content PARTITION (`date`='2018-11-08');

看下原始檔狀態:

hive> dfs -ls /dw/im/prod/sessionContent/
    > ;
Found 7 items
drwxr-xr-x   - icosc  hadoop          0 2018-11-07 23:55 /dw/im/prod/sessionContent/2018-11-07
drwxr-x--x   - hadoop hadoop          0 2018-11-09 23:55 /dw/im/prod/sessionContent/2018-11-09
drwxr-x--x   - hadoop hadoop          0 2018-11-10 23:55 /dw/im/prod/sessionContent/2018-11-10
drwxr-x--x   - hadoop hadoop          0 2018-11-11 23:55 /dw/im/prod/sessionContent/2018-11-11
drwxr-x--x   - hadoop hadoop          0 2018-11-12 23:55 /dw/im/prod/sessionContent/2018-11-12
drwxr-x--x   - hadoop hadoop          0 2018-11-13 14:35 /dw/im/prod/sessionContent/2018-11-13
drwxr-x--x   - hadoop hadoop          0 2018-11-08 23:55 /dw/im/prod/sessionContent/date=2018-11-08

發現什麼沒?原來的目錄/dw/im/prod/sessionContent/2018-11-09的目錄不見了,但是多了一個/dw/im/prod/sessionContent/date=2018-11-08的目錄。

前面我們提到,如果分割槽很多的時候,可以通過msck repair table tableName 的方式來修復,但是如果格式不是 Hive 標準的分割槽檔案儲存格式,這個命令就沒什麼卵用。從剛剛的laod data命令我們也可以看出,此命令會移動資料檔案,如果不是標準的問價儲存路徑,也會根據命令進行相應的調整。這一點很重要,需要記住。

如果需要傳遞日期變數,可以:

-- 針對標準的分割槽檔案,即顯示的按照分割槽欄位存放的資料檔案
laod data inpath '/dw/im/prod/sessionContent/date=${date}' overwrite into table temp.tmp_im_session_content PARTITION (`date`='${date}');

OR

-- 針對非標準的,未顯示按照分割槽欄位存放的資料檔案
laod data inpath '/dw/im/prod/sessionContent/${date}' overwrite into table temp.tmp_im_session_content PARTITION (`date`='${date}');

這裡有個小插曲,前面我通過alter table裝載了2018-11-07的資料,目錄沒有變化,因此有用load data的方式處理:

laod data inpath '/dw/im/prod/sessionContent/2018-11-07' overwrite into table temp.tmp_im_session_content PARTITION (`date`='2018-11-07');

因為使用了overwrite INTO,導致/dw/im/prod/sessionContent/date=2018-11-07的資料被刪除了☹️

只好手動將資料又移動回來:

hadoop fs -mv /user/dev/.Trash/181113150000/dw/im/prod/sessionContent/2018-11-07 /dw/im/prod/sessionContent/date=2018-11-07

然後

laod data inpath '/dw/im/prod/sessionContent/date=2018-11-07' into table temp.tmp_im_session_content PARTITION (`date`='2018-11-07');

分割槽管理

從最前面 HDFS 檔案可以看到,還有還6個日期目錄,我可以建立5個 alterr table 的語句來裝載資料,但是如果有365天的資料需要載入呢?如果寫多條365條alter 語句,豈不是很傻?

shell 迴圈建立

這種方式已經寫過,不再贅述,故而此處省略。

load data 方式載入資料

只要load data,資料都會被移動到表的location下面。

刪除外表分割槽管理

-- 刪除分割槽
alter table temp.tmp_im_session_content drop partition(`date`=2018-11-07)

總結

由於我們的源資料目錄沒有顯示的指定分割槽欄位,因此建表的時候沒有指定 location,通過 laod data inpath 命令來裝載資料

  1. load data 命令會移動資料
  2. laod data inpath ... overwrite 命令使用不當會導致資料被刪除,如果看到本文件,可以按照我前面的方式進行處理即可。
  3. 通過 alter table 的方式裝載資料,會將原始檔與 對應的 Hive 表倉庫進行對映,但是不會移動資料,不會改變目錄。