Java 8 & 機械学習の視点でみる Spark 1.0 リリース

はじめに

さる 5/30、今か今かと待ち望まれていた Spark 1.0 が 遂にリリース されましたね!

その前日 5/29 には都内で 実際のところ Spark ソースコードリーディング だった Hadoop ソースコードリーディング #16 が開催されるなど、 Spark についての注目度が俄然高まってきているように思えます。

そんなわけで、0.9.1 からの変更点や機能追加について、Java と機械学習に携わるエンジニアの視点で 今回の 1.0 リリース内容をまとめてみました!

何が変わったのか?

Spark : Java 8 のラムダ式サポート

Java エンジニア的に今回の一番の変更点は、何と言っても Java 8 のラムダ式への対応、ですね。

今年 3 月の Java 8 正式リリース後、主に Stream API の周辺においてラムダ式を書く機会が徐々に増えつつあるかと思いますが、 Spark 0.9.1 以前の JavaRDD では、Stream API に近いインタフェースを提供しつつも実質的にラムダ式の記述が困難なインタフェース設計と なっていました。

1.0 では Investigate the potential for using JDK 8 lambda expressions for the Java/Scala APIs などの調査を経てこの懸案が解消され、ラムダ式を使ったよりスマートな処理の記述が可能となりました。

なお、このラムダ式サポートによって JavaRDDLike などのインタフェースが変更されており、0.9.1 までの Spark アプリケーションが 1.0 ではコンパイルエラーとなることがありますのでご注意ください。

MLlib : スパースな特徴ベクトルの効率的な表現

0.9.1 までの MLlib を活用されている方ならご存知かと思いますが、0.9.1 以前における、各種機械学習アルゴリズムに入力する特徴ベクトルの型は double[] と、かなりナイーブな実装となっていました。

このプリミティブ型の配列で特徴ベクトルを表現する場合、対象とするデータセットが密な場合には都合がいいのですが、 スパース (疎) なデータセットを取り扱おうとした場合に無駄が多く、空間効率がよろしくないという懸案がありました。 (この問題は、単純ベイズ分類器 (NaiveBayes) を使って、Bag-of-words モデルで表現されたドキュメントを分類しようとした場合などで顕在化します)

1.0 では add DenseVector and SparseVector to mllib, and replace all Array[Double] with Vectors の 対応により、密なデータセット、スパースなデータセットそれぞれに適した特徴ベクトルを構築できるようになりました。

具体的な特徴ベクトルの構築方法は以下のとおりで、 [Vectors.dense()](https://spark.apache.org/docs/1.0.0/api/java/org/apache/spark/mllib/linalg/Vectors.html#dense(double[])) や [Vectors.sparse()](https://spark.apache.org/docs/1.0.0/api/java/org/apache/spark/mllib/linalg/Vectors.html#sparse(int, int[], double[])) を利用します。

なおこちらのスパース特徴ベクトルの対応においても、具体的な機械学習アルゴリズムのインタフェース、例えば [ KMeans.train](https://spark.apache.org/docs/1.0.0/api/java/org/apache/spark/mllib/clustering/KMeans.html#train(org.apache.spark.rdd.RDD, int, int)) などのインタフェースが変更されていることにご注意ください。

MLlib : 新しく追加された各種アルゴリズム

前述したようなインタフェースの改善だけではなく、いくつかの機械学習アルゴリズムなどが追加されました。

  • クラス分類・回帰
    • 決定木 (Scalable decision tree)
      • リリースノートを見ると、クラス分類および回帰ができるようです
      • Experimental とのことなので、インタフェース等はこれから変わるかもしれません
  • 行列計算
    • [特異値分解 (SVD, Singular value decomposition)](https://spark.apache.org/docs/1.0.0/api/java/org/apache/spark/mllib/linalg/distributed/RowMatrix.html#computeSVD(int, boolean, double))
    • [主成分分析 (PCA, Principal component analysis)](https://spark.apache.org/docs/1.0.0/api/java/org/apache/spark/mllib/linalg/distributed/RowMatrix.html#computePrincipalComponents(int))
  • 最適化

アルゴリズム周辺は JIRA の issue を見ると まだまだ色々と控えているようなので今後も期待できますね!

MLlib : 基本統計量の算出

[RowMatrix#computeColumnSummaryStatistics()](https://spark.apache.org/docs/1.0.0/api/java/org/apache/spark/mllib/linalg/distributed/RowMatrix.html#computeColumnSummaryStatistics()) により、データセットの列ごとの、平均、分散、最大値、最小値を簡単に算出できるようになりました。

平均だけではなく中央値や四分位数を求められるとより嬉しいなあ、と個人的に思うのですが、対応予定はないのかな…

まとめと雑感

Java および機械学習周辺に絞り込んで Spark 1.0 のリリース内容を見てきました。

GitHub 上の commit activity を見て分かる通り、1.0 のリリースを迎えても いまだ開発は継続していて安定性という意味でちょっと未知数なところもありますが、アドホックな分析用途などで徐々に利用し始めるのもいいかな… と思います。

なお Spark の適用用途としては、先日の Hadoop ソースコードリーディング #16 で土橋さんが発表されていた 資料 (Slideshare) にあるように、 大規模なデータに対しては従来通り Hadoop でバッチ処理し、Spark はメモリに載り切りかつ量が大きく変動しない データに対して適用するのがよさそうですね。

まあとにかく、Java エンジニアとしてはラムダ式でさくさくとコードを記述できる機会が得られる Spark は (人によっては) 魅力的、ですね!!