Spark自学自習(1) 遅延評価について
昨年末ごろから業務でPySparkを使っているので、そこで勉強したことを何回かに分けてまとめていきたいと思います。
まず、第一回目としてSparkの遅延評価についてまとめたいと思います。
本記事の内容は基本的には、以下の本を参考にしています。今回の内容は1章・2章で解説されています。
そもそもSparkとはなにか?
Spark: The Definitive Guideでは、
Apache Spark is a unified computing engine and a set of libraries for parallel data processing on computer clusters. (p.3.)
という風に説明されています。
ここでは、Sparkとは並列分散処理を行うために必要な機能を提供するプラットフォームなんだな、くらいで理解していただければ大丈夫かと思います。
Sparkの概要についてわかりやすく解説された記事がインターネット上にたくさんあるので*1、詳しくはそちらを参考にしていただきたく思います。
Sparkの遅延評価 (Lazy Evaluation)について
筆者のようなデータサイエンティスト見習いが、Sparkを勉強していて最初に戸惑うのは遅延評価(Lazy Evaluation)という仕組みではないでしょうか?
プログラミング言語では、与えられた式に対してどの時点で実際の計算を行いその値を得るかについて複数の戦略が存在しています。 Pythonを含む多くの言語では先行評価という方法で式の評価を行っています。先行評価は、Sparkで使われている遅延評価と対になる戦略となっています。
本節では、まず先行評価についてまず確認を行ったあと、遅延評価の仕組みについて解説して行きたいと思います。
先行評価について
Pythonでは他の多くの言語と同じく先行評価という戦略で、与えられた式の評価が行われています。
例えば以下のPython3のコードでは、yの値は2行目で即時に計算され、そこで格納された値が3行目で出力されるという仕組みなっており、式の定義と評価が同時に行われています。
x = 10 y = x ** 2 + x print(y)
この評価戦略は直感的に理解しやすいので、Sparkを勉強するまでは他の評価戦略が存在していることを想像したことすらありませんでした。
遅延評価について
Pythonとは異なりSparkでは遅延評価という戦略で与えられた式の評価を行っています。
遅延評価とは、評価しなければならない値がある時に、実際にその値が必要になるまで計算を行わないことを指しています。以下でPySparkのコードを使って遅延評価の動作を解説していきたいと思います。(Spark: The Definitive Guideのp.17~p.20の例 )
myrange = spark.range(1000).toDF("number") divisBy2 = myRange.where("number % 2 = 0") print(divisBy2.count())
上記コードの処理概要
line1: 0 ~ 999までを要素に持つDataFrameを生成しmyRangeという変数に格納 line2: myRangeのなかで偶数のものに絞り、divisBy2をという変数に格納 line3: divisBy2の個数をカウント
さて、上記コードを先行評価で読むと、line2の段階ですでにmyRangeのなかで偶数のものを絞りこむという処理が行われているように見えます。
しかし、遅延評価では、line2では実際の計算は行われず、line3でカウントを行う際に実際のline2で定義された絞りこみの計算が行われています。これは実際にその値が必要になるまで計算を行わないという遅延評価の仕組みによるものです。確かにline2の段階では、データ変換の定義を行っているだけで、なんらかの値が必要になっている訳ではなさそうです。
Sparkでは、上記例のline3のように実際の値が計算が行われるメソッドのことをActionsと呼び、上記例のline2のように変換を定義しているメソッドのことをTransformationsと呼びます。これらについては次回記事でまとめたいと思います。
遅延評価のメリット
遅延評価の概要についてはわかりましたが、ではその遅延評価を行うことでどのようなメリットがあるのでしょうか?
遅延評価のメリットは、Spark側で処理の最適化が行えることです。例えば、あるテーブルに対していくつかの処理を行い、そこから特定の行の結果を取り出したい場合を考えます。得たい結果が特定の一行だけの場合、最初にその一行を抜き出してきて計算を行うほうが、テーブル全体に対して計算を行ってからその特定の一行を取り出してくるより効率的です。このように、Sparkでは処理の順序を入れ替えることで大幅に効率化できることがあります。遅延評価の仕組みを取り入れることで、Spark側で自動的に処理の順番を入れ替えることで効率化を行えるというメリットがあります。