前回に引き続き Apache Hive の複合型の一つ MAP 型を試してみる。
MAP 型は一般的なプログラミング言語でいうマップや辞書といったデータ構造に相当する。 これを使うとテーブルのカラムに任意のキーで値を格納できる。
環境は次の通り。
$ cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core) $ uname -r 3.10.0-693.5.2.el7.x86_64 $ hadoop version Hadoop 2.8.3 Subversion https://git-wip-us.apache.org/repos/asf/hadoop.git -r b3fe56402d908019d99af1f1f4fc65cb1d1436a2 Compiled by jdu on 2017-12-05T03:43Z Compiled with protoc 2.5.0 From source with checksum 9ff4856d824e983fa510d3f843e3f19d This command was run using /home/vagrant/hadoop-2.8.3/share/hadoop/common/hadoop-common-2.8.3.jar $ hive --version Hive 2.3.2 Git git://stakiar-MBP.local/Users/stakiar/Desktop/scratch-space/apache-hive -r 857a9fd8ad725a53bd95c1b2d6612f9b1155f44d Compiled by stakiar on Thu Nov 9 09:11:39 PST 2017 From source with checksum dc38920061a4eb32c4d15ebd5429ac8a
MAP 型を使ったテーブルを作る
MAP 型を使ってテーブルを作るときは、次のようにキーと値に使う型を指定してカラムを作る。
hive> CREATE TABLE users ( > name STRING, > property MAP<STRING, STRING> > ); OK Time taken: 0.047 seconds
ちなみにキーにはプリミティブ型しか指定できない。 試しにキーに ARRAY 型を指定してみると、以下のようにエラーになる。
hive> CREATE TABLE example ( > test MAP<ARRAY, STRING> > ); ... FAILED: ParseException line 2:11 cannot recognize input near 'ARRAY' ',' 'STRING' in primitive type specification
MAP 型を含むレコードを追加する
他の複合型と同様に、一般的な INSERT INTO ... VALUES
を使ったレコードの追加ができない。
hive> INSERT INTO TABLE users > VALUES (MAP("key1", "value1", "key2", "value2")); FAILED: SemanticException [Error 10293]: Unable to create temp file for insert values Expression of type TOK_FUNCTION not supported in insert/values
代わりに SELECT
を使ってデータを作って、それを追加してやる。
MAP()
関数を使うことでキーと値の組を使ったカラムを作れる。
hive> SELECT MAP("key1", "value1", "key2", "value2"); OK _c0 {"key1":"value1","key2":"value2"} Time taken: 0.059 seconds, Fetched: 1 row(s)
上記の SELECT
で作ったデータを INSERT INTO
でテーブルに追加する。
hive> INSERT INTO TABLE users > SELECT "Alice", MAP("key1", "value1", "key2", "value2"); ... OK _c0 _c1 Time taken: 19.437 seconds
テーブルを確認すると、ちゃんとレコードが入っている。
hive> SELECT * FROM users; OK users.name users.property Alice {"key1":"value1","key2":"value2"} Time taken: 0.136 seconds, Fetched: 1 row(s)
MAP 型の中身を参照する
MAP 型の中身を取り出すときはブラケットの中にキーを指定する。
hive> SELECT name, property["key1"] FROM users; OK name _c1 Alice value1 Time taken: 0.157 seconds, Fetched: 1 row(s)
存在しないキーの振る舞いを確認する
MAP 型には型さえ合っていれば、これまでに追加したことのないキーであっても大丈夫。
hive> INSERT INTO TABLE users > SELECT "Bob", MAP("key1", "value1", "key3", "value3"); ... OK _c0 _c1 Time taken: 18.935 seconds
テーブルの内容を確認すると、レコードごとに別々のキーが入っていることが分かる。
hive> SELECT * FROM users; OK users.name users.property Alice {"key1":"value1","key2":"value2"} Bob {"key1":"value1","key3":"value3"} Time taken: 0.133 seconds, Fetched: 2 row(s)
レコードによってあったりなかったりするキーを参照したときの振る舞いを確認しておこう。
hive> SELECT name, > property["key1"] AS key1, > property["key2"] AS key2, > property["key3"] AS key3 > FROM users; OK name key1 key2 key3 Alice value1 value2 NULL Bob value1 NULL value3 Time taken: 0.123 seconds, Fetched: 2 row(s)
上記のように、レコードにキーがないときは NULL
になるようだ。
次の確認のために、一旦テーブルを削除しておこう。
hive> DROP TABLE users; OK Time taken: 0.073 seconds
外部ファイルからデータを読み込む
続いて、外部ファイルからデータを読み込むときの挙動も確認しておく。
外部ファイルから読み込むときは次のように各フィールドやカラムの分割文字を指定しておく。
hive> CREATE TABLE users ( > name STRING, > property MAP<STRING, STRING> > ) > ROW FORMAT DELIMITED > FIELDS TERMINATED BY ',' > COLLECTION ITEMS TERMINATED BY '$' > MAP KEYS TERMINATED BY ':' > STORED AS TEXTFILE; OK Time taken: 0.075 seconds
次のように CSV ファイルを作っておく。
先のテーブルを定義するときに指定した通り、キーと値は :
で区切って、フィールドは $
で分割する。
$ cat << 'EOF' > users.csv Alice,key1:value1$key2:value2 Bob,key1:value1$key3:value3 EOF
上記を Hive で LOAD DATA
を使って読み込む。
hive> LOAD DATA LOCAL INPATH '/home/vagrant/users.csv' INTO TABLE users; Loading data to table default.users OK Time taken: 0.385 seconds
すると、次のようにちゃんとテーブルにデータが格納された。
hive> SELECT * FROM users; OK users.name users.property Alice {"key1":"value1","key2":"value2"} Bob {"key1":"value1","key3":"value3"} Time taken: 0.13 seconds, Fetched: 2 row(s)
ばっちり。
- 作者: Edward Capriolo,Dean Wampler,Jason Rutherglen,佐藤直生,嶋内翔,Sky株式会社玉川竜司
- 出版社/メーカー: オライリージャパン
- 発売日: 2013/06/15
- メディア: 大型本
- この商品を含むブログ (3件) を見る