Apache Hive の LOAD DATA で CSV ファイルをテーブルに読み込む

## 概要

- Apache Hive の LOAD DATA で CSV ファイルをテーブルに読み込む例を示す
- 環境
  - Apache Hive 3.1.2
  - Apache Hadoop 3.2.0
  - Java 8 (OpenJDK 8)
  - Ubuntu 20.10 (Groovy Gorilla)

## LOAD DATA 構文

[LanguageManual DML \- Apache Hive \- Apache Software Foundation](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DML)

```
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)] [INPUTFORMAT 'inputformat' SERDE 'serde']
```

### LOCAL

LOCAL を指定すると、ローカルのファイルシステムにあるファイルを Hadoop ファイルシステムにコピーし、コピーされたファイルは Hive が管理するテーブルデータ置き場に移動する。

[LanguageManual DML \- Apache Hive \- Apache Software Foundation](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DML)

> the load command will try to copy all the files addressed by filepath to the target filesystem. The target file system is inferred by looking at the location attribute of the table. The copied data files will then be moved to the table.

LOCAL を指定しないと、Hadoop ファイルシステムにあるファイルを Hive が管理するテーブルデータ置き場に移動する (元の場所からファイルが消える)。

> Hive will move the files addressed by filepath into the table (or partition)

### OVERWRITE

OVERWRITE を指定すると、テーブルの中身がすべて削除される(パーティション指定の場合は指定したパーティションの中身がすべて削除される)。

[LanguageManual DML \- Apache Hive \- Apache Software Foundation](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DML)

> If the OVERWRITE keyword is used then the contents of the target table (or partition) will be deleted and replaced by the files referred to by filepath; otherwise the files referred by filepath will be added to the table.

## LOAD DATA で CSV ファイルを読み込む例

### データベースとテーブルの準備

データベースを作成。

```
hive> create database foo_database;
OK
Time taken: 1.69 seconds
```

データベースを確認。

```
hive> show databases;
OK
default
foo_database
Time taken: 0.549 seconds, Fetched: 2 row(s)
```

テーブルを作成。

```
hive> create table foo_database.foo_table(
    >   id int,
    >   name string,
    >   updated_at timestamp)
    > row format delimited
    > fields terminated by ','
    > lines terminated by '\n';
OK
Time taken: 1.777 seconds
```

テーブルを確認。

```
hive> show tables from foo_database;
OK
foo_table
Time taken: 0.171 seconds, Fetched: 1 row(s)
```

```
hive> show create table foo_database.foo_table;
OK
CREATE TABLE `foo_database.foo_table`(
  `id` int, 
  `name` string, 
  `updated_at` timestamp)
ROW FORMAT SERDE 
  'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe' 
WITH SERDEPROPERTIES ( 
  'field.delim'=',', 
  'line.delim'='\n', 
  'serialization.format'=',') 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.mapred.TextInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  'hdfs://localhost:9000/user/hive/warehouse/foo_database.db/foo_table'
TBLPROPERTIES (
  'bucketing_version'='2', 
  'transient_lastDdlTime'='1618929431')
Time taken: 0.802 seconds, Fetched: 19 row(s)
```

### CSV データファイルを用意

読み込む CSV ファイルをローカルのファイルシステムに3つ用意する。

data1.csv

```
100,Alice,2020-02-29 00:00:00.000000001
```

data2.csv

```
200,ボブ,1999-12-31 23:59:59
```

data3.csv

```
300,Carol,2021-04-20 00:00:00
```

### LOAD DATA でローカルのファイルシステムにある CSV ファイルを読み込む

Hive からローカルにある data1.csv を読み込む。
LOAD DATA で LOCAL キーワードを指定するとローカルからファイルを読み込むようになる。

```
hive> LOAD DATA LOCAL INPATH 'file:/home/foo/data1.csv' INTO TABLE foo_database.foo_table;
Loading data to table foo_database.foo_table
OK
Time taken: 2.499 seconds
```

data1.csv のデータがテーブルに読み込まれたのを確認。

```
hive> select * from foo_database.foo_table;
OK
100	Alice	2020-02-29 00:00:00.000000001
Time taken: 5.529 seconds, Fetched: 1 row(s)
```

Hive からローカルにある data2.csv を読み込む。

```
hive> LOAD DATA LOCAL INPATH 'file:/home/foo/data2.csv' INTO TABLE foo_database.foo_table;
Loading data to table foo_database.foo_table
OK
Time taken: 0.64 seconds
```

data1.csv と data2.csv のデータが存在していることを確認。

```
hive> select * from foo_database.foo_table;
OK
100	Alice	2020-02-29 00:00:00.000000001
200	ボブ	1999-12-31 23:59:59
Time taken: 0.485 seconds, Fetched: 2 row(s)
```

Hadoop のファイルシステムを確認すると、読み込んだファイルが Hive 管理下のディレクトリに配置されているのがわかる。

```
$ hadoop fs -ls -R /user/hive/
drwxrwxr-x   - foo supergroup          0 2021-04-20 23:36 /user/hive/warehouse
drwxr-xr-x   - foo supergroup          0 2021-04-21 06:56 /user/hive/warehouse/foo_database.db
drwxr-xr-x   - foo supergroup          0 2021-04-21 06:58 /user/hive/warehouse/foo_database.db/foo_table
-rw-r--r--   1 foo supergroup         40 2021-04-21 06:57 /user/hive/warehouse/foo_database.db/foo_table/data1.csv
-rw-r--r--   1 foo supergroup         31 2021-04-21 06:58 /user/hive/warehouse/foo_database.db/foo_table/data2.csv
```

Hive からローカルにある data3.csv を読み込む。
OVERWRITE を指定するとテーブルから既存のデータがすべて削除される。

```
hive> LOAD DATA LOCAL INPATH 'file:/home/foo/data3.csv' OVERWRITE INTO TABLE foo_database.foo_table;
Loading data to table foo_database.foo_table
OK
Time taken: 0.645 seconds
```

data1.csv と data2.csv のデータが削除され、data3.csv のデータがテーブルに読み込まれたのを確認。

```
hive> select * from foo_database.foo_table;
OK
300	Carol	2021-04-20 00:00:00
Time taken: 0.482 seconds, Fetched: 1 row(s)
```

### データ削除

ここで一旦テーブルの中身を空にする。

```
hive> truncate table foo_database.foo_table;
OK
Time taken: 0.308 seconds
```

### Hadoop ファイルシステム上に CSV データファイルを用意

hadoop fs コマンドで Hadoop ファイルシステム上に CSV ファイルを置くためのディレクトリを作成して、ローカルにある CSV ファイルをコピーする。

```
$ hadoop fs -mkdir /user/foo

$ hadoop fs -put data*.csv /user/foo

$ hadoop fs -ls /user/foo
Found 3 items
-rw-r--r--   1 foo supergroup         40 2021-04-21 07:04 /user/foo/data1.csv
-rw-r--r--   1 foo supergroup         31 2021-04-21 07:04 /user/foo/data2.csv
-rw-r--r--   1 foo supergroup         30 2021-04-21 07:04 /user/foo/data3.csv
```

### LOAD DATA で Hadoop ファイルシステムにある CSV ファイルを読み込む

Hive から Hadoop ファイルシステムにある data1.csv を読み込む。

```
hive> LOAD DATA INPATH '/user/foo/data1.csv' INTO TABLE foo_database.foo_table;
Loading data to table foo_database.foo_table
OK
Time taken: 0.622 seconds
```

data1.csv のデータがテーブルに読み込まれたのを確認。

```
hive> select * from foo_database.foo_table;
OK
100	Alice	2020-02-29 00:00:00.000000001
Time taken: 0.517 seconds, Fetched: 1 row(s)
```

Hive から Hadoop ファイルシステムにある data2.csv を読み込む。

```
hive> LOAD DATA INPATH '/user/foo/data2.csv' INTO TABLE foo_database.foo_table;
Loading data to table foo_database.foo_table
OK
Time taken: 0.552 seconds
```

data1.csv と data2.csv のデータが存在していることを確認。

```
hive> select * from foo_database.foo_table;
OK
100	Alice	2020-02-29 00:00:00.000000001
200	ボブ	1999-12-31 23:59:59
Time taken: 0.383 seconds, Fetched: 2 row(s)
```

Hadoop のファイルシステムを確認すると、読み込まれたファイル (data1.csv と data2.csv) が移動して消えているのがわかる。

```
$ hadoop fs -ls /user/foo
-rw-r--r--   1 foo supergroup         30 2021-04-21 07:04 /user/foo/data3.csv
```

Hive から Hadoop ファイルシステムにある data3.csv を読み込む。
OVERWRITE を指定するとテーブルから既存のデータがすべて削除される。

```
hive> LOAD DATA INPATH '/user/foo/data3.csv' OVERWRITE INTO TABLE foo_database.foo_table;
Loading data to table foo_database.foo_table
OK
Time taken: 0.638 seconds
```

data1.csv と data2.csv のデータが削除され、data3.csv のデータがテーブルに読み込まれたのを確認。

```
hive> select * from foo_database.foo_table;
OK
300	Carol	2021-04-20 00:00:00
Time taken: 0.382 seconds, Fetched: 1 row(s)
```

Hadoop のファイルシステムを確認すると、読み込んだファイルが Hive 管理下のディレクトリに配置されているのがわかる。

```
$ hadoop fs -ls -R /user/hive/
drwxrwxr-x   - foo supergroup          0 2021-04-20 23:36 /user/hive/warehouse
drwxr-xr-x   - foo supergroup          0 2021-04-21 07:00 /user/hive/warehouse/foo_database.db
drwxr-xr-x   - foo supergroup          0 2021-04-21 07:07 /user/hive/warehouse/foo_database.db/foo_table
-rw-r--r--   1 foo supergroup         30 2021-04-21 07:04 /user/hive/warehouse/foo_database.db/foo_table/data3.csv
```

### 同じ名前のファイルを LOAD DATA した場合

同じファイル名で中身の違う CSV ファイルをローカルに用意。

data3.csv

```
400,Dave,2022-02-22 02:22:22
```

Hadoop ファイルシステムにコピー。

```
$ hadoop fs -put data3.csv /user/foo
```

Hive から Hadoop ファイルシステムにある data3.csv を読み込む。

```
hive> LOAD DATA INPATH '/user/foo/data3.csv' INTO TABLE foo_database.foo_table;
Loading data to table foo_database.foo_table
OK
Time taken: 1.91 seconds
```

同じファイル名のファイルを読み込んでも、以前のデータも残っていることが確認できる。

```
hive> select * from foo_database.foo_table;
OK
300	Carol	2021-04-20 00:00:00
400	Dave	2022-02-22 02:22:22
Time taken: 0.468 seconds, Fetched: 2 row(s)
```

Hive 管理下のディレクトリを確認すると、data3.csv が data3_copy_1.csv にリネームされて配置されているのがわかる。ファイル名が同じでも安全にデータを配置できている。

```
$ hadoop fs -ls -R /user/hive/
2021-04-21 10:13:45,733 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
drwxrwxr-x   - foo supergroup          0 2021-04-20 23:36 /user/hive/warehouse
drwxr-xr-x   - foo supergroup          0 2021-04-21 07:00 /user/hive/warehouse/foo_database.db
drwxr-xr-x   - foo supergroup          0 2021-04-21 07:13 /user/hive/warehouse/foo_database.db/foo_table
-rw-r--r--   1 foo supergroup         30 2021-04-21 07:04 /user/hive/warehouse/foo_database.db/foo_table/data3.csv
-rw-r--r--   1 foo supergroup         29 2021-04-21 07:12 /user/hive/warehouse/foo_database.db/foo_table/data3_copy_1.csv
```

## 参考資料

- [LanguageManual DML \- Apache Hive \- Apache Software Foundation](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DML)
- [Apache Hadoop 3\.2\.0 – Overview](https://hadoop.apache.org/docs/r3.2.0/hadoop-project-dist/hadoop-common/FileSystemShell.html)