1. 程式人生 > >Hive內部表與外部表區別,資料匯入與資料讀取方式小結

Hive內部表與外部表區別,資料匯入與資料讀取方式小結

建立一個外部表:

使用'|'作為分隔符,‘\n’回車作為換行符,指定資料倉庫地址

hive> CREATE EXTERNAL TABLE rdcuser (
    > id int,
    > name string,
    > password string
    > )
    > row format delimited fields terminated by '|'
    > LINES TERMINATED BY '\n'
    > stored as textfile
    > location '/linyu/hivetest/';
OK
Time taken: 0.651 seconds


Hive每建立一個表都會在hive.metastore.warehouse.dir指向的目錄下以表名建立一個資料夾,所有屬於這個表的資料都存放在這個資料夾裡面。如果不指定倉庫地址,Hive每建立一個表都會在hive.metastore.warehouse.dir指向的目錄下以表名建立一個資料夾,所有屬於這個表的資料都存放在這個資料夾裡面。

可以切換到mysql檢視該表的倉庫地址:

mysql> use hivemeta;       //hive在mysql的元資料庫

mysql> select * from tbls;

+--------+-------------+-------+------------------+-------+-----------+-------+----------+
| TBL_ID | CREATE_TIME | DB_ID | LAST_ACCESS_TIME | OWNER | RETENTION | SD_ID | TBL_NAME |
+--------+-------------+-------+------------------+-------+-----------+-------+----------+
|     11 |  1439456346 |     1 |                0 | root  |         0 |    11 | rdcuser  |
+--------+-------------+-------+------------------+-------+-----------+-------+----------+


mysql> select * from sds;

+-------+------------------------------------------+------------------------------------+
| SD_ID | INPUT_FORMAT                             | LOCATION                           |
+-------+------------------------------------------+------------------------------------+
|    11 | org.apache.hadoop.mapred.TextInputFormat | hdfs://dmp-nn-1:8020/linyu/hivetest|
+-------+------------------------------------------+------------------------------------+

檢視該目錄:

hive> dfs -ls /linyu/hivetest;

hive>

發現這個目錄現在為空。

新建hivedata1.txt,

內容為:

1|a|b
2|aa|bb

使用load把本地檔案匯入到表中:

注意:使用local表示從本地匯入,使用的是複製操作,原檔案保留,沒有local,表示從hdfs檔案系統匯入,使用的是剪下操作,原目錄下的檔案將被移除。

hive> load data local inpath '/hivedata1.txt' into table rdcuser;
Copying data from file:/hivedata1.txt
Copying file: file:/hivedata1.txt
Loading data to table default.rdcuser
Table default.rdcuser stats: [numFiles=0, numRows=0, totalSize=0, rawDataSize=0]
OK
Time taken: 1.241 seconds

再次檢視該目錄:

hive> dfs -ls /linyu/hivetest;

Found 1 items
-rwxr-xr-x   3 root supergroup         13 2015-08-14 14:59 /linyu/hivetest/hivedata1.txt

該目錄下已經出現此檔案,表示資料已經匯入到表中。

hive> select * from rdcuser;

OK
1       a       b
2       aa      bb
Time taken: 0.504 seconds, Fetched: 2 row(s)

原來,hive的load操作,其實就是把資料檔案移動到對應的表目錄下。

那麼,如果我們不是用load操作,而是直接手動把檔案複製到目錄下會怎麼樣呢?如果檔案的格式與表結構不同,又會如何?

繼續試驗:

新建hivedata2.txt,此檔案使用了','作為分隔符(建表時使用的是'|')

3,aaa,bbb
4,aaaa,bbbb

新建hivedata3.txt,此檔案的資料長短與列定義不符

5|aaaaa|bbbbb|ccccc
6|aaaaaa

手動上傳:

# hadoop fs -put /hivedata2.txt /linyu/hivetest

# hadoop fs -put /hivedata3.txt /linyu/hivetest

再次檢視該目錄:

hive> dfs -ls /linyu/hivetest;

Found 3 items
-rwxr-xr-x   3 root supergroup         13 2015-08-14 14:59 /linyu/hivetest/hivedata1.txt
-rw-r--r--   3 root supergroup         21 2015-08-14 15:12 /linyu/hivetest/hivedata2.txt
-rw-r--r--   3 root supergroup         28 2015-08-14 15:12 /linyu/hivetest/hivedata3.txt

hive> select * from rdcuser;

OK
1       a       b
2       aa      bb
NULL    NULL    NULL
NULL    NULL    NULL
5       aaaaa   bbbbb
6       aaaaaa  NULL
Time taken: 1.566 seconds, Fetched: 6 row(s)


我們發現,所有三個檔案都以表內資料的形式被查出來,而不存在建表分隔符的資料全部被標識為NULL,而長度超過表字段數的資料被遺棄,不足的補NULL。

至此我們已經大致瞭解了hive外部表的資料的儲存與讀取方式。

再試試內部表:

hive> CREATE TABLE rdcuser2 (
    > id int,
    > name string,
    > password string
    > )
    > row format delimited fields terminated by '|'
    > LINES TERMINATED BY '\n'
    > stored as textfile;
OK


由於沒有指定儲存位置,資料會被儲存到上文所述的預設位置:由於沒有指定儲存位置,資料會被儲存到上文所述的預設位置。

在看看元資料:

mysql> select * from tbls;

+--------+-------------+-------+------------------+-------+-----------+-------+----------+
| TBL_ID | CREATE_TIME | DB_ID | LAST_ACCESS_TIME | OWNER | RETENTION | SD_ID | TBL_NAME |
+--------+-------------+-------+------------------+-------+-----------+-------+----------+
|     11 |  1439456346 |     1 |                0 | root  |         0 |    11 | rdcuser  |
|     18 |  1439451526 |     1 |                0 | root  |         0 |    18 | rdcuser2 |
+--------+-------------+-------+------------------+-------+-----------+-------+----------+


mysql> select * from sds;

+-------+------------------------------------------+-------------------------------------------------+
| SD_ID | INPUT_FORMAT                             | LOCATION                                        |
+-------+------------------------------------------+-------------------------------------------------+
|    11 | org.apache.hadoop.mapred.TextInputFormat | hdfs://dmp-nn-1:8020/linyu/hivetest             |
|    18 | org.apache.hadoop.mapred.TextInputFormat | hdfs://dmp-nn-1:8020/user/hive/warehouse/rdcuser|
+-------+------------------------------------------+-------------------------------------------------+

重複上述步驟,來匯入資料,我們會發現,內部表與外部表的資料儲存、讀取方式是相同的,無非就是往對應的hdfs目錄複製檔案,再以定義的表結構來讀取資料。過程不再贅述。

那麼,內部表和外部表的區別在哪裡?

我們再刪除表試試。

先刪除外部表:

hive> drop table rdcuser;

OK
Time taken: 6.054 seconds

再刪除內部表:

hive> drop table rdcuser2;

Moved: 'hdfs://dmp-nn-1:8020/user/hive/warehouse/rdcuser2' to trash at: hdfs://dmp-nn-1:8020/user/root/.Trash/Current
OK
Time taken: 5.822 seconds


很明顯,從命令列返回的過程,刪除內部表多了一步:將該表資料倉庫移除到回收站中(若未開啟回收機制,將被直接刪除)

眼見為實,我們再檢視一下對應的目錄:

hive> dfs -ls /linyu/hivetest;

Found 3 items
-rwxr-xr-x   3 root supergroup         13 2015-08-14 14:59 /linyu/hivetest/hivedata1.txt
-rw-r--r--   3 root supergroup         21 2015-08-14 15:12 /linyu/hivetest/hivedata2.txt
-rw-r--r--   3 root supergroup         28 2015-08-14 15:12 /linyu/hivetest/hivedata3.txt
hive> dfs -ls /user/hive/warehouse/rdcuser2;

外部表的三個資料檔案依然健在。

hive> dfs -ls /user/hive/warehouse/rdcuser2;

ls: `/user/hive/warehouse/rdcuser2': No such file or directory
Command failed with exit code = 1
Query returned non-zero code: 1, cause: null

內部表目錄已經人去樓空。

在看看元資料:

mysql> select * from tbls;

Empty set (0.00 sec)

mysql> select * from sds;

Empty set (0.00 sec)

總結:

1.hive無論是內部表還是外部表,無非就是往對應的hdfs目錄複製檔案,再以定義的表結構來讀取資料。

2.hive刪除內部表時,會連同資料檔案、元資料一起刪除,而外部表僅刪除表裡的元資料,資料檔案不會刪除。