Impalaを使ってみました | Hadoop Advent Calendar 2016 #11

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

前回はHiveで機械学習をおこなうライブラリであるHivemallについて紹介しました。
今回はImpalaについて書かせていただきます。
とはいえ、実は私自身もImpalaは今回が初めてとなります。そのため今回は使ってみたという内容になります。

Impalaとは

ImpalaはSQL on Hadoop(SQLでHadoop上のデータアクセスするためのもの)の一種で、HiveQLで処理を記述します。 ImpalaはHiveと比較されることが多いですが、その違いを簡単にまとめてみます。

HiveはMapReduceやTez, Sparkなどの仕組みの上に乗った技術でありそれらに依存します。 そのため、基本的にはバッチ処理で利用されるものであり、インタクティブにデータを分析する用途としては不向きです。

一方Implaraはそれらのフレームワークに乗ることなく独自に処理を行います。インタクティブなデータ分析で活用することを主な目的にしており、高速に動作することが特長です。 そのため、MPPに分類されるようです。
では、Impalaの方がHiveより優れているのかというともちろんデメリットもあり、耐障害性がありません。

入出力データ

Impalaも他のHadoop上で動作するシステムと同様HDFSなどを入出力の対象としています。 そのため、Hive同様データの実体とは別にテーブル定義が必要になりますが、これにはHiveのMetaStoreがそのまま利用できます。 Impalaで利用するファイルは主にParquetを想定しているようで、テキストファイルなども扱えますが複合型を利用できるのはParquet利用時のみのようです。 また、ImpalaではORCファイルには対応していません。

HiveのMetaStoreのデータを読み込んで利用できるようにするには、

$ impala

でREPL形式のシェルを起動するなどして、

invalidate metadata;

とするといいようです。実際にこのコマンド実行後は

use iris;
show tables;
Query: show tables
+------------------+
| name             |
+------------------+
| iris             |
| iris_scaled      |
| iris_shuffled    |
| model_scw        |
| predict_scw      |
| test20p          |
| test20p_exploded |
| train10x         |
| train80p         |
+------------------+

のように過去にHiveで作成したデータベースやテーブルが存在するのが確認できます。

selectしてみる

次にselect文を実行してみます。

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

hiveで同様のselect文を実行した時と同じ結果が得られました。
次に、複合型を含むデータに対してselect文を発行するとエラーが発生するようです。

select * from  iris_scaled;
Query: select * from  iris_scaled
ERROR: NotImplementedException: Scan of table 'iris.iris_scaled' in format 'TEXT' is not supported because the table has a column 'features' with a complex type 'ARRAY<STRING>'.
Complex types are supported for these file formats: PARQUET.

Parquetを使えと言われていますね。

ためしに配列を含むテーブルをParquetファイルで作成してみます。なお、Impalaでこのクエリを実行したところarray関数がないと言われてしまったので、Hiveの方で実行しています。

create table iris_parquet stored as parquet as 
select
  row_number() over() as rowid,
  species as label,
  array(sepal_length, sepal_width, petal_length, petal_width) as features
from
  iris
;

このテーブルに対してImpalaから再びselectを実行してみます

select features from iris_parquet;
Query: select features from iris_parquet
ERROR: AnalysisException: Expr 'features' in select list returns a complex type 'ARRAY<DOUBLE>'.
Only scalar types are allowed in the select list.

なにやら複合型を返すためにはそのままではダメなようです。 下記のようなクエリを書くことで、Arrayの中身を展開(Hiveでのexplode相当)した結果を返してくれるようです。

select * from iris_parquet, iris_parquet.features limit 5;
Query: select * from iris_parquet, iris_parquet.features limit 5
+-------+----------------+------+
| rowid | label          | item |
+-------+----------------+------+
| 1     | Iris-virginica | 5.9  |
| 1     | Iris-virginica | 3    |
| 1     | Iris-virginica | 5.1  |
| 1     | Iris-virginica | 1.8  |
| 2     | Iris-virginica | 6.2  |
+-------+----------------+------+

HiveQLが使えるといっても、複合型の扱いの影響は考慮しなければならなさそうです。 そもそもデータ構造を決める段階で複合型をどこまで許容するのかという問題もありまが、どうしても避けられないような分析をする際には試行錯誤時にはImpalaを使って運用時にはHiveでバッチ処理といった用途を想定すると可能な限り、両方で動くクエリになるようにしておきたいですね。

終わりに

今回はImpalaを使ってみました。 単一ノードで小規模なデータを使っていたため、Hiveとの速度比較はできませんでしたが、使ってみるとJob起動のオーバーヘッドの時間がない分の速度差などは実感することができました。

明日はSQL on Hadoopから一旦離れ、Apache Pigというものについて書かせていただく予定です。
ぜひ、お楽しみに!