Hive入門 | Hadoop Advent Calendar 2016 #06

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、小澤です。 この記事はHadoop Advent Calendar 6日目のものとなります。

前回はSQL on Hadoopを実現するHiveがどのような仕組みで成り立っているのかを説明するために全体の構成を紹介しました。
今回は実際にHiveを利用してテーブルの作成からSELECT文の発行までの流れを追いたいと思います。

利用環境の準備

HiveはHadoopとMetaStore用のRDBに依存しているため、コマンド一発のような簡単な方法で利用を始めることができません。 Macであればhomebrewにhiveがありますが、別途Hadoopを入れて設定を書き換えたり、MySqlやJDBC Connectorを用意したりといくつかの工程が必要になります。
そこで、今回の内容は、ClouderaやHortonworksが提供するVMやDockerイメージを利用し、すでに環境が整っている状態である前提にさせていただきたいと思います。

実際の環境では既存のHadoopクラスタにHiveを新規で導入するよりもエコシステムを含めて利用可能な環境を構築してしまうことが多いかと思いますので、Hiveを単体でクラスタに導入する知識はそこまで 必要となることはありません。

今回利用するデータ

実際に使ってみるにはそのためのデータが必要になります。 今回はサンプルデータとしてUCIにあるIris Data Setを使いたいと思います。
このデータは最後に空行が入っており、そのまま入れるとNULLの行ができてしまうので、先に削っておいてください。

HDFSのパスについて

Hiveの話に入る前にHDFSについて簡単に補足しておきます。 HDFSはUnix系OSのようなファイルシステムになっています。

$ hadoop dfs -ls <path>

などとすることでlsコマンド相当のことができます。厳密に全く同じというわけではありませんが、mvやmkdir,catなどやりたいことに合わせてUnixで対応するコマンドを入れればほぼ想定した通りに動いてくれます。
また、アクセス権限についても同様でuser, group, otherに対してそれぞれrwxで権限を指定することができます。

ユーザ向けのディレクトリは/user/<user名>以下となっているので、今回の内容程度であれば、こちらを使っておけばファイルがどこにあるかわからなくなるなどの問題は発生しないかと思います。

Hiveの実行

特に難しいことはありません。

$ hive
hive> 

と、HiveQLを実行するためのシェルに移ります。sqlを書いたファイルを渡す場合などもこちらのコマンドに-fオプションをつけることで実現できます。

データの準備

Hiveにはデータベースとテーブルという概念があります。これはRDBの同等の概念のほかにHDFS上のデータの保存先を指定するのにも利用します。
データベースに関しては特に利用しなくても問題ありませんが、役割やデータの保存先ごとにテーブルを分けておきたいときなどに利用すると便利です。データベースを作成するには

hive> CREATE DATABASE <database名> LOCATION '<hdfsのパス>';

とすることで、作成できます。LOCATIONは必須でありませんが、データベースごとにデータの保存先を分けたいときには指定しておくと便利です。
データベースの一覧を取得するには

hive> SHOW DATABASES;
OK
default
iris

のようにすると現在あるデータベースを一覧できます。

次にテーブルを作成します。今回は利用するデータセット用にirisという名前のデータベースを作成して、その中にテーブルも作成します。

CREATE TABLE iris.iris (
 sepal_length double,
 sepal_width double,
 petal_length double,
 petal_width double,
 species string
) 
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n'
;

というCREATE TABLE文を発行します。通常のRDBのCREATE TABLE文とほぼ一緒ですが、最後にHDFS上で区切り文字を指定しています。これは必須ではありませんが、直接中身を見たいときなどは指定しておいたほうが便利です。
今回は元のデータがCSVなので、それに合わせる必要があるため区切り文字を指定してます。この後解説するLOAD DATAでデータを挿入する場合、元のファイルをそのまま変換せずに使用するため、そのファイルのフォーマットに合わせた区切り文字の指定が必要になります。
また、今回は指定してませんが、CREATE TABLEもCREATE DATABASEと同様にLOCATIONの指定が可能です。
テーブル定義の際にLOCATIONの指定をしなかった場合は、データベースのLOCATION以下にテーブル名のディレクトリが作成され、そこにデータが格納されます。

次にデータをこのテーブルに入れます。手元にデータがある場合は

LOAD DATA LOCAL INPATH '<ファイルのパス>' INTO TABLE iris;

とファイルを指定します。LOCALをつけないことでHDFS上にあるファイルから読み込むことも可能なので、

$ hadoop dsf -pu <ローカルのパス> <HDFSのパス>
$ hive -e "LOAD DATA INPATH '<HDFS上のファイルパス>' INTO TABLE iris;

としても大丈夫です。
ただし、HDFS上にあるファイルの場合データを移動させます。そのため、元のパスにはファイルはなくなってしまいますし、hive上で削除した場合はデータ自体が失われてしまう可能性もあるので気をつけて下さい。

SELECT文の発行

データの用意ができたので、取得してみます。

SELECT * FROM iris.iris;

簡単なSELECT文です。テーブル名の指定は <データベース名>.<テーブル名> となっています。
USE <データベース名>;としておくと、そのデータベースに対してはデータベース名を省略してテーブル名のみでの指定が可能になります。

USE iris;
SELECT * FROM iris;

次に先ほどよりちょっと複雑なクエリを投げてみます。

SELECT
  avg(sepal_width),
  avg(sepal_length),
  avg(petal_width),
  avg(petal_length),
  species
FROM iris
GROUP BY species
;

このクエリを実行すると、先ほどとは違い、MapReduecやTezのジョブが実行されている様子が出力されるかと思います。 実はHiveは最初の例のような簡単なクエリの場合、HDFSのファイルをそのまま返すだけという仕組みになっているのです。 これはLIMIT句をつけた場合でも同じ動きをしてくれるので、どんなデータなのか先頭数行で確認してみるといった時に便利です。

CREATE TABLE AS SELECTとINSERT SELECT

分析用途の場合、SELECT文の結果をそのまま受け取るのではなく、そのまま別なテーブルに入れてしまいたいことがよくあります。 そんな時に使えるのがこの2つの構文です。

CREATA TABLEは

CREATA TABLE iris2 AS SELECT ...

のようにSELECT文の結果からそのまま新しいテーブルを作成します。テーブルの構造はSELECTの結果から自明なので記載する必要はありません。

INSERTの場合は

INSERT INTO TABLE iris3 SELECT ...

のように実行することですでに存在しているテーブルの内容を上書きします。
今回は解説しませんが、INSERTはpartitionという機能と合わせて使うことで、まとまった単位(日毎など)でデータを追加していくといった用途にも利用されます。

終わりに

今回の内容はここまでとなります。 入門ということで、一番初歩的な内容のみ扱いましたが、なんとなくHiveやHadoop上でSQLを扱うイメージをつかめてもらえましたでしょうか?
実際にHiveを活用するには基本的なものだけでは足りていない部分も多くありますが、まずは試してみることをお勧めします。

明日はApache Tezというものを紹介する予定です。 Hiveのより高度な機能の一部はTezに依存しているため、先にTezについて書かせていただこうと考えております。
ぜひ、お楽しみに!