Apache Hive には基本となる文字列や数値以外にも複合型 (Complex Type) というデータタイプがある。 以前、その中の一つとして ARRAY 型をこのブログでも扱った。
今回は、それに続いて複合型の中で STRUCT 型というデータタイプを試してみる。 これは、文字通り一般的なプログラミング言語でいう構造体 (Struct) に相当するもの。 この STRUCT 型を使うことで一つのカラムの中に複数のデータを格納できる。 使い勝手としては KVS によくあるカラムファミリーに近いかもしれない。
環境は次の通り。
$ 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
STRUCT 型を使ってテーブルを作る
例として、まずは名前の姓と名を STRUCT 型で分割して保存するテーブルを作ってみる。
STRUCT 型を定義するときは、次のように <>
の中に名前と型をカンマ区切りで羅列していく。
hive> CREATE TABLE users ( > name STRUCT<first: STRING, > last: STRING> > ); OK Time taken: 0.135 seconds
STRUCT 型を使ったレコードを追加する
データを追加するときは一般的な INSERT INTO ... VALUES
が使えない。
hive> INSERT INTO TABLE users > VALUES (NAMED_STRUCT("first", "John", "last", "Doe")); FAILED: SemanticException [Error 10293]: Unable to create temp file for insert values Expression of type TOK_FUNCTION not supported in insert/values
代わりに SELECT
で作ったデータを使うことになる。
NAMED_STRUCT()
関数はフィールドに名前のついた STRUCT 型のデータを作るために使う。
hive> SELECT NAMED_STRUCT("first", "John", "last", "Doe"); OK _c0 {"first":"John","last":"Doe"} Time taken: 0.066 seconds, Fetched: 1 row(s)
上記のように SELECT
で作ったデータを INSERT INTO
に渡してやる。
hive> INSERT INTO TABLE users > SELECT NAMED_STRUCT("first", "John", "last", "Doe"); ... OK _c0 Time taken: 21.451 seconds
この通り、ちゃんとレコードが保存された。
hive> SELECT * FROM users; OK users.name {"first":"John","last":"Doe"} Time taken: 0.156 seconds, Fetched: 1 row(s)
STRUCT 型のフィールドを参照する
STRUCT 型に保存されたフィールドの中身を参照するときは、次のようにカラム名にドットでフィールド名をつなげてやる。
hive> SELECT name.first, name.last FROM users; OK first last John Doe Time taken: 0.143 seconds, Fetched: 1 row(s)
基本的な使い方は上記の通り。 一旦テーブルを削除しておこう。
hive> DROP TABLE users; OK Time taken: 0.119 seconds
ARRAY 型と組み合わせて使う
STRUCT 型は別の複合型と組み合わせて使うこともできる。
例えば ARRAY 型の中に STRUCT 型を含むようなテーブルを作ってみよう。
hive> CREATE TABLE users ( > name STRING, > addresses ARRAY<STRUCT<country: STRING, > city: STRING>> > ); OK Time taken: 0.114 seconds
データを追加するときは、次のように ARRAY()
関数と NAMED_STRUCT()
関数を組み合わせる。
hive> INSERT INTO TABLE users > SELECT "Alice", ARRAY(NAMED_STRUCT("country", "japan", "city", "tokyo"), > NAMED_STRUCT("country", "japan", "city", "osaka")); ... OK _c0 _c1 Time taken: 20.376 seconds
テーブルを確認すると、ちゃんと ARRAY 型の中に STRUCT 型のデータが収まっていることが分かる。
hive> SELECT * FROM users; OK users.name users.addresses Alice [{"country":"japan","city":"tokyo"},{"country":"japan","city":"osaka"}] Time taken: 0.133 seconds, Fetched: 1 row(s)
中身を展開して集計するときは普通に ARRAY 型を使うときと同じように LATERAL VIEW
と explode()
関数を組み合わせれば良い。
hive> SELECT * > FROM users > LATERAL VIEW explode(addresses) users AS address; OK users.name users.addresses users.address Alice [{"country":"japan","city":"tokyo"},{"country":"japan","city":"osaka"}] {"country":"japan","city":"tokyo"} Alice [{"country":"japan","city":"tokyo"},{"country":"japan","city":"osaka"}] {"country":"japan","city":"osaka"} Time taken: 0.121 seconds, Fetched: 2 row(s) hive> SELECT name, address.country, address.city > FROM users > LATERAL VIEW explode(addresses) users AS address; OK name country city Alice japan tokyo Alice japan osaka Time taken: 0.045 seconds, Fetched: 2 row(s)
外部ファイルからデータを読み込む
外部ファイルからデータを読み込むときは、次のようにフィールドやコレクションの区切り文字を指定しておく。
hive> CREATE TABLE users ( > name STRUCT<first: STRING, > last: STRING> > ) > ROW FORMAT DELIMITED > FIELDS TERMINATED BY ',' > COLLECTION ITEMS TERMINATED BY '$' > STORED AS TEXTFILE; OK Time taken: 0.143 seconds
フィールドの区切り文字として $
を使った CSV ファイルを用意しておく。
$ cat << 'EOF' > users.csv Yamada$Taro Suzuki$Ichiro EOF
あとは上記を Hive で読み込むだけ。
hive> LOAD DATA LOCAL INPATH '/home/vagrant/users.csv' INTO TABLE users; Loading data to table default.users OK Time taken: 0.944 seconds
この通り、ちゃんとデータが格納された。
hive> SELECT * FROM users; OK users.name {"first":"Yamada","last":"Taro"} {"first":"Suzuki","last":"Ichiro"} Time taken: 0.287 seconds, Fetched: 2 row(s)
次はもうちょっと複雑な例を示す。 その前に、一旦テーブルを削除しておこう。
hive> DROP TABLE users; OK Time taken: 0.193 seconds
次は、先ほどと同じように ARRAY 型と STRUCT 型を組み合わせたパターンでも外部ファイルから読み込んでみる。
このときのポイントとしては MAP KEYS TERMINATED BY
も指定しておくところ。
hive> CREATE TABLE users ( > name STRING, > addresses ARRAY<STRUCT<country: STRING, > city: STRING>> > ) > ROW FORMAT DELIMITED > FIELDS TERMINATED BY ',' > COLLECTION ITEMS TERMINATED BY '$' > MAP KEYS TERMINATED BY ':' > STORED AS TEXTFILE; OK Time taken: 0.06 seconds
今度はフィールドの区切り文字は :
を使いつつリストの区切り文字として $
を指定してやる。
$ cat << 'EOF' > users.csv Alice,japan:tokyo$japan:osaka Bob,america:newyork$america:california EOF
上記のファイルを読み込んでみよう。
hive> LOAD DATA LOCAL INPATH '/home/vagrant/users.csv' INTO TABLE users; Loading data to table default.users OK Time taken: 0.432 seconds
すると、以下のようにちゃんと保存されている。
hive> SELECT * FROM users; OK users.name users.addresses Alice [{"country":"japan","city":"tokyo"},{"country":"japan","city":"osaka"}] Bob [{"country":"america","city":"newyork"},{"country":"america","city":"california"}] Time taken: 0.134 seconds, Fetched: 2 row(s)
ばっちり。
- 作者: Edward Capriolo,Dean Wampler,Jason Rutherglen,佐藤直生,嶋内翔,Sky株式会社玉川竜司
- 出版社/メーカー: オライリージャパン
- 発売日: 2013/06/15
- メディア: 大型本
- この商品を含むブログ (3件) を見る