社内se × プログラマ × ビッグデータ

プログラミングなどITに興味があります。

SparkSql で5教科の成績に評価を付けてみる

SparkSqlはSpark上でSQLを利用するためのコンポーネントです。
Sparkの分散環境上で大量データに対して高速なSQLを実行できます。

SparkSqlでソートする練習のために、5教科の成績に評価を付けるプログラムを書いてみました。
例えば、今5人(A君~E君)がいるとして、英語の成績が以下であるとします。
A君:100点
B君:80点
C君:60点
D君:40点
E君:20点

その順位に応じた評価点をつけます。
上記の場合、A君:5点、B君:4点、C君:3点、D君:2点、E君:1点という感じです。
これを5教科(国語、数学、英語、理科、社会)に対して行い、合計の評価点を計算します。

元の点数そのまま使えばいいやんという感じでもありますが、ソートして連番を付ける練習がしたかったので、こんな計算をするようにしています。

ソースコードはこちらgithub.com

SparkSql で扱うエンティティには getter を定義しなければならない!

今回、成績を格納するエンティティとして、RecordData というクラスを定義しましたが、必ず各フィールドに対して getter を定義する必要がありました。
最初は定義していなかったのですが、DataFrame に対して、printSchema() を実行しても、select 文を発行しても何のデータも得られませんでした。
どうやら、getter 経由でデータを取得してくる仕様のようです。

SparkSql でも Window関数が使える!

select 文の結果に対して連番を付与する場合、SQLではWindow関数のrow_numberという機能がありますが、SparkSqlでもそれが使えるようです。
DataFrame には zipWithIndex 関数もありませんし、これは便利ですね。

df.select(row_number().over(Window.partitionBy().orderBy(orderElement1))
Window関数を使うためには HiveContext が必要!

HiveContext なしで使おうとすると、以下のエラーメッセージが表示されてしまいました。

Exception in thread "main" org.apache.spark.sql.AnalysisException: Could not resolve window function 'row_number'. Note that, using window functions currently requires a HiveContext;

なので、SQLContext は HiveContext から作りました。

SQLContext sqlCtx = new HiveContext(jsc);

ただ、コンテキストの生成処理に体感でも数秒間時間がかかっている気がします。

実行確認

printSchema() の実行結果。

root
 |-- english: integer (nullable = true)
 |-- japanese: integer (nullable = true)
 |-- mathematics: integer (nullable = true)
 |-- name: string (nullable = true)
 |-- science: integer (nullable = true)
 |-- social: integer (nullable = true)

日本語の成績。このように点数の多い人から、高い score が付けられています。

+-----+-------+--------+
|score|   name|japanese|
+-----+-------+--------+
|    1| Edison|       3|
|    2|Clinton|      13|
|    3|    Abe|      51|
|    4| Donald|      63|
|    5|   Bush|      66|
+-----+-------+--------+

数学の成績。みんな低すぎでしょ。

+-----+-------+-----------+
|score|   name|mathematics|
+-----+-------+-----------+
|    1| Donald|          2|
|    2| Edison|          2|
|    3|   Bush|          6|
|    4|    Abe|          9|
|    5|Clinton|         40|
+-----+-------+-----------+

英語の成績。単なる乱数とは言え、0点が出てしまった。

+-----+-------+-------+
|score|   name|english|
+-----+-------+-------+
|    1| Donald|      0|
|    2|    Abe|     29|
|    3|Clinton|     40|
|    4|   Bush|     49|
|    5| Edison|     51|
+-----+-------+-------+

社会の成績。

+-----+-------+------+
|score|   name|social|
+-----+-------+------+
|    1| Donald|    12|
|    2|Clinton|    53|
|    3| Edison|    72|
|    4|    Abe|    84|
|    5|   Bush|    98|
+-----+-------+------+

最後は、理科の成績。

+-----+-------+-------+
|score|   name|science|
+-----+-------+-------+
|    1| Edison|      6|
|    2| Donald|      7|
|    3|Clinton|     61|
|    4|   Bush|     69|
|    5|    Abe|     90|
+-----+-------+-------+

そして、総合成績。totalScore は綺麗に3の倍数になりました。

+-------+----------+--------+-----------+-------+------+-------+
|   name|totalScore|japanese|mathematics|english|social|science|
+-------+----------+--------+-----------+-------+------+-------+
|   Bush|        21|      66|          6|     49|    98|     69|
|    Abe|        18|      51|          9|     29|    84|     90|
|Clinton|        15|      13|         40|     40|    53|     61|
| Edison|        12|       3|          2|     51|    72|      6|
| Donald|         9|      63|          2|      0|    12|      7|
+-------+----------+--------+-----------+-------+------+-------+
まとめ

今までは、DataFrame で出来ないことを RDD に変換してから処理して、また DataFrame に戻すみたいなことをしていたけど、SparkSql(DataFrame) のままでも出来ることは思っていたより多い。
変換処理のオーバーヘッドも減らせるだろうし、使っていくのが楽しみになってきました。