SlideShare a Scribd company logo
1 of 47
Download to read offline
Learning Spark
Chapter03
Programming with RDD
参考資料
• http://www.slideshare.net/hadoopxnttdata/ap
ache-spark
• http://www.ne.jp/asahi/hishidama/home/tech/
scala/spark/RDD.html
• http://d.hatena.ne.jp/kimutansk/20130924/13
79971579
• http://www.slideshare.net/data_sciesotist/2
-learning-spark-3
• http://dev.classmethod.jp/etc/apache-
spark_rdd_investigation/
• http://qiita.com/FKuro_/items/3b34f9f64a17c
73ccdd4
• 今回の資料は、Learning Spark自体や書籍に関する勉強会
資料、更にはSparkに関して公開している資料を参考にしな
がら、社内の勉強会向けに作成したものです
• もし、この資料に関して、内容の訂正・削除の必要がある場
合は、こちらのメールアドレスまで連絡をお願いします
– akky.like.spark@gmail.com
– 資料に関するアドバイス、誤訳の指摘など、大歓迎です
• 今回のこちらの資料は会社の活動とは無関係ですので、会
社名は 伏せますが、資料を見たうえで勉強会に興味をもた
れた方は、同様にこちらのアドレスに連絡ください
– 特に、弊社は機械学習に力を入れておりますので、MLlibに関し
て興味がある方は、大歓迎ですので、宜しくお願い致します
• 当資料では、RDDとRDDsに関する違いは無いと判断
し、文書中では元の書籍の表現がどうあれ、RDDで統
一しています
– 使い分けが必要である場合は、もう一度見直しますので、
ご指摘をお願いします
• 本文書のサンプルは、基本Scalaに関してのみ記載し
ています。元の書籍にPythonしか無いものも、一部
はScala版のサンプルも用意しています
• 基本的に元の書籍と1対1で訳文を用意しています
が、一部、意味の無い文書は省略しています
– 重要な文書を省略していると思われる場合は、ご連絡い
ただければ、対応いたします
本編
This Chapter Introduces
• Sparkにおけるデータ(RDD)の取り扱いを説
明する
• Sparkにおける全ての操作は、RDDの生成、
RDDの変換、RDDの計算で表される
• データサイエンティストもエンジニアも、この
章を読んでほしい
• 出来れば、手元で動作確認をしながら読んで
欲しい
• コードはGitHubで公開している
RDD Basics(1)
• RDD(Resilient Distributed Datasets)はイミュータブル
(不変)な分散コレクションである
• RDDは複数のパーティションに分割され、それぞれ異なる
ノードで処理される
• RDDは、ユーザオブジェクトを含む、Python、Java、Scala
のオブジェクトを含むことが出来る
• 外部のデータセットを読み込むか、ドライバを用いてコレク
ションオブジェクトを配布することで生成出来る
• 遅延計算される
– 計算を行うタイミングをスケジューリングされたあと、計算される
val lines = sc.textFile(“README.md”)
例3-1:
RDD Basics(2) 補足①
• Sparkアプリケーションを起動する側(メインプログラム)をdriverdriverdriverdriverと呼ぶ
– ユーザがRDDの返還を記述したプログラム
• 各マシン(ワーカーノード)上で分散して実際に稼動する側(プロセス)を
executorexecutorexecutorexecutorと呼ぶ
– ワーカ上で動作し、実際の計算処理を
担当する
• 共有変数
– Sparkでは、各executorに定数を転送
したり、各executorで集計した値を
driverで受け取ったりする機能がある
• Sparkの実行はexecutorで行われるので、Sparkで変数に対して行われた変更
はdriver側には反映されない
• 当然、executor間で参照し合うことも出来ない
• そのため、driverとexecutorとの間で値を共有するための仕組みがSparkに
は用意されている
– ブロードキャスト変数は、driverで定義した
定数(固定値)を各executorに転送する為の変数
– Scalaで記述する場合は、定数を共有することが
出来るが、非効率
val rdd = sc.makeRDD(Seq(123, 456, 789))
val CONSTANTCONSTANTCONSTANTCONSTANT = sc.broadcastbroadcastbroadcastbroadcast(123)
val filter = rdd.filter(_ != CONSTANT.valueCONSTANT.valueCONSTANT.valueCONSTANT.value)
filter.foreach(println)
RDD Basics(3) 補足②
• RDDがイミュータブルである必要がある理由
– Sparkでは、大量おデータをオンメモリで分散処理するので、
各サーバに分散配置されたデータが処理中に欠損した場合に
備えた仕組みが必要
– 欠損に備えつつ、ネットワーク転送を出来る限り避けたい
• 得たいデータが失われていたら、前のデータから再作成する、
という アプローチをとっている
– このため、RDDはイミュータブルである必要がある
RDD Basics(4) 補足③
RDD Basics(5)
• 作成したRDDには、二つの操作が適用できる
– Transformations:RDDから別の新しいRDDを生成出来る
– Actions:RDDに対して処理を適用した結果を出力する
• Transformationsの例として、条件に一致する要素を抽出
して、新しいRDDを作成するフィルタリングがある
• 例3-2に示すように、単語のPythonが含まれている文字列
だけを保持する新しいRDDを作成するためにこれを使用する
ことができます
val lineWithSpark = lines.filter( line => line.contains("Spark") )
例3-2:
RDD Basics(6)
• Actionsは、RDDに基づいて計算し、結果をドライバプログラ
ムに戻すか、外部記憶装置(例えば、HDFS)に保存するか、
いずれかを行う
• Actionsの例として、RDDから最初の1要素を抽出する
first()がある
lineWithSpark.first()
例3-3:
• TransformationsとActionsは、RDDを処理する際の動作が
異なる
– RDDをいつでも定義することができるが、最初に使用される時まで
処理は実行されない(遅延実行)
– このアプローチは一般的では無い様に見えるが、ビッグデータで作
業しているとき、多くの意味を持つかもしれない
RDD Basics(7)
– フィルタを行う際にファイルを読み込む際、ファイル内のすべての行
をロードすることは、スペースの多くを無駄に消費することになる
– スパークはTransformationsのチェーン全体で必要なデータだけ処
理することができる
– first()アクションにおいて、Sparkは最初の1行が見つかるまでファ
イルをスキャンするが、ファイル全体を読み取ることは無い
RDD Basics(8)
• RDDはActionsの実行の度に処理される
• RDDを複数のActionsで再利用したい場合は、RDD.persist()で永続化する必要がある
• Sparkは、最初に計算した後にメモリ内のデータを保存し、将来Actionsで再利用すること
が出来る
• デフォルトでは永続化しない仕様が珍しいかもしれないが、大きなデータセットの場合に意味
ある仕様となる。RDDを再利用せず、処理に必要なデータはストリーム経由で取得できる場
合は、ストレージスペースを無駄にする理由は無い
• データの一部をメモリ上に永続化し、繰り返しクエリを発行するときに使うことが多いだろう
lineWithSpark.persist()
lineWithSpark.count()
lineWithSpark.first()
例3-4:
RDD Basics(9)
• まとめ
– 外部データから入力用RDDを作る
– filter()のようなtransformationsを使い入力用RDDを変換することで、新しいRDDを作
成する
– 再利用するRDDをpersist()で永続化出来る
– ActionsはRDDを分散処理する
• TIPS
– cache()もデフォルト設定でpersist()を実行したのと同じ結果を得られる
Creating RDD
• RDDの作り方には2種類存在する
– 外部データセットを読み込む方法
– コレクションを並列化(Parallelizing)させる方法
• 外部データセットの読み込みに関する説明は既に実施済み
• 簡単なのは、sc.parallelize()を使用する
– 既に存在するコレクションをSparkContextの並列化メソッドに渡すことである
– シェルの中で独自のRDDを作成し、実行することが出来るので、学習の際には便利
– 1マシン上のメモリに全体のデータセットを持っていることを必要とすることは認識しておく必要があります
(よって、プロトタイプやテスト以外では、広く使用されない)
– RDDを作成する、より一般的な方法は、外部記憶装置からデータをロードすることである
val lines = sc.parallelize(List("pandas", "i like pandas"))
例3-6:
val lines = sc.textFile("/path/to/README.md")
例3-9:
RDD Operations(1)
• RDDは2種類の操作をサポートしている
– TransformationsとActionsがある
• Transformationsは新しいRDDを返す
– map() や filter() など
• Actionsはドライバーに計算結果を返すか、ストレージに結果を書き込む操作である
– count() や first()など
• TransformationsとActionsは非常に違うので、使う操作の種類を理解することは非常に重要
– 種類に関して混乱してしまった場合は、戻り値の型を見ればよい
RDD Operations(2) Transformations①
• Transformationsは新しいRDDを生成する
• RDDに対してActionsが実行されるまで、transformationsは実行されない(遅延評価)
• 多くのtransformationsは“要素指向”で、各要素に対して作用する
– 例えば、MATLABの配列同士の乗算は、要素同士の乗算になる(C = A.*B)
• ログファイルlog.txtからエラーメッセージを抽出する例を見る
– 以前に見たfilter()を使用する
• filter()が既存のinputRDDを変更しないことに注意してください。
• 代わりに新しいRDDが生成されます
• inputRDDを後でプログラム内で再利用することができる(例えば、他の単語を検索するなど)
• 再度、"warning"を検索する為に、inputRDDを使用してみるとしましょう
val inputRDD = sc.textFile("log.txt")
val errorsRDD = inputRDD.filter(line => line.contains("error"))
例3-12:
RDD Operations(3) Transformations②
• そこで、"error"もしくは"warning"を含む行を検索する為に、transformation:union()を使う
• union()は2つのRDDを処理するところがfilter()と違う
• transformationは、任意の数のRDDをInputに処理することが出来る
• TIP
– 例3-14と同じ結果を得るための良い方法は、単純に"error"もしくは"warning"を一度検索し、
同様に残りの一方でフィルタすることである
– 系統グラフについて
• Sparkは、異なるRDD間の依存関係のセットを追跡する(系統グラフ)
• 必要に応じて各RDDを計算する際に永続したRDDの一部が
失われた場合に、回復するためにこの情報を使用する
• 図3-1は、例3-14のための系統グラフを示している
• DAG(Directed Acyclic Graph:有向非循環グラフ)ともいう
例3-14:
val errorsRDD = inputRDD.filter(line => line.contains("error"))
val warningsRDD = inputRDD.filter(line => line.contains("warning"))
val badLinesRDD = errorsRDD.union(warningsRDD)
図3-1
RDD Operations(4) Actions①
• Actionsは、データセットに対して何かを実行し、ドライバに値を戻すか、ストレージに何かを
出力する操作である
• Actionsが呼ばれた際に、RDDのために必要なTransactionsの評価を強制する
• 前のセクションから続いているログ処理を続けて、badLinesRDDに関する情報を出力する方法を見
ていく
– count():データの件数を返す
– take():
• 指定した件数の要素を返す
• ローカルで反復した後、ドライバに情報を出力する
例3-16:
println("Input had " + badLinesRDD.count() + " concerning lines")
println("Here are 10 examples:")
badLinesRDD.take(10).foreach(println)
RDD Operations(5) Actions②
• Collect()について
– RDD全体を取得するために、 collect()というactionsも用意されている
– プログラムがRDDを非常に小さいサイズにフィルタし、ローカルでフィルタしたRDDを取り扱
いたい場合に非常に便利です
– collect()を使用する場合、全体のデータセットが単一のマシン上のメモリに収まらなければな
らない点に注意してください。collect()を大規模なデータセットで使用すべきではありません
– ほとんどの場合RDDは大きすぎる為、collect()で収集しきれない
– これらのケースでは、HDFSやAmazon S3などの分散ストレージシステムにデータを書き込む
ことが一般的
• saveAsTextFile()やsaveAsSequenceFile() を用いてRDDの内容を保存することが出来る
• 第5章にて、データをエクスポートするためのさまざまなオプションを説明する
• 新しいactionを呼び出す度にRDD全体が最初から再計算されなければならないことに注意する必要
がある
• この非効率性を回避するために、persist()もしくはcache()を使って、中間結果を永続化することが
できる
RDD Operations(6) Lazy Evaluation(遅延評価)①
• 既に述べた通り、transformationsは遅延評価される。それはSparkはactionを認識するまで実行
しないことを意味する
• 慣れないユーザからすると直観に反していますが、Haskell・LINQのようなのような関数型言語を使
用している人には慣れていることでしょう
• 遅延評価は、RDDに対するtransformationを呼び出す時(例えば、map())、操作はすぐに実行されな
いことを意味します
• 代わりに、Sparkは内部的にメタデータをこの操作が要求されたことを示すために記録します
• RDDに特定のデータが含まれていると考えるのではなく、transformationsを通じてデータを計算
する方法の手順が各RDDから構築されていると考えるのがベストです
• RDDへのデータのロードはtransformationsと同様に遅延評価が行われます
• sc.textFile()を呼び出した際、必要になるまでデータはロードされません。transformations同様に、
操作が複数回発生する可能性があります
• TIP
– transformationsは遅延評価されるが、count()のようなactionを実行することで、実行を強制することが出来る
– これは、プログラムの一部だけをテストする簡単な方法だ
– Sparkは一緒の操作をグループ化することによって、データの引継ぎを行うパスの数を減らすために、遅延評価を使用する
– HadoopのMapReduceのようなシステムでは、開発者は多くの場合、MapReduceのパスの数を最小限に抑えるために、操作の
グループ化への考慮に多くの時間を費やす必要がある
– Sparkでは多くの簡単な操作のチェーン化を行う代わりに、単一の複雑なMapを記述することに、実質的な利点は無い
– このため、ユーザ(プログラマ)は彼らのプログラムを管理できる単位に、自由に細分化することが出来る
Passing Functions to Spark(1)
• 殆どのSparkのtransformationsや一部のactionsは、データを計算するためにSparkに
よって使用される関数を渡すことに依存している
• コア言語(Python, Scala, Java)はそれぞれ、僅かに異なるSparkに関数を渡すための
メカニズムを保有する
• Python
– Pythonでは3つの形式を用いることが出来る(ラムダ式、トップレベル、ローカル)
– 関数を渡す時に注意する必要がある問題の一つは、誤って関数を含むオブジェクトをシリアル
化することである
– オブジェクトのメンバーである、またはオブジェクト内のフィールドへの参照を含む関数を渡
すと(例:self.field)、Sparkはワーカーノードに全体のオブジェクト(全ての データ)を
送信する為、必要とする情報のビット数よりもはるかに大きくなってしまう
– もしクラスがPythonがpickle化することが出来ないオブジェクトを含んでいる場合、プログラ
ムが失敗することがある
例3-18:
word = rdd.filter(lambda s: "error" in s)
def containsError(s):
return "error" in s
word = rdd.filter(containsError)
Passing Functions to Spark(2)
例3-19:Passing a function with field references (don’t do this!)
class SearchFunctions(object):
def __init__(self, query):
self.query = query
def isMatch(self, s):
return self.query in s
def getMatchesFunctionReference(self, rdd):
# Problem: references all of "self" in "self.isMatch"
return rdd.filter(self.isMatch)
def getMatchesMemberReference(self, rdd):
# Problem: references all of "self" in "self.query"
return rdd.filter(lambda x: self.query in x)
代わりにローカル変数にオブジェクトから必要な項目を抽出し、Python関数を渡す
例3-20:Python function passing without field references
class WordFunctions(object):
...
def getMatchesNoReference(self, rdd):
# Safe: extract only the field we need into a local variable
query = self.query
return rdd.filter(lambda x: query in x)
Passing Functions to Spark(3)
例3-21:Scala function passing
class SearchFunctions(val query: String) {
def isMatch(s: String): Boolean = {
s.contains(query)
}
def getMatchesFunctionReference(rdd: RDD[String]): RDD[String] = {
//注意:全データを参照してしまう
rdd.map(isMatch)
}
def getMatchesFieldReference(rdd: RDD[String]): RDD[String] = {
//注意:全データを参照してしまう
rdd.map(x => x.split(query))
}
def getMatchesNoReference(rdd: RDD[String]): RDD[String] = {
// Safe: extract just the field we need into a local variable
val query_ = this.query
rdd.map(x => x.split(query_))
}
}
• Scala
– Scalaでは、Scalaの他の機能的なAPIの為に、インラインに定義された関数内のメソッド、関数への参照、静的
な関数を渡すことが出来る
– いくつかの他の考慮事項は、関数を渡し、その中で参照されているデータはSerializableである(Javaの
Serializableインタフェースを実装する)必要がある
– さらにPythonのように、オブジェクトのメソッドやフィールドを渡すと、そのオブジェクト全体への参照が含
まれてしまう
– 例3-20のPython同様に例3-21に示すように、我々はローカル変数に必要項目を抽出することで、オブジェク
ト全体を渡すことから回避することが出来る
– もしNotSerializableExceptionがScalaで発生した場合は、シリアル化不可能なクラスのメソッド
やフィールド への参照は通常問題になる
– トップレベルのオブジェクトのメンバーである、シリアル化可能なローカル変数や関数を渡す
ことは常に安全であることに注意する必要がある
• Java
– Javaでは、関数はSparkの機能に関するInterface(org.apache.spark.api.java.functionパッケー
ジ)の一つを実装することで、機能は提供されます
– 関数の戻り型に基づいて、異なるインターフェイスの数がある
– 表3-1にて最も基本的な機能のインターフェースを示す
– Javaでは、Key/Valueのような特別な型を戻す必要がある時のために、他のInterfaceの数をカ
バーしている
Passing Functions to Spark(4)
Function nameFunction nameFunction nameFunction name Method to implementMethod to implementMethod to implementMethod to implement UsageUsageUsageUsage
Function<T, R> R call(T) Take in one input and return one output,
for use with operations like map() and
filter().
Function2<T1, T2, R> R call(T1, T2) Take in two inputs and return one output,
for use with operations like aggregate() or
fold().
FlatMapFunction<T, R> Iterable<R> call(T) Take in one input and return zero or more
outputs, for use with operations like
flatMap().
表3-1
– インライン匿名内部クラス(例:3-22)として機能クラスを定義する、または名前付きクラスを作成すること
が出来る
Passing Functions to Spark(4)
例3-22:Java function passing with anonymous inner class
RDD<String> errors = lines.filter(new Function<String, Boolean>() {
public Boolean call(String x) { return x.contains("error"); }
});
例3-23:Java function passing with named class
class ContainsError implements Function<String, Boolean>() {
public Boolean call(String x) { return x.contains("error"); }
}
RDD<String> errors = lines.filter(new ContainsError());
– 選択するスタイルは個人的な好みであるが、トップレベルの名前付きの関数は、多くの場合大規模なプログラ
ムを編成するためのクリーナーであることを見出した
– 例3-24に示すように、トップレベルの機能の利点の一つは、コンストラクタのパラメータを与えることが出
来ることである
例3-24:Java function class with parameters
class Contains implements Function<String, Boolean>() {
private String query;
public Contains(String query) { this.query = query; }
public Boolean call(String x) { return x.contains(query); }
}
RDD<String> errors = lines.filter(new Contains("error"));
– Java8では、簡潔に関数のインターフェースを実装する為にラムダ式を使用することが出来ます
– Java8は、この文章を書いている時点では比較的新しく、当書の例では、以前のバージョンのJavaの構文を用
いてクラスを定義しします
– ラムダ式を用いた例を例3-25で例示します
例3-25:Java function passing with lambda expression in Java 8
RDD<String> errors = lines.filter(s -> s.contains("error"));
– もし、Java8のラムダ式を使用することに興味がある場合は、OracleのマニュアルとSparkでラムダ式を使用
する方法について記述されたDatabricksのブログ記事を参照して下さい
– TIP
• 匿名内部クラスとラムダ式の両方において、どのようなfinal変数でもそれを囲む方法で参照することが
出来るので、PythonやScalaのようにこれらの変数を渡すことが出来る
Passing Functions to Spark(5)
• 序文
– この章では、Sparkの中で最も一般的なtransformationsとactionsを見ていく
– 追加の操作は、特定のタイプのデータを含むRDDで利用可能
• 例:統計関数によりRDDを操作する/KeyValueのRDDをキー毎に集計する
– 後のセクションにおいて、RDDの種類とこれらの特別な操作の間の変換をカバーします
• Basic RDD
– データに関係なく全てのRDDに対して実行できるtransformationsとactionsについて、記載することとする
– Element-wise transformations(要素毎のtransformations )
• おそらく、最も一般的で使用されるtransformationsはmap()とfilter()です
• map()は関数を取りこみ、RDDの各要素に対して関数を適用し、その結果を新しいRDDの各要素に適用し
ます
• filter()は関数を取りこみ、関数を用いてフィルタ条件に合致する要素で新しいRDDを戻します
Common Transformations and Actions(1)
• 自分がコレクションしているURLに関連づいているウェブサイトを取得するかのように、任意の数字の
二乗を行うためにmap()を使用することが出来ます(?)
• map()の戻り値の型は、入力の型と一致する必要はありません
Common Transformations and Actions(2)
例:3-27. Scala squaring the values in an RDD
val input = sc.parallelize(List(1, 2, 3, 4))
val result = input.map(x => x * x)
println(result.collect().mkString(","))
• 自分がコレクションしているURLに関連づいているウェブサイトを取得するかのように、任意の数字の二乗を行う
ためにmap()を使用することが出来ます(?)
• map()の戻り値の型は、入力の型と一致する必要はありません
• 時折、各入力要素に対応した複数の出力を必要とすることがあります
• この操作はflatMap()と呼ばれています
• Map()同様、flatMap()に渡された関数は、入力RDD内の要素毎に個別に呼ばれます
• 単一の要素を返す代わりに、戻り値とイテレータを戻す
• イテレータのRDDを生成するよりはむしろ、イテレータの全ての要素から構成されるRDDを得る
• flatMapの単純な使用例は、入力された文字列を分割するものである
例3-30:flatMap() in Scala, splitting lines into multiple words
val lines = sc.parallelize(List("hello world", "hi"))
val words = lines.flatMap(line => line.split(" "))
words.first() // returns "hello"
Common Transformations and Actions(3)
• flatMap()とmap()の違いを説明します
• リスト形式のRDDではなく、リスト形
式の要素を持つRDDを戻すことが出来
るので、flatMap()についてイテレータ
を「フラット化するもの」のように考
えることが出来ます(?)
– Pseudo set operations(擬似集合演算(操作))
• RDD自身について、要素に欠落がある場合でも、RDDはunion()やintersection()などの多くの数学的な操
作をサポートしています(?)
• 4つの操作について、図3-4に示します
• これらの操作は、操作対象のRDDが全て同じタイプである必要がある点に注意してください
• Distinct()
– 最も頻繁に発生するRDDの欠落は、我々もよくデータを重複させるように、要素の一意性に関して
です
– ユニークな要素が必要な場合、ユニークな要素と新しいRDDを生成するRDD.distinct()
transformationを使用することが出来ます
– 各要素の1つのコピーのみを受け取ることを保証するために、ネットワーク上(クラスタ上?)の
全データをシャッフルする必要があるため、distinct()は負担が大きいことに留意してください
– シャッフルに関して、およびそれをどのように回避するかは、第4章で詳しく説明されています
• union()
– 最も単純な集合演算(操作)はunion()です、それは両方のソースデータから構成されるRDDを戻す
ものです
– これは、多くのソースからログファイルを処理するようなユースケースの場合に有用です
– 数学的なunion()と異なり、入力のRDDに重複が存在する場合、Sparkのunion()の結果には重複が含
まれます(必要に応じて、distinct()を併用することで修正することが可能です)
• intersection()
– 最も単純な集合演算(操作)はunion(other)である、それは両方のソースデータから構成される
RDDを戻すものです
– Sparkは両方のRDDから要素だけを戻すintersection(other)関数を提供します
– intersection()は全ての重複を排除します(シングルRDDの重複を含む)
– intersection() and union()は類似した概念でありますが、intersection()は共通の要素を識別する
ために、ネットワークを介したシャッフルを必要とするので、パフォーマンスは遥かに悪いです
– 時々、パフォーマンスへの考慮からデータを削除する必要があります
Common Transformations and Actions(4)
• subtract()
– subtract()関数は、二つのRDDの差分を返します。subtract()関数は別のRDDを引数にとり、引数に
指定したRDDには存在せず、最初のRDDにだけ存在するRDDを戻します
– intersection()のようにシャッフルを行います
• cartesian()
– 二つのRDD間の直積を計算する事が出来ます
– cartesian() transformationは全ての対を返します
– 各々のオファーに対する全てのユーザの期待興味を計算するような、全ての可能なペアの類似性を
考慮したい場合に、cartesian()は役に立ちます
– RDD自身とのcartesian()を実行することが出来ます、それはユーザ類似のようなタスクの際に
役立ちます
– しかし、巨大なRDDの場合、cartesian()は非常に高価であることに注意してください
Common Transformations and Actions(5)
Common Transformations and Actions(6)
関数名関数名関数名関数名 目的目的目的目的 実装例実装例実装例実装例 結果結果結果結果
map() 関数をそれぞれの要素に 適用し、結果のRDD
を返す
rdd.map
(x=>X+1)
{2,3,4,4}
flatMap() RDDの各要素に関数を適用し、イテレータの内
容のRDDを戻す。しばしば、単語を抽出する為
に使用される
rdd.flatMap
(x=>x.to(3))
{1,2,3,2,3,3,3}
filter() フィルタ条件に合致する要素だけから構成され
るRDDを返す
rdd.filter
(x=>!=1)
{2,3,3}
distinct() 重複を排除する rdd.distinct() {1,2,3}
sample(WithReplacement,
fraction, [seed] )
置換の有無に関係なく、サンプルを抽出する rdd.sample
(false, 0.5)
Nondeterminist
ic
• 表3-2:基本的なRDD transformations
※ 実装例のRDDの内容:{1, 2, 3, 3}
Common Transformations and Actions(7)
関数名関数名関数名関数名 目的目的目的目的 実装例実装例実装例実装例 結果結果結果結果
union() 両方のRDDの要素を 含むRDDを生成する rdd.union(other) {1, 2, 3, 3, 4, 5}
intersection() 両方のRDDに含まれる要素だけを含んだRDD
を生成する
rdd.intersection
(other)
{3}
subtract() 対象のRDDから要素を削除する
(例:トレーニングデータを削除する)
→対象のRDDと引数で
指定したRDDの共通
要素を対象のRDD
から削除する
rdd.subtract
(other)
{1, 2}
cartesian() 引数で渡したRDDとの直積のRDDを生成する rdd.Cartesian
(other)
{(1, 3), (1, 4), …
(3, 5)}
• 表3-3:二つのRDDによる transformations
※ 実装例のRDDの内容:{1, 2, 3}{3, 4, 5}
– Actions
• おそらく最も使用する、RDD上の最も一般的なActionはreduce()です。それはRDDの2つの要素を使用し、
同じ型の新しい要素を返す機能です
• この機能の簡単な例は「+」であり、RDDの合計を計算するために使用できます
• reduce()は、要素の合計を計算し、要素の数をカウントし、他の種類の集計を実行することが出来ます
• reduce()と同様の処理としてfold()がありますが、これは各パーティション上の最初の呼出に使用される
0値を必要とする点である
• 提供される0値は、操作における基準(=アイデンティティ要素)であるべきです。機能で複数回適用す
る事で、値を変更してはいけません(例えば、+の場合は0、*の場合は1、または連結の場合は空リス
ト)
• TIP
– fold()
» 2つのパラメータのうち、最初のオペレータを修正することで、fold()によるオブジェクト
の生成を最小限に抑えることが出来ます
» ただし、第二のパラメータを変更してはなりません
» fold()やreduce()は共に、戻り値の型と操作するRDDの属性が同じ型である必要があります
» この仕様は合計を計算するような操作には適していますが、時には異なる型を必要とするこ
とがあります
» 例えば、移動平均を計算するとき、数値の要素とカウントの経過を追跡し、ペアとして取得
する必要があります
» 最初に全ての要素を(関数を適用することで)別の要素に変換するmap()を最初の変数に使用
することで、必要とする型を戻し、reduce()はペアで作業できるようになります
Common Transformations and Actions(8)
例3-33: Scala における reduce()の例
val sum = rdd.reduce((x, y) => x + y)
Common Transformations and Actions(9)
– aggregate()
» aggregate() 関数は、戻り値の型がRDDと同じ型である制約から、私たちを解放します
(fold()のように、戻り値で必要とする型を返す為に、「zero value」を指定する必要がある
ように)
» 次に、アキュムレータとのRDDの要素を結合する機能を提供します
» 最後に、各ノードに独自の計算結果を蓄積していることを考えると、2つのアキュムレータ
をマージする第二の機能を提供する必要があります
» aggregate()を使用して平均を計算する例を示します(map()を使用せずに、RDDの平均を計
算する例を示します)
例3-36: Scala における aggregate() の例
val result = input.aggregate((0, 0))(
(acc, value) => (acc._1 + value, acc._2 + 1),
(acc1, acc2) => (acc1._1 + acc2._1, acc1._2 + acc2._2))
val avg = result._1 / result._2.toDouble
Common Transformations and Actions(10)
Accumulatorに関する補足
– アキュムレーター(accumulator)は、“追加”のみを行う変数
– driverでアキュムレーターを生成し、各executorでアキュムレーターに対して値の追加
(加算・蓄積)を行い、driverでその結果(総計)を受け取ることが出来る
– アキュムレーターは、Hadoopのカウンターのようなもの(Hadoopでは、各タスクでカウンターに
値を加算していく)
– ただし、Hadoopのカウンターの結果はアプリケーション内からは利用できない(Mapタスクで
集計したカウンターをReduceタスクで読み込むことは出来ない)が、Sparkのアキュムレーター
はアプリケーション内の後続処理に利用することが出来る
– アキュムレーターはvalueというフィールドを持っており、アキュムレーターの「+=」メソッドを
使うと、valueに対して追加(加算)が実行される
val rdd = sc.makeRDD(Seq(1, 2, 3))
val sum = sc.accumulator(0)
rdd.foreach(sum += _)
println(sum.value)
– collect()
» RDD上のいくつかのactionsは、driverにデータの一部または全部を通常のコレクションまた
は値の形式で返します
» driverにデータを戻す最も単純で一般的な操作はcollect()で、それはRDD全体の内容を返し
ます
» collect()は一般的に、RDDと期待結果を比較することが簡単に出来ることから、RDD全体が
メモリに収まることを前提にユニットテストに使用されます
» collect()には、全てのデータをdriverにコピーする必要があるので、全てのデータが単一の
マシンに収まる必要がある、という制限があります
– take(n)
» take(n)はn個の要素をRDDから取得しますが、それはアクセスするパーティションの数を最
小限にするので、取得できるコレクションは偏ってしまうかもしれません
» この操作が期待する順序で要素を返さない点に注意することは重要です
» これらの操作(collect()、take(n))は、ユニットテスト及びデバッグには有用ですが、大量
のデータを扱う場合、ボトルネックを引き起こすかも知れません
– top(n)
» もし、データに順序性がある場合は、top()を使用してRDDからトップ要素を抽出することが
出来ます
» top()はデータ自体の順序を使用しますが、トップ要素を抽出する為に、自分の比較関数を
供給することが出来ます
– takeSample(withReplacement, num, seed)
» 時々、driverはサンプルデータを必要とします
» takeSample(withReplacement, num, seed)機能は交換することなく、データのサンプルを取
得することが出来ます
Common Transformations and Actions(11)
– foreach()
» 時には、driverに結果を返すことなく、RDD内のすべての要素に対してactionを実行するこ
とが有用です
» この良い例は、WebサーバにJSONをPOSTしたり、DBにレコードを挿入することです
» いずれの場合も、foreach() actionは、ローカルに戻ることなく(driverに戻ることなく)、
RDDの各要素の計算を行うことが出来ます
– その他の基本的なRDDの操作は、名前から想像されるように振る舞います
– count()は要素数を返し、countByValue()は固有値と固有値毎の要素数を紐づけて返します
Common Transformations and Actions(12)
関数名関数名関数名関数名 目的目的目的目的 実装例実装例実装例実装例 結果結果結果結果
collect() 全ての要素をRDDから戻す rdd.collect() {1, 2, 3, 3}
count() RDDの要素数を戻す rdd.count() 4
countByValue() 各々の要素のRDD内の数を
戻す
rdd.countByValue() {(1, 1), (2, 1), (3, 2)}
take(num) RDDからnum個の要素を
戻す
rdd.take(2) {1, 2}
• 表3-4:基本的なactions
※ 実装例のRDDの内容:{1, 2, 3, 3}
Common Transformations and Actions(13)
関数名関数名関数名関数名 目的目的目的目的 実装例実装例実装例実装例 結果結果結果結果
top(num) トップnum個の要素をRDD
から戻す
rdd.top(2) {3, 3}
takeOrdered(num)
(ordering)
指定された順序に基づいて、
num個の要素を戻す
rdd.takeOrdered(2)(
myOrdering)
{3, 3}
takeSample
(withReplacement,
num,
[seed])
ランダムにnum個の要素を
戻す
rdd.takeSample(fals
e, 1)
Nondeterministic
reduce(func) 複数のRDDの要素を並行に
組込む(例:合計する)(?)
rdd.reduce
((x, y) => x + y)
9
fold(zero)(func) reduce()同様。ただし、
0を指定する必要がある
rdd.fold
(0)((x, y) => x + y)
9
Aggregate
(zeroValue)
(seqOp, combOp)
reduce()同様。ただし、
違う型を戻す場合に使用
する
rdd.aggregate
((0, 0)) ((x, y) =>
(x._1 + y, x._2 + 1),
(x, y) => (x._1 +
y._1, x._2 + y._2))
(9, 4)
foreach(func) RDDの各要素に与えられた
関数を適用する
rdd.foreach(func) Nothing
• Converting Between RDD Types(RDDの型の変換)
– いくつかの関数は、RDDの特定の型だけで利用可能です(例えば、Key/Valueのペアを使用したjoin()、数値の
RDDを使用したmean()/variance())
– 第6章で数値のRDDでしか使用できない関数を、第4章でKey/ValueのペアのRDDでしか使用できない関数を説
明します
– ScalaとJavaでは、これらの方法は標準的なRDD上では定義されていないので、この追加機能を利用する為に、
正しい専用のクラスを得る必要があります
– Scala
• Scalaにおける特別な機能によるRDDへの変換は(例:RDD[Double]をnumericを必要とする機能に公開す
る際)、暗黙的な変換によって、自動的に行われます
• 「SparkContextの初期化」で述べた通り、これらの変換を動作させるために、
「import org.apache.spark.SparkContext._ 」を追記する必要があります
• SparkContextオブジェクトのScalaDocに、暗黙的な変換に関する記述を見ることが出来ます
• mean()やvariance()のような追加機能を公開する為に、暗黙的にRDDを変換するラッパークラスを用意し
ます(DoubleRDDFunctions(数値データのRDDのため)、PairRDDFunctions(Key/Valueペアのため)
のような)
• 暗黙の変換は非常に強力ながら、時には混乱することがあります
• RDDのmean()のような関数を呼び出す場合は、RDDクラスのScaladocsを確認し、mean()が存在しないこ
とに気づきます
• RDD[Double]とDoubleRDDFunctionsの暗黙的な変換の成功のために、呼出側が管理しています
• ScaladocでRDDの機能を検索する場合は、ラッパークラスで利用可能な機能を確認してください
Common Transformations and Actions(14)
– Java
• Javaにおける特殊なRDDへの変換は、もう少し明示的に行う必要があります
• 具体的には、これらの型用のメソッドを追加した、これらの型のRDDのためのJavaDoubleRDDと
JavaPairRDDと呼ばれる特別なクラスがあります
• これは、正確に何が起きているのかをより深く理解できるという利点を持っていますが、少し厄介でもあ
ります(ソースの可読性は高くなるが、実装者に負担を与える、ということかな?)
• これらの特別な型のRDDを作るために、Functionクラスを使用する代わりに、特殊なバージョンを使用す
る必要があります
• もし、型TのRDDからDoubleRDDを生成する場合は、Function<T, Double>よりむしろ、
DoubleFunction<T>を使用します
• 表3-5にて、専門化された機能とそれらの用途を示します
• 私たちは、RDDの様々な関数を呼び出す必要があります(よって、単純にDoubleFunctionを生成し、
map()に渡すことは出来ません)
• DoubleRDDを戻してほしい場合、map()を呼ぶ代わりに以降の他の機能と同じパターンで、mapToDouble()
を呼ぶ必要があります
Common Transformations and Actions(15)
関数 代替手段 用途
DoubleFlatMapFunction<T> Function<T, Iterable<Double>> DoubleRDD from a
flatMapToDouble
DoubleFunction<T> Function<T, double> DoubleRDD from mapToDouble
PairFlatMapFunction<T, K, V> Function<T, Iterable<Tuple2<K, V>>> PairRDD<K, V> from a
flatMapToPair
PairFunction<T, K, V> Function<T, Tuple2<K, V>> PairRDD<K, V> from a mapToPair
• 序文
– 前述したように、Spark RDDは遅延評価され、時には同じRDDを複数回使用することがあるかもしれません
– 単純にRDDを複数回使用すると、Sparkは使用したRDDとその依存関係にあるRDDをactionを呼び出す度に再計
算します
– データを多回数参照するような、反復アルゴリズムにおいて、特に高価になります
– 例3-39に示すように、別の簡単な例では、同じRDDをカウントし、出力しています
– RDDの複数回の計算を回避する為に、Sparkにデータを永続させることが出来ます
– RDDを永続化することをSparkに依頼する場合、RDDを実行しているノードはそのパーティションを格納します
– もし、データを永続化しているノードに障害が発生した場合、Sparkはデータを必要とされるタイミングで失
われたパーティションを再計算します
– もし、ノード障害への対応によるスローダウンを避けたい場合、複数のノードにデータを複製することが出来
ます
– Sparkは永続化に関して目的に合わせて選択できるように、多くのレベルを持っています(表3-6で確認する
ことが出来ます)
– Scala(例3-40)やJavaでは、persist()のデフォルトの仕様は、シリアライズ化されていないオブジェクトと
してJVMヒープ領域にデータを格納します
– Pythonでは、常にデータを永続化・保存する際はシリアル化します、デフォルトは塩漬けされたオブジェクト
としてJVMのヒープ領域に格納されます
– データをディスクやヒープ以外のストレージに出力した場合は、そのデータは常にシリアル化されます
Persistence (Caching)①
例3-39:Scalaにおける重複実行
val result = input.map(x => x*x)
println(result.count())
println(result.collect().mkString(","))
Persistence (Caching)②
Level Space
used
CPU
time
In
memory
On
disk
Comments
MEMORY_ONLY High Low Y N
MEMORY_ONLY
_SER
Low High Y N
MEMORY_AND
_DISK
High Mediu
m
Some Some Spills to disk if there is too
much data to fit in memory.
MEMORY_AND
_DISK_SER
Low High Some Some Spills to disk if there is too
much data to fit in memory.
Stores serialized
representation in memory.
DISK_ONLY Low High N Y
• 表3-6:永続化レベル(org.apache.spark.storage.StorageLevelとpyspark.StorageLevel)
※必要に応じて、ストレージレベルの末尾に“_2”を追加することで、二台のマシン上のデータを複製する
ことが出来ます
• TIP
– ヒープ外のキャッシングは実験的で、Tachyonを使用しています
– もしSparkのヒープ外のキャッシングに興味を持っている場合、"Running Spark on Tachyon guide(*)"を見て
みましょう
(*)http://tachyon-project.org/Running-Spark-on-Tachyon.html
(*)日本語の解説サイト:http://qiita.com/FKuro_/items/3b34f9f64a17c73ccdd4
– 最初のactionが実行される前に、呼び出したpersist()がRDDに通知されます
– persist()の呼出は、評価を強制するものではありません
– あまりにも多くのデータをキャッシュしようとすると、Sparkは自動的に最長未使用時間キャッシングポリ
シー(LRU)に従って、古いパーティションを追い出します
– ストレージレベルが”メモリのみ”の場合、これらのパーティションは再度アクセスされた際に再計算されま
す。ストレージレベルが”メモリとディスク”の場合、ディスクに出力されます
– いずれの場合も、Sparkに多くのデータをキャッシュさせたとしても、JOBの失敗を心配することが無いことを
意味します
– しかし、キャッシュ不要なデータは、データを有用な状態から遠ざけ、更なる再計算時間を必要とします
– 最後にRDDには、unpersist()と呼ばれるキャッシュから手動で削除するメソッドが存在します
Persistence (Caching)③
例3-40: Scala におけるpersist()
val result = input.map(x => x * x)
result.persist(StorageLevel.DISK_ONLY)
println(result.count())
println(result.collect().mkString(","))
• 本章では、RDDの実行モデルと多くの一般的な操作をカバーしました
• もしここまで読んできたのであれば、あなたはSparkにおける全てのコアコンセプトを学ぶことが出来ました
• 次の章では私たちは特別な操作のセットを可能にするKey/Valueのペアをカバーします。それは並列に集約するため
に最も一般的な方法です
• そのあと、我々は様々なデータソースとの入出力やSparkContextの挙動に関するより高度なトピックについて説明
します
• RDDが何故弾力性があると言われているかというと、常にRDDを再計算する能力があるからです
• RDDデータを保持する機械に障害が発生すると、Sparkは行方不明になったデータをユーザに意識させずに再計算し
ます
Conclusion(結論)

More Related Content

What's hot

HDFS新機能総まとめin 2015 (日本Hadoopユーザー会 ライトニングトーク@Cloudera World Tokyo 2015 講演資料)
HDFS新機能総まとめin 2015 (日本Hadoopユーザー会 ライトニングトーク@Cloudera World Tokyo 2015 講演資料)HDFS新機能総まとめin 2015 (日本Hadoopユーザー会 ライトニングトーク@Cloudera World Tokyo 2015 講演資料)
HDFS新機能総まとめin 2015 (日本Hadoopユーザー会 ライトニングトーク@Cloudera World Tokyo 2015 講演資料)NTT DATA OSS Professional Services
 
Apache Sparkに手を出してヤケドしないための基本 ~「Apache Spark入門より」~ (デブサミ 2016 講演資料)
Apache Sparkに手を出してヤケドしないための基本 ~「Apache Spark入門より」~ (デブサミ 2016 講演資料)Apache Sparkに手を出してヤケドしないための基本 ~「Apache Spark入門より」~ (デブサミ 2016 講演資料)
Apache Sparkに手を出してヤケドしないための基本 ~「Apache Spark入門より」~ (デブサミ 2016 講演資料)NTT DATA OSS Professional Services
 
Hadoopデータプラットフォーム #cwt2013
Hadoopデータプラットフォーム #cwt2013Hadoopデータプラットフォーム #cwt2013
Hadoopデータプラットフォーム #cwt2013Cloudera Japan
 
Hadoopの概念と基本的知識
Hadoopの概念と基本的知識Hadoopの概念と基本的知識
Hadoopの概念と基本的知識Ken SASAKI
 
Hadoopのシステム設計・運用のポイント
Hadoopのシステム設計・運用のポイントHadoopのシステム設計・運用のポイント
Hadoopのシステム設計・運用のポイントCloudera Japan
 
オライリーセミナー Hive入門 #oreilly0724
オライリーセミナー Hive入門  #oreilly0724オライリーセミナー Hive入門  #oreilly0724
オライリーセミナー Hive入門 #oreilly0724Cloudera Japan
 
FluentdやNorikraを使った データ集約基盤への取り組み紹介
FluentdやNorikraを使った データ集約基盤への取り組み紹介FluentdやNorikraを使った データ集約基盤への取り組み紹介
FluentdやNorikraを使った データ集約基盤への取り組み紹介Recruit Technologies
 
並列分散処理基盤Hadoopの紹介と、開発者が語るHadoopの使いどころ (Silicon Valley x 日本 / Tech x Business ...
並列分散処理基盤Hadoopの紹介と、開発者が語るHadoopの使いどころ (Silicon Valley x 日本 / Tech x Business ...並列分散処理基盤Hadoopの紹介と、開発者が語るHadoopの使いどころ (Silicon Valley x 日本 / Tech x Business ...
並列分散処理基盤Hadoopの紹介と、開発者が語るHadoopの使いどころ (Silicon Valley x 日本 / Tech x Business ...NTT DATA OSS Professional Services
 
40分でわかるHadoop徹底入門 (Cloudera World Tokyo 2014 講演資料)
40分でわかるHadoop徹底入門 (Cloudera World Tokyo 2014 講演資料) 40分でわかるHadoop徹底入門 (Cloudera World Tokyo 2014 講演資料)
40分でわかるHadoop徹底入門 (Cloudera World Tokyo 2014 講演資料) hamaken
 
HadoopとRDBMSをシームレスに連携させるSmart SQL Processing (Hadoop Conference Japan 2014)
HadoopとRDBMSをシームレスに連携させるSmart SQL Processing (Hadoop Conference Japan 2014)HadoopとRDBMSをシームレスに連携させるSmart SQL Processing (Hadoop Conference Japan 2014)
HadoopとRDBMSをシームレスに連携させるSmart SQL Processing (Hadoop Conference Japan 2014)Hadoop / Spark Conference Japan
 
サポートメンバは見た! Hadoopバグワースト10 (adoop / Spark Conference Japan 2016 ライトニングトーク発表資料)
サポートメンバは見た! Hadoopバグワースト10 (adoop / Spark Conference Japan 2016 ライトニングトーク発表資料)サポートメンバは見た! Hadoopバグワースト10 (adoop / Spark Conference Japan 2016 ライトニングトーク発表資料)
サポートメンバは見た! Hadoopバグワースト10 (adoop / Spark Conference Japan 2016 ライトニングトーク発表資料)NTT DATA OSS Professional Services
 
今さら聞けないHadoop セントラルソフト株式会社(20120119)
今さら聞けないHadoop セントラルソフト株式会社(20120119)今さら聞けないHadoop セントラルソフト株式会社(20120119)
今さら聞けないHadoop セントラルソフト株式会社(20120119)Toru Takizawa
 
Hadoopことはじめ
HadoopことはじめHadoopことはじめ
Hadoopことはじめ均 津田
 
Sparkによる GISデータを題材とした時系列データ処理 (Hadoop / Spark Conference Japan 2016 講演資料)
Sparkによる GISデータを題材とした時系列データ処理 (Hadoop / Spark Conference Japan 2016 講演資料)Sparkによる GISデータを題材とした時系列データ処理 (Hadoop / Spark Conference Japan 2016 講演資料)
Sparkによる GISデータを題材とした時系列データ処理 (Hadoop / Spark Conference Japan 2016 講演資料)Hadoop / Spark Conference Japan
 
Pythonで入門するApache Spark at PyCon2016
Pythonで入門するApache Spark at PyCon2016Pythonで入門するApache Spark at PyCon2016
Pythonで入門するApache Spark at PyCon2016Tatsuya Atsumi
 
本当にあったHadoopの恐い話 Blockはどこへきえた? (Hadoop / Spark Conference Japan 2016 ライトニングトー...
本当にあったHadoopの恐い話Blockはどこへきえた? (Hadoop / Spark Conference Japan 2016 ライトニングトー...本当にあったHadoopの恐い話Blockはどこへきえた? (Hadoop / Spark Conference Japan 2016 ライトニングトー...
本当にあったHadoopの恐い話 Blockはどこへきえた? (Hadoop / Spark Conference Japan 2016 ライトニングトー...NTT DATA OSS Professional Services
 

What's hot (20)

HDFS新機能総まとめin 2015 (日本Hadoopユーザー会 ライトニングトーク@Cloudera World Tokyo 2015 講演資料)
HDFS新機能総まとめin 2015 (日本Hadoopユーザー会 ライトニングトーク@Cloudera World Tokyo 2015 講演資料)HDFS新機能総まとめin 2015 (日本Hadoopユーザー会 ライトニングトーク@Cloudera World Tokyo 2015 講演資料)
HDFS新機能総まとめin 2015 (日本Hadoopユーザー会 ライトニングトーク@Cloudera World Tokyo 2015 講演資料)
 
はやわかりHadoop
はやわかりHadoopはやわかりHadoop
はやわかりHadoop
 
Apache Spark 1000 nodes NTT DATA
Apache Spark 1000 nodes NTT DATAApache Spark 1000 nodes NTT DATA
Apache Spark 1000 nodes NTT DATA
 
MapReduce入門
MapReduce入門MapReduce入門
MapReduce入門
 
Apache Sparkに手を出してヤケドしないための基本 ~「Apache Spark入門より」~ (デブサミ 2016 講演資料)
Apache Sparkに手を出してヤケドしないための基本 ~「Apache Spark入門より」~ (デブサミ 2016 講演資料)Apache Sparkに手を出してヤケドしないための基本 ~「Apache Spark入門より」~ (デブサミ 2016 講演資料)
Apache Sparkに手を出してヤケドしないための基本 ~「Apache Spark入門より」~ (デブサミ 2016 講演資料)
 
Hadoopデータプラットフォーム #cwt2013
Hadoopデータプラットフォーム #cwt2013Hadoopデータプラットフォーム #cwt2013
Hadoopデータプラットフォーム #cwt2013
 
Hadoopの概念と基本的知識
Hadoopの概念と基本的知識Hadoopの概念と基本的知識
Hadoopの概念と基本的知識
 
Hadoopのシステム設計・運用のポイント
Hadoopのシステム設計・運用のポイントHadoopのシステム設計・運用のポイント
Hadoopのシステム設計・運用のポイント
 
オライリーセミナー Hive入門 #oreilly0724
オライリーセミナー Hive入門  #oreilly0724オライリーセミナー Hive入門  #oreilly0724
オライリーセミナー Hive入門 #oreilly0724
 
FluentdやNorikraを使った データ集約基盤への取り組み紹介
FluentdやNorikraを使った データ集約基盤への取り組み紹介FluentdやNorikraを使った データ集約基盤への取り組み紹介
FluentdやNorikraを使った データ集約基盤への取り組み紹介
 
並列分散処理基盤Hadoopの紹介と、開発者が語るHadoopの使いどころ (Silicon Valley x 日本 / Tech x Business ...
並列分散処理基盤Hadoopの紹介と、開発者が語るHadoopの使いどころ (Silicon Valley x 日本 / Tech x Business ...並列分散処理基盤Hadoopの紹介と、開発者が語るHadoopの使いどころ (Silicon Valley x 日本 / Tech x Business ...
並列分散処理基盤Hadoopの紹介と、開発者が語るHadoopの使いどころ (Silicon Valley x 日本 / Tech x Business ...
 
40分でわかるHadoop徹底入門 (Cloudera World Tokyo 2014 講演資料)
40分でわかるHadoop徹底入門 (Cloudera World Tokyo 2014 講演資料) 40分でわかるHadoop徹底入門 (Cloudera World Tokyo 2014 講演資料)
40分でわかるHadoop徹底入門 (Cloudera World Tokyo 2014 講演資料)
 
HadoopとRDBMSをシームレスに連携させるSmart SQL Processing (Hadoop Conference Japan 2014)
HadoopとRDBMSをシームレスに連携させるSmart SQL Processing (Hadoop Conference Japan 2014)HadoopとRDBMSをシームレスに連携させるSmart SQL Processing (Hadoop Conference Japan 2014)
HadoopとRDBMSをシームレスに連携させるSmart SQL Processing (Hadoop Conference Japan 2014)
 
サポートメンバは見た! Hadoopバグワースト10 (adoop / Spark Conference Japan 2016 ライトニングトーク発表資料)
サポートメンバは見た! Hadoopバグワースト10 (adoop / Spark Conference Japan 2016 ライトニングトーク発表資料)サポートメンバは見た! Hadoopバグワースト10 (adoop / Spark Conference Japan 2016 ライトニングトーク発表資料)
サポートメンバは見た! Hadoopバグワースト10 (adoop / Spark Conference Japan 2016 ライトニングトーク発表資料)
 
今さら聞けないHadoop セントラルソフト株式会社(20120119)
今さら聞けないHadoop セントラルソフト株式会社(20120119)今さら聞けないHadoop セントラルソフト株式会社(20120119)
今さら聞けないHadoop セントラルソフト株式会社(20120119)
 
Hadoopことはじめ
HadoopことはじめHadoopことはじめ
Hadoopことはじめ
 
Sparkによる GISデータを題材とした時系列データ処理 (Hadoop / Spark Conference Japan 2016 講演資料)
Sparkによる GISデータを題材とした時系列データ処理 (Hadoop / Spark Conference Japan 2016 講演資料)Sparkによる GISデータを題材とした時系列データ処理 (Hadoop / Spark Conference Japan 2016 講演資料)
Sparkによる GISデータを題材とした時系列データ処理 (Hadoop / Spark Conference Japan 2016 講演資料)
 
ストリームデータ分散処理基盤Storm
ストリームデータ分散処理基盤Stormストリームデータ分散処理基盤Storm
ストリームデータ分散処理基盤Storm
 
Pythonで入門するApache Spark at PyCon2016
Pythonで入門するApache Spark at PyCon2016Pythonで入門するApache Spark at PyCon2016
Pythonで入門するApache Spark at PyCon2016
 
本当にあったHadoopの恐い話 Blockはどこへきえた? (Hadoop / Spark Conference Japan 2016 ライトニングトー...
本当にあったHadoopの恐い話Blockはどこへきえた? (Hadoop / Spark Conference Japan 2016 ライトニングトー...本当にあったHadoopの恐い話Blockはどこへきえた? (Hadoop / Spark Conference Japan 2016 ライトニングトー...
本当にあったHadoopの恐い話 Blockはどこへきえた? (Hadoop / Spark Conference Japan 2016 ライトニングトー...
 

Similar to Learning spaerk chapter03

S3 を単純ストレージとして 利用する手段の比較
S3 を単純ストレージとして 利用する手段の比較S3 を単純ストレージとして 利用する手段の比較
S3 を単純ストレージとして 利用する手段の比較真治 米田
 
Presto As A Service - Treasure DataでのPresto運用事例
Presto As A Service - Treasure DataでのPresto運用事例Presto As A Service - Treasure DataでのPresto運用事例
Presto As A Service - Treasure DataでのPresto運用事例Taro L. Saito
 
2014 11-20 Machine Learning with Apache Spark 勉強会資料
2014 11-20 Machine Learning with Apache Spark 勉強会資料2014 11-20 Machine Learning with Apache Spark 勉強会資料
2014 11-20 Machine Learning with Apache Spark 勉強会資料Recruit Technologies
 
Bluemixを使ったTwitter分析
Bluemixを使ったTwitter分析Bluemixを使ったTwitter分析
Bluemixを使ったTwitter分析Tanaka Yuichi
 
夏サミ2013 Hadoopを使わない独自の分散処理環境の構築とその運用
夏サミ2013 Hadoopを使わない独自の分散処理環境の構築とその運用夏サミ2013 Hadoopを使わない独自の分散処理環境の構築とその運用
夏サミ2013 Hadoopを使わない独自の分散処理環境の構築とその運用Developers Summit
 
EmbulkとDigdagとデータ分析基盤と
EmbulkとDigdagとデータ分析基盤とEmbulkとDigdagとデータ分析基盤と
EmbulkとDigdagとデータ分析基盤とToru Takahashi
 
EmbulkとDigdagとデータ分析基盤と
EmbulkとDigdagとデータ分析基盤とEmbulkとDigdagとデータ分析基盤と
EmbulkとDigdagとデータ分析基盤とToru Takahashi
 
マルチテナント Hadoop クラスタのためのモニタリング Best Practice
マルチテナント Hadoop クラスタのためのモニタリング Best Practiceマルチテナント Hadoop クラスタのためのモニタリング Best Practice
マルチテナント Hadoop クラスタのためのモニタリング Best PracticeHadoop / Spark Conference Japan
 
ADO.NETとORMとMicro-ORM -dapper dot netを使ってみた
ADO.NETとORMとMicro-ORM -dapper dot netを使ってみたADO.NETとORMとMicro-ORM -dapper dot netを使ってみた
ADO.NETとORMとMicro-ORM -dapper dot netを使ってみたNarami Kiyokura
 
Rユーザのためのspark入門
Rユーザのためのspark入門Rユーザのためのspark入門
Rユーザのためのspark入門Shintaro Fukushima
 
Treasure Dataを支える技術 - MessagePack編
Treasure Dataを支える技術 - MessagePack編Treasure Dataを支える技術 - MessagePack編
Treasure Dataを支える技術 - MessagePack編Taro L. Saito
 
MongoDBを用いたソーシャルアプリのログ解析 〜解析基盤構築からフロントUIまで、MongoDBを最大限に活用する〜
MongoDBを用いたソーシャルアプリのログ解析 〜解析基盤構築からフロントUIまで、MongoDBを最大限に活用する〜MongoDBを用いたソーシャルアプリのログ解析 〜解析基盤構築からフロントUIまで、MongoDBを最大限に活用する〜
MongoDBを用いたソーシャルアプリのログ解析 〜解析基盤構築からフロントUIまで、MongoDBを最大限に活用する〜Takahiro Inoue
 
Why dont you_create_new_spark_jl
Why dont you_create_new_spark_jlWhy dont you_create_new_spark_jl
Why dont you_create_new_spark_jlShintaro Fukushima
 
第2回 R言語で始めよう、データサイエンス(ハンズオン勉強会) 〜相関分析による需要予測編〜
第2回 R言語で始めよう、データサイエンス(ハンズオン勉強会) 〜相関分析による需要予測編〜第2回 R言語で始めよう、データサイエンス(ハンズオン勉強会) 〜相関分析による需要予測編〜
第2回 R言語で始めよう、データサイエンス(ハンズオン勉強会) 〜相関分析による需要予測編〜Yasuyuki Sugai
 
[db tech showcase Tokyo 2014] D33: Prestoで実現するインタラクティブクエリ by トレジャーデータ株式会社 斉藤太郎
[db tech showcase Tokyo 2014] D33: Prestoで実現するインタラクティブクエリ  by トレジャーデータ株式会社 斉藤太郎[db tech showcase Tokyo 2014] D33: Prestoで実現するインタラクティブクエリ  by トレジャーデータ株式会社 斉藤太郎
[db tech showcase Tokyo 2014] D33: Prestoで実現するインタラクティブクエリ by トレジャーデータ株式会社 斉藤太郎Insight Technology, Inc.
 
Apache Sparkを使った感情極性分析
Apache Sparkを使った感情極性分析Apache Sparkを使った感情極性分析
Apache Sparkを使った感情極性分析Tanaka Yuichi
 
tcpdump & xtrabackup @ MySQL Casual Talks #1
tcpdump & xtrabackup @ MySQL Casual Talks #1tcpdump & xtrabackup @ MySQL Casual Talks #1
tcpdump & xtrabackup @ MySQL Casual Talks #1Ryosuke IWANAGA
 

Similar to Learning spaerk chapter03 (20)

S3 を単純ストレージとして 利用する手段の比較
S3 を単純ストレージとして 利用する手段の比較S3 を単純ストレージとして 利用する手段の比較
S3 を単純ストレージとして 利用する手段の比較
 
SAIS/SIGMOD参加報告 in SAIS/DWS2018報告会@Yahoo! JAPAN
SAIS/SIGMOD参加報告 in SAIS/DWS2018報告会@Yahoo! JAPANSAIS/SIGMOD参加報告 in SAIS/DWS2018報告会@Yahoo! JAPAN
SAIS/SIGMOD参加報告 in SAIS/DWS2018報告会@Yahoo! JAPAN
 
Tokyo r38
Tokyo r38Tokyo r38
Tokyo r38
 
Presto As A Service - Treasure DataでのPresto運用事例
Presto As A Service - Treasure DataでのPresto運用事例Presto As A Service - Treasure DataでのPresto運用事例
Presto As A Service - Treasure DataでのPresto運用事例
 
2014 11-20 Machine Learning with Apache Spark 勉強会資料
2014 11-20 Machine Learning with Apache Spark 勉強会資料2014 11-20 Machine Learning with Apache Spark 勉強会資料
2014 11-20 Machine Learning with Apache Spark 勉強会資料
 
Bluemixを使ったTwitter分析
Bluemixを使ったTwitter分析Bluemixを使ったTwitter分析
Bluemixを使ったTwitter分析
 
夏サミ2013 Hadoopを使わない独自の分散処理環境の構築とその運用
夏サミ2013 Hadoopを使わない独自の分散処理環境の構築とその運用夏サミ2013 Hadoopを使わない独自の分散処理環境の構築とその運用
夏サミ2013 Hadoopを使わない独自の分散処理環境の構築とその運用
 
EmbulkとDigdagとデータ分析基盤と
EmbulkとDigdagとデータ分析基盤とEmbulkとDigdagとデータ分析基盤と
EmbulkとDigdagとデータ分析基盤と
 
EmbulkとDigdagとデータ分析基盤と
EmbulkとDigdagとデータ分析基盤とEmbulkとDigdagとデータ分析基盤と
EmbulkとDigdagとデータ分析基盤と
 
マルチテナント Hadoop クラスタのためのモニタリング Best Practice
マルチテナント Hadoop クラスタのためのモニタリング Best Practiceマルチテナント Hadoop クラスタのためのモニタリング Best Practice
マルチテナント Hadoop クラスタのためのモニタリング Best Practice
 
ADO.NETとORMとMicro-ORM -dapper dot netを使ってみた
ADO.NETとORMとMicro-ORM -dapper dot netを使ってみたADO.NETとORMとMicro-ORM -dapper dot netを使ってみた
ADO.NETとORMとMicro-ORM -dapper dot netを使ってみた
 
Rユーザのためのspark入門
Rユーザのためのspark入門Rユーザのためのspark入門
Rユーザのためのspark入門
 
Treasure Dataを支える技術 - MessagePack編
Treasure Dataを支える技術 - MessagePack編Treasure Dataを支える技術 - MessagePack編
Treasure Dataを支える技術 - MessagePack編
 
MongoDBを用いたソーシャルアプリのログ解析 〜解析基盤構築からフロントUIまで、MongoDBを最大限に活用する〜
MongoDBを用いたソーシャルアプリのログ解析 〜解析基盤構築からフロントUIまで、MongoDBを最大限に活用する〜MongoDBを用いたソーシャルアプリのログ解析 〜解析基盤構築からフロントUIまで、MongoDBを最大限に活用する〜
MongoDBを用いたソーシャルアプリのログ解析 〜解析基盤構築からフロントUIまで、MongoDBを最大限に活用する〜
 
Why dont you_create_new_spark_jl
Why dont you_create_new_spark_jlWhy dont you_create_new_spark_jl
Why dont you_create_new_spark_jl
 
第2回 R言語で始めよう、データサイエンス(ハンズオン勉強会) 〜相関分析による需要予測編〜
第2回 R言語で始めよう、データサイエンス(ハンズオン勉強会) 〜相関分析による需要予測編〜第2回 R言語で始めよう、データサイエンス(ハンズオン勉強会) 〜相関分析による需要予測編〜
第2回 R言語で始めよう、データサイエンス(ハンズオン勉強会) 〜相関分析による需要予測編〜
 
[db tech showcase Tokyo 2014] D33: Prestoで実現するインタラクティブクエリ by トレジャーデータ株式会社 斉藤太郎
[db tech showcase Tokyo 2014] D33: Prestoで実現するインタラクティブクエリ  by トレジャーデータ株式会社 斉藤太郎[db tech showcase Tokyo 2014] D33: Prestoで実現するインタラクティブクエリ  by トレジャーデータ株式会社 斉藤太郎
[db tech showcase Tokyo 2014] D33: Prestoで実現するインタラクティブクエリ by トレジャーデータ株式会社 斉藤太郎
 
Tokyo r30 beginner
Tokyo r30 beginnerTokyo r30 beginner
Tokyo r30 beginner
 
Apache Sparkを使った感情極性分析
Apache Sparkを使った感情極性分析Apache Sparkを使った感情極性分析
Apache Sparkを使った感情極性分析
 
tcpdump & xtrabackup @ MySQL Casual Talks #1
tcpdump & xtrabackup @ MySQL Casual Talks #1tcpdump & xtrabackup @ MySQL Casual Talks #1
tcpdump & xtrabackup @ MySQL Casual Talks #1
 

Learning spaerk chapter03

  • 2. 参考資料 • http://www.slideshare.net/hadoopxnttdata/ap ache-spark • http://www.ne.jp/asahi/hishidama/home/tech/ scala/spark/RDD.html • http://d.hatena.ne.jp/kimutansk/20130924/13 79971579 • http://www.slideshare.net/data_sciesotist/2 -learning-spark-3 • http://dev.classmethod.jp/etc/apache- spark_rdd_investigation/ • http://qiita.com/FKuro_/items/3b34f9f64a17c 73ccdd4
  • 3. • 今回の資料は、Learning Spark自体や書籍に関する勉強会 資料、更にはSparkに関して公開している資料を参考にしな がら、社内の勉強会向けに作成したものです • もし、この資料に関して、内容の訂正・削除の必要がある場 合は、こちらのメールアドレスまで連絡をお願いします – akky.like.spark@gmail.com – 資料に関するアドバイス、誤訳の指摘など、大歓迎です • 今回のこちらの資料は会社の活動とは無関係ですので、会 社名は 伏せますが、資料を見たうえで勉強会に興味をもた れた方は、同様にこちらのアドレスに連絡ください – 特に、弊社は機械学習に力を入れておりますので、MLlibに関し て興味がある方は、大歓迎ですので、宜しくお願い致します
  • 4. • 当資料では、RDDとRDDsに関する違いは無いと判断 し、文書中では元の書籍の表現がどうあれ、RDDで統 一しています – 使い分けが必要である場合は、もう一度見直しますので、 ご指摘をお願いします • 本文書のサンプルは、基本Scalaに関してのみ記載し ています。元の書籍にPythonしか無いものも、一部 はScala版のサンプルも用意しています • 基本的に元の書籍と1対1で訳文を用意しています が、一部、意味の無い文書は省略しています – 重要な文書を省略していると思われる場合は、ご連絡い ただければ、対応いたします
  • 6. This Chapter Introduces • Sparkにおけるデータ(RDD)の取り扱いを説 明する • Sparkにおける全ての操作は、RDDの生成、 RDDの変換、RDDの計算で表される • データサイエンティストもエンジニアも、この 章を読んでほしい • 出来れば、手元で動作確認をしながら読んで 欲しい • コードはGitHubで公開している
  • 7. RDD Basics(1) • RDD(Resilient Distributed Datasets)はイミュータブル (不変)な分散コレクションである • RDDは複数のパーティションに分割され、それぞれ異なる ノードで処理される • RDDは、ユーザオブジェクトを含む、Python、Java、Scala のオブジェクトを含むことが出来る • 外部のデータセットを読み込むか、ドライバを用いてコレク ションオブジェクトを配布することで生成出来る • 遅延計算される – 計算を行うタイミングをスケジューリングされたあと、計算される val lines = sc.textFile(“README.md”) 例3-1:
  • 8. RDD Basics(2) 補足① • Sparkアプリケーションを起動する側(メインプログラム)をdriverdriverdriverdriverと呼ぶ – ユーザがRDDの返還を記述したプログラム • 各マシン(ワーカーノード)上で分散して実際に稼動する側(プロセス)を executorexecutorexecutorexecutorと呼ぶ – ワーカ上で動作し、実際の計算処理を 担当する • 共有変数 – Sparkでは、各executorに定数を転送 したり、各executorで集計した値を driverで受け取ったりする機能がある • Sparkの実行はexecutorで行われるので、Sparkで変数に対して行われた変更 はdriver側には反映されない • 当然、executor間で参照し合うことも出来ない • そのため、driverとexecutorとの間で値を共有するための仕組みがSparkに は用意されている – ブロードキャスト変数は、driverで定義した 定数(固定値)を各executorに転送する為の変数 – Scalaで記述する場合は、定数を共有することが 出来るが、非効率 val rdd = sc.makeRDD(Seq(123, 456, 789)) val CONSTANTCONSTANTCONSTANTCONSTANT = sc.broadcastbroadcastbroadcastbroadcast(123) val filter = rdd.filter(_ != CONSTANT.valueCONSTANT.valueCONSTANT.valueCONSTANT.value) filter.foreach(println)
  • 9. RDD Basics(3) 補足② • RDDがイミュータブルである必要がある理由 – Sparkでは、大量おデータをオンメモリで分散処理するので、 各サーバに分散配置されたデータが処理中に欠損した場合に 備えた仕組みが必要 – 欠損に備えつつ、ネットワーク転送を出来る限り避けたい • 得たいデータが失われていたら、前のデータから再作成する、 という アプローチをとっている – このため、RDDはイミュータブルである必要がある
  • 11. RDD Basics(5) • 作成したRDDには、二つの操作が適用できる – Transformations:RDDから別の新しいRDDを生成出来る – Actions:RDDに対して処理を適用した結果を出力する • Transformationsの例として、条件に一致する要素を抽出 して、新しいRDDを作成するフィルタリングがある • 例3-2に示すように、単語のPythonが含まれている文字列 だけを保持する新しいRDDを作成するためにこれを使用する ことができます val lineWithSpark = lines.filter( line => line.contains("Spark") ) 例3-2:
  • 12. RDD Basics(6) • Actionsは、RDDに基づいて計算し、結果をドライバプログラ ムに戻すか、外部記憶装置(例えば、HDFS)に保存するか、 いずれかを行う • Actionsの例として、RDDから最初の1要素を抽出する first()がある lineWithSpark.first() 例3-3: • TransformationsとActionsは、RDDを処理する際の動作が 異なる – RDDをいつでも定義することができるが、最初に使用される時まで 処理は実行されない(遅延実行) – このアプローチは一般的では無い様に見えるが、ビッグデータで作 業しているとき、多くの意味を持つかもしれない
  • 13. RDD Basics(7) – フィルタを行う際にファイルを読み込む際、ファイル内のすべての行 をロードすることは、スペースの多くを無駄に消費することになる – スパークはTransformationsのチェーン全体で必要なデータだけ処 理することができる – first()アクションにおいて、Sparkは最初の1行が見つかるまでファ イルをスキャンするが、ファイル全体を読み取ることは無い
  • 14. RDD Basics(8) • RDDはActionsの実行の度に処理される • RDDを複数のActionsで再利用したい場合は、RDD.persist()で永続化する必要がある • Sparkは、最初に計算した後にメモリ内のデータを保存し、将来Actionsで再利用すること が出来る • デフォルトでは永続化しない仕様が珍しいかもしれないが、大きなデータセットの場合に意味 ある仕様となる。RDDを再利用せず、処理に必要なデータはストリーム経由で取得できる場 合は、ストレージスペースを無駄にする理由は無い • データの一部をメモリ上に永続化し、繰り返しクエリを発行するときに使うことが多いだろう lineWithSpark.persist() lineWithSpark.count() lineWithSpark.first() 例3-4:
  • 15. RDD Basics(9) • まとめ – 外部データから入力用RDDを作る – filter()のようなtransformationsを使い入力用RDDを変換することで、新しいRDDを作 成する – 再利用するRDDをpersist()で永続化出来る – ActionsはRDDを分散処理する • TIPS – cache()もデフォルト設定でpersist()を実行したのと同じ結果を得られる
  • 16. Creating RDD • RDDの作り方には2種類存在する – 外部データセットを読み込む方法 – コレクションを並列化(Parallelizing)させる方法 • 外部データセットの読み込みに関する説明は既に実施済み • 簡単なのは、sc.parallelize()を使用する – 既に存在するコレクションをSparkContextの並列化メソッドに渡すことである – シェルの中で独自のRDDを作成し、実行することが出来るので、学習の際には便利 – 1マシン上のメモリに全体のデータセットを持っていることを必要とすることは認識しておく必要があります (よって、プロトタイプやテスト以外では、広く使用されない) – RDDを作成する、より一般的な方法は、外部記憶装置からデータをロードすることである val lines = sc.parallelize(List("pandas", "i like pandas")) 例3-6: val lines = sc.textFile("/path/to/README.md") 例3-9:
  • 17. RDD Operations(1) • RDDは2種類の操作をサポートしている – TransformationsとActionsがある • Transformationsは新しいRDDを返す – map() や filter() など • Actionsはドライバーに計算結果を返すか、ストレージに結果を書き込む操作である – count() や first()など • TransformationsとActionsは非常に違うので、使う操作の種類を理解することは非常に重要 – 種類に関して混乱してしまった場合は、戻り値の型を見ればよい
  • 18. RDD Operations(2) Transformations① • Transformationsは新しいRDDを生成する • RDDに対してActionsが実行されるまで、transformationsは実行されない(遅延評価) • 多くのtransformationsは“要素指向”で、各要素に対して作用する – 例えば、MATLABの配列同士の乗算は、要素同士の乗算になる(C = A.*B) • ログファイルlog.txtからエラーメッセージを抽出する例を見る – 以前に見たfilter()を使用する • filter()が既存のinputRDDを変更しないことに注意してください。 • 代わりに新しいRDDが生成されます • inputRDDを後でプログラム内で再利用することができる(例えば、他の単語を検索するなど) • 再度、"warning"を検索する為に、inputRDDを使用してみるとしましょう val inputRDD = sc.textFile("log.txt") val errorsRDD = inputRDD.filter(line => line.contains("error")) 例3-12:
  • 19. RDD Operations(3) Transformations② • そこで、"error"もしくは"warning"を含む行を検索する為に、transformation:union()を使う • union()は2つのRDDを処理するところがfilter()と違う • transformationは、任意の数のRDDをInputに処理することが出来る • TIP – 例3-14と同じ結果を得るための良い方法は、単純に"error"もしくは"warning"を一度検索し、 同様に残りの一方でフィルタすることである – 系統グラフについて • Sparkは、異なるRDD間の依存関係のセットを追跡する(系統グラフ) • 必要に応じて各RDDを計算する際に永続したRDDの一部が 失われた場合に、回復するためにこの情報を使用する • 図3-1は、例3-14のための系統グラフを示している • DAG(Directed Acyclic Graph:有向非循環グラフ)ともいう 例3-14: val errorsRDD = inputRDD.filter(line => line.contains("error")) val warningsRDD = inputRDD.filter(line => line.contains("warning")) val badLinesRDD = errorsRDD.union(warningsRDD) 図3-1
  • 20. RDD Operations(4) Actions① • Actionsは、データセットに対して何かを実行し、ドライバに値を戻すか、ストレージに何かを 出力する操作である • Actionsが呼ばれた際に、RDDのために必要なTransactionsの評価を強制する • 前のセクションから続いているログ処理を続けて、badLinesRDDに関する情報を出力する方法を見 ていく – count():データの件数を返す – take(): • 指定した件数の要素を返す • ローカルで反復した後、ドライバに情報を出力する 例3-16: println("Input had " + badLinesRDD.count() + " concerning lines") println("Here are 10 examples:") badLinesRDD.take(10).foreach(println)
  • 21. RDD Operations(5) Actions② • Collect()について – RDD全体を取得するために、 collect()というactionsも用意されている – プログラムがRDDを非常に小さいサイズにフィルタし、ローカルでフィルタしたRDDを取り扱 いたい場合に非常に便利です – collect()を使用する場合、全体のデータセットが単一のマシン上のメモリに収まらなければな らない点に注意してください。collect()を大規模なデータセットで使用すべきではありません – ほとんどの場合RDDは大きすぎる為、collect()で収集しきれない – これらのケースでは、HDFSやAmazon S3などの分散ストレージシステムにデータを書き込む ことが一般的 • saveAsTextFile()やsaveAsSequenceFile() を用いてRDDの内容を保存することが出来る • 第5章にて、データをエクスポートするためのさまざまなオプションを説明する • 新しいactionを呼び出す度にRDD全体が最初から再計算されなければならないことに注意する必要 がある • この非効率性を回避するために、persist()もしくはcache()を使って、中間結果を永続化することが できる
  • 22. RDD Operations(6) Lazy Evaluation(遅延評価)① • 既に述べた通り、transformationsは遅延評価される。それはSparkはactionを認識するまで実行 しないことを意味する • 慣れないユーザからすると直観に反していますが、Haskell・LINQのようなのような関数型言語を使 用している人には慣れていることでしょう • 遅延評価は、RDDに対するtransformationを呼び出す時(例えば、map())、操作はすぐに実行されな いことを意味します • 代わりに、Sparkは内部的にメタデータをこの操作が要求されたことを示すために記録します • RDDに特定のデータが含まれていると考えるのではなく、transformationsを通じてデータを計算 する方法の手順が各RDDから構築されていると考えるのがベストです • RDDへのデータのロードはtransformationsと同様に遅延評価が行われます • sc.textFile()を呼び出した際、必要になるまでデータはロードされません。transformations同様に、 操作が複数回発生する可能性があります • TIP – transformationsは遅延評価されるが、count()のようなactionを実行することで、実行を強制することが出来る – これは、プログラムの一部だけをテストする簡単な方法だ – Sparkは一緒の操作をグループ化することによって、データの引継ぎを行うパスの数を減らすために、遅延評価を使用する – HadoopのMapReduceのようなシステムでは、開発者は多くの場合、MapReduceのパスの数を最小限に抑えるために、操作の グループ化への考慮に多くの時間を費やす必要がある – Sparkでは多くの簡単な操作のチェーン化を行う代わりに、単一の複雑なMapを記述することに、実質的な利点は無い – このため、ユーザ(プログラマ)は彼らのプログラムを管理できる単位に、自由に細分化することが出来る
  • 23. Passing Functions to Spark(1) • 殆どのSparkのtransformationsや一部のactionsは、データを計算するためにSparkに よって使用される関数を渡すことに依存している • コア言語(Python, Scala, Java)はそれぞれ、僅かに異なるSparkに関数を渡すための メカニズムを保有する • Python – Pythonでは3つの形式を用いることが出来る(ラムダ式、トップレベル、ローカル) – 関数を渡す時に注意する必要がある問題の一つは、誤って関数を含むオブジェクトをシリアル 化することである – オブジェクトのメンバーである、またはオブジェクト内のフィールドへの参照を含む関数を渡 すと(例:self.field)、Sparkはワーカーノードに全体のオブジェクト(全ての データ)を 送信する為、必要とする情報のビット数よりもはるかに大きくなってしまう – もしクラスがPythonがpickle化することが出来ないオブジェクトを含んでいる場合、プログラ ムが失敗することがある 例3-18: word = rdd.filter(lambda s: "error" in s) def containsError(s): return "error" in s word = rdd.filter(containsError)
  • 24. Passing Functions to Spark(2) 例3-19:Passing a function with field references (don’t do this!) class SearchFunctions(object): def __init__(self, query): self.query = query def isMatch(self, s): return self.query in s def getMatchesFunctionReference(self, rdd): # Problem: references all of "self" in "self.isMatch" return rdd.filter(self.isMatch) def getMatchesMemberReference(self, rdd): # Problem: references all of "self" in "self.query" return rdd.filter(lambda x: self.query in x) 代わりにローカル変数にオブジェクトから必要な項目を抽出し、Python関数を渡す 例3-20:Python function passing without field references class WordFunctions(object): ... def getMatchesNoReference(self, rdd): # Safe: extract only the field we need into a local variable query = self.query return rdd.filter(lambda x: query in x)
  • 25. Passing Functions to Spark(3) 例3-21:Scala function passing class SearchFunctions(val query: String) { def isMatch(s: String): Boolean = { s.contains(query) } def getMatchesFunctionReference(rdd: RDD[String]): RDD[String] = { //注意:全データを参照してしまう rdd.map(isMatch) } def getMatchesFieldReference(rdd: RDD[String]): RDD[String] = { //注意:全データを参照してしまう rdd.map(x => x.split(query)) } def getMatchesNoReference(rdd: RDD[String]): RDD[String] = { // Safe: extract just the field we need into a local variable val query_ = this.query rdd.map(x => x.split(query_)) } } • Scala – Scalaでは、Scalaの他の機能的なAPIの為に、インラインに定義された関数内のメソッド、関数への参照、静的 な関数を渡すことが出来る – いくつかの他の考慮事項は、関数を渡し、その中で参照されているデータはSerializableである(Javaの Serializableインタフェースを実装する)必要がある – さらにPythonのように、オブジェクトのメソッドやフィールドを渡すと、そのオブジェクト全体への参照が含 まれてしまう – 例3-20のPython同様に例3-21に示すように、我々はローカル変数に必要項目を抽出することで、オブジェク ト全体を渡すことから回避することが出来る
  • 26. – もしNotSerializableExceptionがScalaで発生した場合は、シリアル化不可能なクラスのメソッド やフィールド への参照は通常問題になる – トップレベルのオブジェクトのメンバーである、シリアル化可能なローカル変数や関数を渡す ことは常に安全であることに注意する必要がある • Java – Javaでは、関数はSparkの機能に関するInterface(org.apache.spark.api.java.functionパッケー ジ)の一つを実装することで、機能は提供されます – 関数の戻り型に基づいて、異なるインターフェイスの数がある – 表3-1にて最も基本的な機能のインターフェースを示す – Javaでは、Key/Valueのような特別な型を戻す必要がある時のために、他のInterfaceの数をカ バーしている Passing Functions to Spark(4) Function nameFunction nameFunction nameFunction name Method to implementMethod to implementMethod to implementMethod to implement UsageUsageUsageUsage Function<T, R> R call(T) Take in one input and return one output, for use with operations like map() and filter(). Function2<T1, T2, R> R call(T1, T2) Take in two inputs and return one output, for use with operations like aggregate() or fold(). FlatMapFunction<T, R> Iterable<R> call(T) Take in one input and return zero or more outputs, for use with operations like flatMap(). 表3-1
  • 27. – インライン匿名内部クラス(例:3-22)として機能クラスを定義する、または名前付きクラスを作成すること が出来る Passing Functions to Spark(4) 例3-22:Java function passing with anonymous inner class RDD<String> errors = lines.filter(new Function<String, Boolean>() { public Boolean call(String x) { return x.contains("error"); } }); 例3-23:Java function passing with named class class ContainsError implements Function<String, Boolean>() { public Boolean call(String x) { return x.contains("error"); } } RDD<String> errors = lines.filter(new ContainsError()); – 選択するスタイルは個人的な好みであるが、トップレベルの名前付きの関数は、多くの場合大規模なプログラ ムを編成するためのクリーナーであることを見出した – 例3-24に示すように、トップレベルの機能の利点の一つは、コンストラクタのパラメータを与えることが出 来ることである 例3-24:Java function class with parameters class Contains implements Function<String, Boolean>() { private String query; public Contains(String query) { this.query = query; } public Boolean call(String x) { return x.contains(query); } } RDD<String> errors = lines.filter(new Contains("error"));
  • 28. – Java8では、簡潔に関数のインターフェースを実装する為にラムダ式を使用することが出来ます – Java8は、この文章を書いている時点では比較的新しく、当書の例では、以前のバージョンのJavaの構文を用 いてクラスを定義しします – ラムダ式を用いた例を例3-25で例示します 例3-25:Java function passing with lambda expression in Java 8 RDD<String> errors = lines.filter(s -> s.contains("error")); – もし、Java8のラムダ式を使用することに興味がある場合は、OracleのマニュアルとSparkでラムダ式を使用 する方法について記述されたDatabricksのブログ記事を参照して下さい – TIP • 匿名内部クラスとラムダ式の両方において、どのようなfinal変数でもそれを囲む方法で参照することが 出来るので、PythonやScalaのようにこれらの変数を渡すことが出来る Passing Functions to Spark(5)
  • 29. • 序文 – この章では、Sparkの中で最も一般的なtransformationsとactionsを見ていく – 追加の操作は、特定のタイプのデータを含むRDDで利用可能 • 例:統計関数によりRDDを操作する/KeyValueのRDDをキー毎に集計する – 後のセクションにおいて、RDDの種類とこれらの特別な操作の間の変換をカバーします • Basic RDD – データに関係なく全てのRDDに対して実行できるtransformationsとactionsについて、記載することとする – Element-wise transformations(要素毎のtransformations ) • おそらく、最も一般的で使用されるtransformationsはmap()とfilter()です • map()は関数を取りこみ、RDDの各要素に対して関数を適用し、その結果を新しいRDDの各要素に適用し ます • filter()は関数を取りこみ、関数を用いてフィルタ条件に合致する要素で新しいRDDを戻します Common Transformations and Actions(1)
  • 30. • 自分がコレクションしているURLに関連づいているウェブサイトを取得するかのように、任意の数字の 二乗を行うためにmap()を使用することが出来ます(?) • map()の戻り値の型は、入力の型と一致する必要はありません Common Transformations and Actions(2) 例:3-27. Scala squaring the values in an RDD val input = sc.parallelize(List(1, 2, 3, 4)) val result = input.map(x => x * x) println(result.collect().mkString(",")) • 自分がコレクションしているURLに関連づいているウェブサイトを取得するかのように、任意の数字の二乗を行う ためにmap()を使用することが出来ます(?) • map()の戻り値の型は、入力の型と一致する必要はありません • 時折、各入力要素に対応した複数の出力を必要とすることがあります • この操作はflatMap()と呼ばれています • Map()同様、flatMap()に渡された関数は、入力RDD内の要素毎に個別に呼ばれます • 単一の要素を返す代わりに、戻り値とイテレータを戻す • イテレータのRDDを生成するよりはむしろ、イテレータの全ての要素から構成されるRDDを得る • flatMapの単純な使用例は、入力された文字列を分割するものである 例3-30:flatMap() in Scala, splitting lines into multiple words val lines = sc.parallelize(List("hello world", "hi")) val words = lines.flatMap(line => line.split(" ")) words.first() // returns "hello"
  • 31. Common Transformations and Actions(3) • flatMap()とmap()の違いを説明します • リスト形式のRDDではなく、リスト形 式の要素を持つRDDを戻すことが出来 るので、flatMap()についてイテレータ を「フラット化するもの」のように考 えることが出来ます(?) – Pseudo set operations(擬似集合演算(操作)) • RDD自身について、要素に欠落がある場合でも、RDDはunion()やintersection()などの多くの数学的な操 作をサポートしています(?) • 4つの操作について、図3-4に示します • これらの操作は、操作対象のRDDが全て同じタイプである必要がある点に注意してください
  • 32. • Distinct() – 最も頻繁に発生するRDDの欠落は、我々もよくデータを重複させるように、要素の一意性に関して です – ユニークな要素が必要な場合、ユニークな要素と新しいRDDを生成するRDD.distinct() transformationを使用することが出来ます – 各要素の1つのコピーのみを受け取ることを保証するために、ネットワーク上(クラスタ上?)の 全データをシャッフルする必要があるため、distinct()は負担が大きいことに留意してください – シャッフルに関して、およびそれをどのように回避するかは、第4章で詳しく説明されています • union() – 最も単純な集合演算(操作)はunion()です、それは両方のソースデータから構成されるRDDを戻す ものです – これは、多くのソースからログファイルを処理するようなユースケースの場合に有用です – 数学的なunion()と異なり、入力のRDDに重複が存在する場合、Sparkのunion()の結果には重複が含 まれます(必要に応じて、distinct()を併用することで修正することが可能です) • intersection() – 最も単純な集合演算(操作)はunion(other)である、それは両方のソースデータから構成される RDDを戻すものです – Sparkは両方のRDDから要素だけを戻すintersection(other)関数を提供します – intersection()は全ての重複を排除します(シングルRDDの重複を含む) – intersection() and union()は類似した概念でありますが、intersection()は共通の要素を識別する ために、ネットワークを介したシャッフルを必要とするので、パフォーマンスは遥かに悪いです – 時々、パフォーマンスへの考慮からデータを削除する必要があります Common Transformations and Actions(4)
  • 33. • subtract() – subtract()関数は、二つのRDDの差分を返します。subtract()関数は別のRDDを引数にとり、引数に 指定したRDDには存在せず、最初のRDDにだけ存在するRDDを戻します – intersection()のようにシャッフルを行います • cartesian() – 二つのRDD間の直積を計算する事が出来ます – cartesian() transformationは全ての対を返します – 各々のオファーに対する全てのユーザの期待興味を計算するような、全ての可能なペアの類似性を 考慮したい場合に、cartesian()は役に立ちます – RDD自身とのcartesian()を実行することが出来ます、それはユーザ類似のようなタスクの際に 役立ちます – しかし、巨大なRDDの場合、cartesian()は非常に高価であることに注意してください Common Transformations and Actions(5)
  • 34. Common Transformations and Actions(6) 関数名関数名関数名関数名 目的目的目的目的 実装例実装例実装例実装例 結果結果結果結果 map() 関数をそれぞれの要素に 適用し、結果のRDD を返す rdd.map (x=>X+1) {2,3,4,4} flatMap() RDDの各要素に関数を適用し、イテレータの内 容のRDDを戻す。しばしば、単語を抽出する為 に使用される rdd.flatMap (x=>x.to(3)) {1,2,3,2,3,3,3} filter() フィルタ条件に合致する要素だけから構成され るRDDを返す rdd.filter (x=>!=1) {2,3,3} distinct() 重複を排除する rdd.distinct() {1,2,3} sample(WithReplacement, fraction, [seed] ) 置換の有無に関係なく、サンプルを抽出する rdd.sample (false, 0.5) Nondeterminist ic • 表3-2:基本的なRDD transformations ※ 実装例のRDDの内容:{1, 2, 3, 3}
  • 35. Common Transformations and Actions(7) 関数名関数名関数名関数名 目的目的目的目的 実装例実装例実装例実装例 結果結果結果結果 union() 両方のRDDの要素を 含むRDDを生成する rdd.union(other) {1, 2, 3, 3, 4, 5} intersection() 両方のRDDに含まれる要素だけを含んだRDD を生成する rdd.intersection (other) {3} subtract() 対象のRDDから要素を削除する (例:トレーニングデータを削除する) →対象のRDDと引数で 指定したRDDの共通 要素を対象のRDD から削除する rdd.subtract (other) {1, 2} cartesian() 引数で渡したRDDとの直積のRDDを生成する rdd.Cartesian (other) {(1, 3), (1, 4), … (3, 5)} • 表3-3:二つのRDDによる transformations ※ 実装例のRDDの内容:{1, 2, 3}{3, 4, 5}
  • 36. – Actions • おそらく最も使用する、RDD上の最も一般的なActionはreduce()です。それはRDDの2つの要素を使用し、 同じ型の新しい要素を返す機能です • この機能の簡単な例は「+」であり、RDDの合計を計算するために使用できます • reduce()は、要素の合計を計算し、要素の数をカウントし、他の種類の集計を実行することが出来ます • reduce()と同様の処理としてfold()がありますが、これは各パーティション上の最初の呼出に使用される 0値を必要とする点である • 提供される0値は、操作における基準(=アイデンティティ要素)であるべきです。機能で複数回適用す る事で、値を変更してはいけません(例えば、+の場合は0、*の場合は1、または連結の場合は空リス ト) • TIP – fold() » 2つのパラメータのうち、最初のオペレータを修正することで、fold()によるオブジェクト の生成を最小限に抑えることが出来ます » ただし、第二のパラメータを変更してはなりません » fold()やreduce()は共に、戻り値の型と操作するRDDの属性が同じ型である必要があります » この仕様は合計を計算するような操作には適していますが、時には異なる型を必要とするこ とがあります » 例えば、移動平均を計算するとき、数値の要素とカウントの経過を追跡し、ペアとして取得 する必要があります » 最初に全ての要素を(関数を適用することで)別の要素に変換するmap()を最初の変数に使用 することで、必要とする型を戻し、reduce()はペアで作業できるようになります Common Transformations and Actions(8) 例3-33: Scala における reduce()の例 val sum = rdd.reduce((x, y) => x + y)
  • 37. Common Transformations and Actions(9) – aggregate() » aggregate() 関数は、戻り値の型がRDDと同じ型である制約から、私たちを解放します (fold()のように、戻り値で必要とする型を返す為に、「zero value」を指定する必要がある ように) » 次に、アキュムレータとのRDDの要素を結合する機能を提供します » 最後に、各ノードに独自の計算結果を蓄積していることを考えると、2つのアキュムレータ をマージする第二の機能を提供する必要があります » aggregate()を使用して平均を計算する例を示します(map()を使用せずに、RDDの平均を計 算する例を示します) 例3-36: Scala における aggregate() の例 val result = input.aggregate((0, 0))( (acc, value) => (acc._1 + value, acc._2 + 1), (acc1, acc2) => (acc1._1 + acc2._1, acc1._2 + acc2._2)) val avg = result._1 / result._2.toDouble
  • 38. Common Transformations and Actions(10) Accumulatorに関する補足 – アキュムレーター(accumulator)は、“追加”のみを行う変数 – driverでアキュムレーターを生成し、各executorでアキュムレーターに対して値の追加 (加算・蓄積)を行い、driverでその結果(総計)を受け取ることが出来る – アキュムレーターは、Hadoopのカウンターのようなもの(Hadoopでは、各タスクでカウンターに 値を加算していく) – ただし、Hadoopのカウンターの結果はアプリケーション内からは利用できない(Mapタスクで 集計したカウンターをReduceタスクで読み込むことは出来ない)が、Sparkのアキュムレーター はアプリケーション内の後続処理に利用することが出来る – アキュムレーターはvalueというフィールドを持っており、アキュムレーターの「+=」メソッドを 使うと、valueに対して追加(加算)が実行される val rdd = sc.makeRDD(Seq(1, 2, 3)) val sum = sc.accumulator(0) rdd.foreach(sum += _) println(sum.value)
  • 39. – collect() » RDD上のいくつかのactionsは、driverにデータの一部または全部を通常のコレクションまた は値の形式で返します » driverにデータを戻す最も単純で一般的な操作はcollect()で、それはRDD全体の内容を返し ます » collect()は一般的に、RDDと期待結果を比較することが簡単に出来ることから、RDD全体が メモリに収まることを前提にユニットテストに使用されます » collect()には、全てのデータをdriverにコピーする必要があるので、全てのデータが単一の マシンに収まる必要がある、という制限があります – take(n) » take(n)はn個の要素をRDDから取得しますが、それはアクセスするパーティションの数を最 小限にするので、取得できるコレクションは偏ってしまうかもしれません » この操作が期待する順序で要素を返さない点に注意することは重要です » これらの操作(collect()、take(n))は、ユニットテスト及びデバッグには有用ですが、大量 のデータを扱う場合、ボトルネックを引き起こすかも知れません – top(n) » もし、データに順序性がある場合は、top()を使用してRDDからトップ要素を抽出することが 出来ます » top()はデータ自体の順序を使用しますが、トップ要素を抽出する為に、自分の比較関数を 供給することが出来ます – takeSample(withReplacement, num, seed) » 時々、driverはサンプルデータを必要とします » takeSample(withReplacement, num, seed)機能は交換することなく、データのサンプルを取 得することが出来ます Common Transformations and Actions(11)
  • 40. – foreach() » 時には、driverに結果を返すことなく、RDD内のすべての要素に対してactionを実行するこ とが有用です » この良い例は、WebサーバにJSONをPOSTしたり、DBにレコードを挿入することです » いずれの場合も、foreach() actionは、ローカルに戻ることなく(driverに戻ることなく)、 RDDの各要素の計算を行うことが出来ます – その他の基本的なRDDの操作は、名前から想像されるように振る舞います – count()は要素数を返し、countByValue()は固有値と固有値毎の要素数を紐づけて返します Common Transformations and Actions(12) 関数名関数名関数名関数名 目的目的目的目的 実装例実装例実装例実装例 結果結果結果結果 collect() 全ての要素をRDDから戻す rdd.collect() {1, 2, 3, 3} count() RDDの要素数を戻す rdd.count() 4 countByValue() 各々の要素のRDD内の数を 戻す rdd.countByValue() {(1, 1), (2, 1), (3, 2)} take(num) RDDからnum個の要素を 戻す rdd.take(2) {1, 2} • 表3-4:基本的なactions ※ 実装例のRDDの内容:{1, 2, 3, 3}
  • 41. Common Transformations and Actions(13) 関数名関数名関数名関数名 目的目的目的目的 実装例実装例実装例実装例 結果結果結果結果 top(num) トップnum個の要素をRDD から戻す rdd.top(2) {3, 3} takeOrdered(num) (ordering) 指定された順序に基づいて、 num個の要素を戻す rdd.takeOrdered(2)( myOrdering) {3, 3} takeSample (withReplacement, num, [seed]) ランダムにnum個の要素を 戻す rdd.takeSample(fals e, 1) Nondeterministic reduce(func) 複数のRDDの要素を並行に 組込む(例:合計する)(?) rdd.reduce ((x, y) => x + y) 9 fold(zero)(func) reduce()同様。ただし、 0を指定する必要がある rdd.fold (0)((x, y) => x + y) 9 Aggregate (zeroValue) (seqOp, combOp) reduce()同様。ただし、 違う型を戻す場合に使用 する rdd.aggregate ((0, 0)) ((x, y) => (x._1 + y, x._2 + 1), (x, y) => (x._1 + y._1, x._2 + y._2)) (9, 4) foreach(func) RDDの各要素に与えられた 関数を適用する rdd.foreach(func) Nothing
  • 42. • Converting Between RDD Types(RDDの型の変換) – いくつかの関数は、RDDの特定の型だけで利用可能です(例えば、Key/Valueのペアを使用したjoin()、数値の RDDを使用したmean()/variance()) – 第6章で数値のRDDでしか使用できない関数を、第4章でKey/ValueのペアのRDDでしか使用できない関数を説 明します – ScalaとJavaでは、これらの方法は標準的なRDD上では定義されていないので、この追加機能を利用する為に、 正しい専用のクラスを得る必要があります – Scala • Scalaにおける特別な機能によるRDDへの変換は(例:RDD[Double]をnumericを必要とする機能に公開す る際)、暗黙的な変換によって、自動的に行われます • 「SparkContextの初期化」で述べた通り、これらの変換を動作させるために、 「import org.apache.spark.SparkContext._ 」を追記する必要があります • SparkContextオブジェクトのScalaDocに、暗黙的な変換に関する記述を見ることが出来ます • mean()やvariance()のような追加機能を公開する為に、暗黙的にRDDを変換するラッパークラスを用意し ます(DoubleRDDFunctions(数値データのRDDのため)、PairRDDFunctions(Key/Valueペアのため) のような) • 暗黙の変換は非常に強力ながら、時には混乱することがあります • RDDのmean()のような関数を呼び出す場合は、RDDクラスのScaladocsを確認し、mean()が存在しないこ とに気づきます • RDD[Double]とDoubleRDDFunctionsの暗黙的な変換の成功のために、呼出側が管理しています • ScaladocでRDDの機能を検索する場合は、ラッパークラスで利用可能な機能を確認してください Common Transformations and Actions(14)
  • 43. – Java • Javaにおける特殊なRDDへの変換は、もう少し明示的に行う必要があります • 具体的には、これらの型用のメソッドを追加した、これらの型のRDDのためのJavaDoubleRDDと JavaPairRDDと呼ばれる特別なクラスがあります • これは、正確に何が起きているのかをより深く理解できるという利点を持っていますが、少し厄介でもあ ります(ソースの可読性は高くなるが、実装者に負担を与える、ということかな?) • これらの特別な型のRDDを作るために、Functionクラスを使用する代わりに、特殊なバージョンを使用す る必要があります • もし、型TのRDDからDoubleRDDを生成する場合は、Function<T, Double>よりむしろ、 DoubleFunction<T>を使用します • 表3-5にて、専門化された機能とそれらの用途を示します • 私たちは、RDDの様々な関数を呼び出す必要があります(よって、単純にDoubleFunctionを生成し、 map()に渡すことは出来ません) • DoubleRDDを戻してほしい場合、map()を呼ぶ代わりに以降の他の機能と同じパターンで、mapToDouble() を呼ぶ必要があります Common Transformations and Actions(15) 関数 代替手段 用途 DoubleFlatMapFunction<T> Function<T, Iterable<Double>> DoubleRDD from a flatMapToDouble DoubleFunction<T> Function<T, double> DoubleRDD from mapToDouble PairFlatMapFunction<T, K, V> Function<T, Iterable<Tuple2<K, V>>> PairRDD<K, V> from a flatMapToPair PairFunction<T, K, V> Function<T, Tuple2<K, V>> PairRDD<K, V> from a mapToPair
  • 44. • 序文 – 前述したように、Spark RDDは遅延評価され、時には同じRDDを複数回使用することがあるかもしれません – 単純にRDDを複数回使用すると、Sparkは使用したRDDとその依存関係にあるRDDをactionを呼び出す度に再計 算します – データを多回数参照するような、反復アルゴリズムにおいて、特に高価になります – 例3-39に示すように、別の簡単な例では、同じRDDをカウントし、出力しています – RDDの複数回の計算を回避する為に、Sparkにデータを永続させることが出来ます – RDDを永続化することをSparkに依頼する場合、RDDを実行しているノードはそのパーティションを格納します – もし、データを永続化しているノードに障害が発生した場合、Sparkはデータを必要とされるタイミングで失 われたパーティションを再計算します – もし、ノード障害への対応によるスローダウンを避けたい場合、複数のノードにデータを複製することが出来 ます – Sparkは永続化に関して目的に合わせて選択できるように、多くのレベルを持っています(表3-6で確認する ことが出来ます) – Scala(例3-40)やJavaでは、persist()のデフォルトの仕様は、シリアライズ化されていないオブジェクトと してJVMヒープ領域にデータを格納します – Pythonでは、常にデータを永続化・保存する際はシリアル化します、デフォルトは塩漬けされたオブジェクト としてJVMのヒープ領域に格納されます – データをディスクやヒープ以外のストレージに出力した場合は、そのデータは常にシリアル化されます Persistence (Caching)① 例3-39:Scalaにおける重複実行 val result = input.map(x => x*x) println(result.count()) println(result.collect().mkString(","))
  • 45. Persistence (Caching)② Level Space used CPU time In memory On disk Comments MEMORY_ONLY High Low Y N MEMORY_ONLY _SER Low High Y N MEMORY_AND _DISK High Mediu m Some Some Spills to disk if there is too much data to fit in memory. MEMORY_AND _DISK_SER Low High Some Some Spills to disk if there is too much data to fit in memory. Stores serialized representation in memory. DISK_ONLY Low High N Y • 表3-6:永続化レベル(org.apache.spark.storage.StorageLevelとpyspark.StorageLevel) ※必要に応じて、ストレージレベルの末尾に“_2”を追加することで、二台のマシン上のデータを複製する ことが出来ます
  • 46. • TIP – ヒープ外のキャッシングは実験的で、Tachyonを使用しています – もしSparkのヒープ外のキャッシングに興味を持っている場合、"Running Spark on Tachyon guide(*)"を見て みましょう (*)http://tachyon-project.org/Running-Spark-on-Tachyon.html (*)日本語の解説サイト:http://qiita.com/FKuro_/items/3b34f9f64a17c73ccdd4 – 最初のactionが実行される前に、呼び出したpersist()がRDDに通知されます – persist()の呼出は、評価を強制するものではありません – あまりにも多くのデータをキャッシュしようとすると、Sparkは自動的に最長未使用時間キャッシングポリ シー(LRU)に従って、古いパーティションを追い出します – ストレージレベルが”メモリのみ”の場合、これらのパーティションは再度アクセスされた際に再計算されま す。ストレージレベルが”メモリとディスク”の場合、ディスクに出力されます – いずれの場合も、Sparkに多くのデータをキャッシュさせたとしても、JOBの失敗を心配することが無いことを 意味します – しかし、キャッシュ不要なデータは、データを有用な状態から遠ざけ、更なる再計算時間を必要とします – 最後にRDDには、unpersist()と呼ばれるキャッシュから手動で削除するメソッドが存在します Persistence (Caching)③ 例3-40: Scala におけるpersist() val result = input.map(x => x * x) result.persist(StorageLevel.DISK_ONLY) println(result.count()) println(result.collect().mkString(","))
  • 47. • 本章では、RDDの実行モデルと多くの一般的な操作をカバーしました • もしここまで読んできたのであれば、あなたはSparkにおける全てのコアコンセプトを学ぶことが出来ました • 次の章では私たちは特別な操作のセットを可能にするKey/Valueのペアをカバーします。それは並列に集約するため に最も一般的な方法です • そのあと、我々は様々なデータソースとの入出力やSparkContextの挙動に関するより高度なトピックについて説明 します • RDDが何故弾力性があると言われているかというと、常にRDDを再計算する能力があるからです • RDDデータを保持する機械に障害が発生すると、Sparkは行方不明になったデータをユーザに意識させずに再計算し ます Conclusion(結論)