hscj2019_ishizaki_public

Kazuaki Ishizaki
Kazuaki IshizakiResearcher at IBM Research - Tokyo
石崎 一明
日本アイ・ビー・エム(株)東京基礎研究所
@kiszk
DataFrameとDatasetの内部をのぞいてみる
1
About Me – Kazuaki Ishizaki
▪ IBM Research – Tokyoで研究員をしています
https://ibm.biz/ishizaki
– コンパイラ最適化、言語処理系実装、並列処理、が専門
▪ 1996年より、IBM Java(今はOpen J9)の実装にかかわる
– 特に、PowerPC用の実行時コンパイラの実装リード
▪ 2018年9月より、Apache Sparkコミッタ(SQLモジュール)
– 現在、Apache Sparkコミッタは日本に4人
▪ 2018年よりACM Distinguished Member
▪ SNS
– @kiszk
– Slideshare: https://www.slideshare.net/ishizaki
2 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
今日のお話
▪ DataFrameとDatasetでできることの違い
▪ DataFrameとDatasetで同じ処理を行ったときの、性能差は?
▪ DataFrameとDatasetは、内部をのぞいて見るとどのように違うか?
▪ Spark 2.xでどんな性能改善がされてきたか?
▪ まだ残されている性能改善の余地は?
3 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
こんなことを知って役に立つのか?
▪ アプリケーションプログラマにとって
– 高速に処理可能なMLパイプラインを書く助けになる
▪ 機械学習(ML)ライブラリ開発者にとって
– RDDの代わりに、Datasetを使いたくなる かもしれない
– Issueを投げたくなる
▪ SQLモジュールのコントリビュータにとって
– プルリクを投げる余地があることが分かる
4 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
DataFrame、Dataset、(とおまけでRDD)
5 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
SQLDataFrame (DF) Dataset (DS)
RDD
ラムダ式を使って処理を記述
コンパイル時に変数の型が分かる
SQLのオペレータで処理を記述
df = (1 to 100).toDF.cache
df.selectExpr(“value + 1”)
ds = (1 to 100).toDS.cache
ds.map(value => value + 1)
rdd = sc.parallelize(
(1 to 100)).cache
rdd.map(value => value + 1)
DataFrameもDatasetもできること
▪ 単純な演算
▪ 合計などの集合演算
6 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
DataFrame (DF) Dataset (DS)
df = (1 to 100).toDF
df.agg(sum(“value”))
ds = (1 to 100).toDS
ds.reduce(_ + _)
ds = (1 to 100).toDS
ds.map(value => value + 1)
df = (1 to 100).toDF
df.selectExpr(“value + 1”)
DataFrameができなくてDatasetができること
▪ ループの記述
7 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
DataFrame (DF) Dataset (DS)
ds = (1 to 100).toDS
ds.map(value => {
int a = 1;
for (int i = 1; i <= value; i++) {
a *= i;
}
return a;
})
ループが無いと、機械学習のアルゴリズムが書けない…
DF, DS, RDDはSpark内部でどう処理されているのか?
– 書いたプログラムが直接実行されるのではなく、生成されたJavaコードが実
行される
8 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
From Structuring Apache Spark 2.0: SQL, DataFrames, Datasets And Streaming - by Michael Armbrust
DS
DF
Catalyst 最適化器
// generated Java code
// for DF and DS
while (itr.hasNext()) {
Row r = (Row)itr.next();
int v = r.getInt(0);
…
}
DF, DS, RDDはSpark内部でどう処理されているのか?
– 書いたプログラムが直接実行されるのではなく、生成されたJavaコードが実
行される
– DFとDSを使ったプログラムは同じ最適化パスを通るので、
同様に最適化され、同じコードが生成され、同じ性能が出るはず?9 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
From Structuring Apache Spark 2.0: SQL, DataFrames, Datasets And Streaming - by Michael Armbrust
DS
DF
Catalyst 最適化器
// generated Java code
// for DF and DS
while (itr.hasNext()) {
Row r = (Row)itr.next();
int v = r.getInt(0);
…
}
単純な処理のDatasetプログラムでも遅い @Spark 2.0
▪ スカラ整数変数への足し算が、DataFrameに比べて1.7倍遅い
10 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
0 0.5 1 1.5 2
DataFrameの実行時間に対する相対値
DataFrame Dataset
All experiments are done using
16-core Intel E2667-v3 3.2GHz, with 384GB mem, Ubuntu 16.04,
OpenJDK 1.8.0u212-b13 with 256GB heap, Spark master=local[1]
Spark branch-2.0 and branch-2.2, ds/df/rdd are cached
左のほうが高速
ds.map(value => value + 1)
df.selectExpr(“value + 1”)
配列のDatasetプログラムではもっと遅い @Spark 2.0
▪ 整数配列の生成が、DataFrameに比べて54倍遅い
11 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
左のほうが高速
0 10 20 30 40 50 60
DataFrameの実行時間に対する相対値
DataFrame Dataset
SPARK-16070参照
ds = Seq(Array(…), Array(…), …)
.toDS.cache
ds.map(a => Array(a(0)))
df = Seq(Array(…), Array(…), …)
.toDF(“a”).cache
df.selectExpr(“Array(a[0])”)
Spark 2.2では、これらのプログラムを高速化しました
▪ スカラ整数変数への足し算は、1.6倍速く
▪ 整数配列の生成は、4.5倍速く
12 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
どうやって?
Catalystとコード生成を改良しました
ds.map(value => value + 1)
ds = Seq(Array(…), Array(…), …)
.toDS.cache
ds.map(a => Array(a(0)))
このあとの話の流れ
▪ DataFrameとDatasetの紹介と現状
▪ 先程の2つの例を深掘り
– なぜDatasetは遅いのか?
– Spark 2.2ではどのように改善したか?
▪ 別の例を深掘り
– なぜDatasetは遅いのか?
– 将来のSparkで改善する余地はどこにあるのか?
▪ DatasetはSpark MLパイプラインでどのように使われているか?
▪ 終わりに
13 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
DataFrameでのスカラ整数を扱うプログラム
▪ 全てSparkが生成したコードを実行する
▪ int型の足し算を実行する、きれいなJavaコードが生成される
– DataframeがSpark内でvalueがint型であることを知っている
– Project Tungstenで高速化のために導入した列の独自データ構造表現から、整
数を読み出し、intを使ったJavaコードを生成する
14
while (itr.hasNext()) { // execute a row
// get a value from a row in DF
int value =((Row)itr.next()).getInt(0);
// compute a new value
int mapValue = value + 1;
// store a new value to a row in DF
outRow.write(0, mapValue);
append(outRow);
}
// df: DataFrame for int …
df.selectExpr(“value + 1”)
コード
生成
DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
Catalystで
Javaコードを
生成
列の独自データ構造(Row)
row.getInt(0)
outRow.write(0, …)
Datasetでのスカラ整数を扱うプログラム@Spark 2.0
▪ ラムダ式はScalacのコードを、それ以外はSparkが生成したコードを実行
▪ 4つのデータ型変換(intとIntegerオブジェクト)を含む、複雑なJavaコー
ドが生成される
– Scalaのラムダ式の標準インタフェース apply(Object) を使うため、Integerオブ
ジェクトを使う必要がある
15
コード
生成
DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
Catalystで
Javaコードを
生成
// ds: Dataset[Int] …
ds.map(value => value + 1)
while (itr.hasNext()) {
int value = ((Row)itr.next()).getInt(0);
Object objValue = new Integer(value);
int mapValue = ((Integer)
mapFunc.apply(objVal)).toValue();
outRow.write(0, mapValue);
append(outRow);
}
Object apply(Object obj) {
int value = Integer(obj).toValue();
return new Integer(apply$II(value));
}
int apply$II(int value) { return value + 1; }
Scalacがラムダ式から
生成したコード
Spark 2.2でどのように改善したか?
▪ DataFrameと同様に、 int型の足し算を実行する、きれいなJavaコードを
生成する(SPARK-19008)
– Scalacが apply$II(int) というコードを出すことを知って、Sparkが生成した
コードからをObjectを使わず、apply$II(int)を直呼びするコードを生成する
16
コード
生成
DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
Catalystで
Javaコードを
生成
// ds: Dataset[Int] …
ds.map(value => value + 1)
while (itr.hasNext()) {
int value = ((Row)itr.next()).getInt(0);
int mapValue = mapFunc.apply$II(value);
outRow.write(0, mapValue);
append(outRow);
}
int apply$II(int value) { return value + 1; }
Scalacがラムダ式から
生成したコード
Spark 2.2では、この場合はもう遅くない!
▪ Spark 2.0に比べて、1.6倍高速化された
– DataFrameとの差は、わずか9%
17 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
0 0.5 1 1.5 2
DataFrameの実行時間に対する相対値
DataFrame Dataset
左側のほうが高速
1.6xds.map(value => value + 1)
df.selectExpr(“value + 1”)
RDDとも比べてみると @ Spark 2.2
▪ 性能差は、大きく縮まった
18 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
0 0.5 1 1.5 2
DataFrameの実行時間に対する相対値
RDD DataFrame Dataset
9%
5%
左側のほうが高速
ds.map(value => value + 1)
df.selectExpr(“value + 1”)
df.map(value => value + 1)
生成されたJavaコードを見るには
▪ .debugCode()をつける
– DataFrame
– Dataset @ Spark 2.0
19 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
scala> import org.apache.spark.sql.execution.debug._
scala> spark.range(1, 100).selectExpr("id + 1").debugCodegen
...
/* 099 */ boolean project_isNull = false;
/* 100 */
/* 101 */ long project_value = -1L;
/* 102 */ project_value = range_value + 1L;
/* 103 */ project_rowWriter.write(0, project_value);
/* 104 */ append(project_result);
/* 105 */
...
scala> import org.apache.spark.sql.execution.debug._
scala> spark.range(1, 100).map(value => value + 1).debugCodegen
...
/* 100 */
/* 101 */ boolean mapelements_isNull = false || deserializetoobject_isNull;
/* 102 */ final long mapelements_value = mapelements_isNull ?
-1L : (Long) mapelements_value1.apply(deserializetoobject_value);
/* 103 */
...
ここで見てるのは
ほんの一部です
生成されたJavaコードを見るのがしんどい人は
▪ .explain() をつけて、Catalystが最適化した結果の実行プランを見ると雰
囲気がわかる
– DataFrame
– Dataset @ Spark 2.0
– Dataset @ Spark 2.2
20 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
scala> (1 to 100).toDF.selectExpr("value + 1").explain
== Physical Plan ==
LocalTableScan [(value + 1)#14]
scala> (1 to 100).toDS.map(value => value + 1).explain
== Physical Plan ==
*SerializeFromObject [input[0, int, false] AS value#24]
+- *MapElements <function1>, obj#23: int
+- *DeserializeToObject value#19: int, obj#22: int
+- LocalTableScan [value#19]
scala> (1 to 100).toDS.map(value => value + 1).explain
== Physical Plan ==
*SerializeFromObject [input[0, int, true] AS value#14]
+- *MapElements <function1>, obj#13: int
+- *DeserializeToObject value#9: int, obj#12: int
+- LocalTableScan [value#9]
このあとの話の流れ
▪ DataFrameとDatasetの紹介と現状
▪ 先程の2つの例を深掘り
– なぜDatasetは遅いのか?
– Spark 2.2ではどのように改善したか?
▪ 別の例を深掘り
– なぜDatasetは遅いのか?
– 将来のSparkで改善する余地はどこにあるのか?
▪ DatasetはSpark MLパイプラインでどのように使われているか?
▪ 終わりに
21 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
DataFrameでの整数配列を扱うプログラム
▪ Project Tungstenで高速化のために導入した、配列用の独自データ構造を
通して、配列操作を行う
22 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
ArrayData inArray, outArray;
while (itr.hasNext()) {
inArray = ((Row)itr.next()).getArray(0);
int value = inArray.getInt(0)); //a[0]
outArray = new UnsafeArrayData(); ...
outArray.setInt(0, value); //Array(a[0])
outArray.writeToMemory(outRow);
append(outRow);
}
配列の独自データ構造(ArrayData)
inArray.getInt(0)
outArray.setInt(0, …)
// df: DataFrame for Array(Int) …
df.selectExpr(“Array(a[0])”)
Catalystで
Javaコードを
生成
コード
生成
Datasetでの整数配列を扱うプログラム
▪ ラムダ式用のJavaバイトコードでは、Project Tungstenの独自データ構造
を操作できないため、Javaオブジェクトとの間でserialization/
deserialzation (Ser/De)が必要になる
23 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
ArrayData inArray, outArray;
while (itr.hasNext()) {
inArray = ((Row)itr.next()).getArray(0);
append(outRow);
}
配列の独自データ構造(ArrayData)
// ds: DataSet[Array(Int)] …
ds.map(a => Array(a(0)))
Catalystで
Javaコードを
生成
コード
生成
Ser/De
int[] mapArray = Array(a(0));
Ser/De
Javaオブジェクト
ラムダ式用の
Javaバイトコード Deserialization
Serialization
Ser/Deをさらに深掘りすると…
▪ 遅い操作がてんこ盛り
– Integer オブジェクトとintの間の
データ変換
– 配列要素単位のコピー
24 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
// ds: DataSet[Array(Int)] …
ds.map(a => Array(a(0)))
Catalystで
Javaコードを
生成
コード
生成
ArrayData inArray, outArray;
while (itr.hasNext()) {
inArray = ((Row)itr.next().getArray(0);
append(outRow);
}
データ変換
配列要素単位のコピー
配列要素単位のコピー
データ変換
配列要素単位のコピー Null checkを伴うデータコピー
int[] mapArray = Array(a(0));
データ変換
配列要素単位のコピー
Ser
De
Javaオブジェクトの作成 or 参照を伴う変換
Spark 2.2でどのように改善したか?
▪ 遅いSer/Deを、速いarraycopyで置き換えたコードを生成する
(SPARK-15985、SPARK-17490、SPARK-15962)
25 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
// ds: DataSet[Array(Int)] …
ds.map(a => Array(a(0)))
Catalystで
Javaコードを
生成
コード
生成
ArrayData inArray, outArray;
while (itr.hasNext()) {
inArray = ((Row)itr.next().getArray(0);
append(outRow);
}
int[] mapArray = Array(a(0));
arraycopy()を使う配列全体のコピー
配列全体のコピー
配列全体のコピー
配列全体のコピー
Spark 2.2では、超極端には遅くない!
▪ でも、まだ12倍遅いです…
26 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
0 10 20 30 40 50 60
DataFrameの実行時間に対する相対値
DataFrame Dataset
4.5x
12x
左側のほうが高速
ds = Seq(Array(…), Array(…), …)
.toDS.cache
ds.map(a => Array(a(0)))
df = Seq(Array(…), Array(…), …)
.toDF(“a”).cache
df.selectExpr(“Array(a[0])”)
map()メソッドで、計算時間がかかる
処理をしたら、無視できる …といいな
RDDとも比べてみると
▪ DataFrame版は、RDD版より速い
27 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
ds = Seq(Array(…), Array(…), …)
.toDS.cache
ds.map(a => Array(a(0)))
df = Seq(Array(…), Array(…), …)
.toDF(“a”).cache
df.selectExpr(“Array(a[0])”)
0 5 10 15
DataFrameの実行時間に対する相対値
RDD DataFrame Dataset
1.2
12
左側のほうが高速
rdd = sc.parallelize(Seq(
Array(…), Array(…), …)).cache
rdd.map(a => Array(a(0)))
実行プランを見てみると
▪ DataFrame
▪ DataSet @ Spark 2.0
▪ Dataset @ Spark 2.2
28 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
scala> sc.parallelize(Seq(Array(1)), 1).toDF.selectExpr("Array(value[0])").explain
== Physical Plan ==
*Project [array(value#39[0]) AS array(value[0])#47]
+- *SerializeFromObject [staticinvoke(class org.apache.spark.sql.catalyst.expressions.UnsafeArrayData,
ArrayType(IntegerType,false), fromPrimitiveArray, input[0, [I, true], true) AS value#39]
+- Scan ExternalRDDScan[obj#38]
scala> sc.parallelize(Seq(Array(1)), 1).toDS.map(a => Array(a(0))).explain
== Physical Plan ==
*SerializeFromObject [newInstance(class org.apache.spark.sql.catalyst.util.GenericArrayData) AS value#11]
+- *MapElements <function1>, obj#10: [I
+- *DeserializeToObject cast(value#6 as array<int>).toIntArray, obj#9: [I
+- Scan ExistingRDD[value#6]
scala> sc.parallelize(Seq(Array(1)), 1).toDS.map(a => Array(a(0))).explain
== Physical Plan ==
*SerializeFromObject [staticinvoke(class org.apache.spark.sql.catalyst.expressions.UnsafeArrayData,
ArrayType(IntegerType,false), fromPrimitiveArray, input[0, [I, true], true) AS value#34]
+- *MapElements <function1>, obj#33: [I
+- Scan ExternalRDDScan[obj#28]
ラムダ式が、独自データ構造を操作できないなら
▪ ラムダ式がProject Tungsten用の独自データ構造を操作できるように、ラ
ムダ式を書き換えてしまえばよい
▪ プロトタイプを作ってみたところ、 Ser/Deを無くすことができて大きく
性能が改善された
29 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
while (itr.hasNext()) {
inArray = ((Row)itr.next().getArray(0);
outArray = mapFunc.applyTungsten(inArray);
outArray.writeToMemory(outRow);
append(outRow);
}
// ds: DataSet[Array(Int)] …
ds.map(a => Array(a(0)))
Catalystで
Javaコードを
生成
コード
生成
“Accelerating Spark Datasets by inlining deserialization”, IPDPS2017という学会で発表済
配列の独自データ構造
1
1
apply(Object)
1011
applyTungsten
(ArrayData)
バイトコード
変換
a.getInt(0)
a.setInt(0, …)
このあとの話の流れ
▪ DataFrameとDatasetの紹介と現状
▪ 先程の2つの例を深掘り
– なぜDatasetは遅いのか?
– Spark 2.2ではどのように改善したか?
▪ 別の例を深掘り
– なぜDatasetは遅いのか?
– 将来のSparkで改善する余地はどこにあるのか?
▪ DatasetはSpark MLパイプラインでどのように使われているか?
▪ 終わりに
30 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
単純処理が続くDatasetプログラムも遅い @Spark 2.2
▪ スカラ整数変数への足し算を2回続けて実行すると、DataFrameに比べ
て1.1倍遅い
31 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
左のほうが高速
ds.map(value => value + 1)
.map(value => value + 2)
df.selectExpr(“value + 1”)
.selectExpr(“value + 2”)
rdd.map(value => value + 1)
.map(value => value + 2)
0 0.5 1 1.5
DataFrameの実行時間に対する相対値
RDD DataFrame Dataset
DataFrameでは、2つの足し算が1つになる
▪ Catalyst最適化器が、selectExpr()の中の式を足し算である、と理解し
て2つの足し算をコード生成前に計算して、value+3、に変換する
32 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
while (itr.hasNext()) {
Row row = (Row)itr.next();
int value = row.getInt(0);
int mapValue = value + 3;
projectRow.write(0, mapValue);
append(projectRow);
}
df.selectExpr(“value + 1”)
.selectExpr(“value + 2”)
Catalystで
Javaコードを
生成
コード
生成
Datasetでは、足し算のメソッド呼び出しが残ったまま
▪ Catalyst最適化器は、メソッド呼び出しの先にあるscalacが生成したJava
バイトコードが、整数の足し算である、と理解できないので、そのまま
残る
33 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
while (itr.hasNext()) {
int value = ((Row)itr.next()).getInt(0);
int mapValue = mapFunc1.apply$II(value);
mapValue += mapFunc2.apply$II(mapValue);
outRow.write(0, mapValue);
append(outRow);
}
// ds: Dataset[Int] …
ds.map(value => value + 1)
.map(value => value + 2)
Catalystで
Javaコードを
生成
コード
生成
class MapFunc1 {
int apply$II(int value) { return value + 1;}}
class MapFunc2 {
int apply$II(int value) { return value + 2;}}
Scalacがラムダ式から
生成したコード
CatalystがJavaバイトコードを理解できないのなら…
▪ 理解できるように改善すればいい(SPARK-14083)
– 残念ながら、2年近く塩漬けのプルリクとなってる
– 個人的には、このプルリクは前に進めたい
34 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
while (itr.hasNext()) {
int value = ((Row)itr.next()).getInt(0);
int mapValue = value + 3;
outRow.write(0, mapValue);
append(outRow);
}
// ds: Dataset[Int] …
ds.map(value => value + 1)
.map(value => value + 2)
Catalystで
Javaコードを
生成
コード
生成
class MapFunc1 {
int apply$II(int value) { return value + 1;}}
class MapFunc2 {
int apply$II(int value) { return value + 2;}}
Scalacがラムダ式から
生成したコード
このあとの話の流れ
▪ DataFrameとDatasetの紹介と現状
▪ 先程の2つの例を深掘り
– なぜDatasetは遅いのか?
– Spark 2.2ではどのように改善したか?
▪ 別の例を深掘り
– なぜDatasetは遅いのか?
– 将来のSparkで改善する余地はどこにあるのか?
▪ DatasetはSpark MLパイプラインでどのように使われているか?
▪ 終わりに
35 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
DatasetはSpark ML pipelineの中でどう使われている?
▪ ML Pipelineを構築するために、Datasetは使われている
▪ 個々のMLアルゴリズムを見ると、実は内部ではRDDに変換して処理を
行っている
– 主に記述力(ループ、その他)の問題?
– RDDとDatasetの変換は実行時オーバヘッドを発生する
36 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
val trainingDS: Dataset = ...
val tokenizer = new Tokenizer()
val hashingTF = new HashingTF()
val lr = new LogisticRegression()
val pipeline = new Pipeline().setStages(
Array(tokenizer, hashingTF, lr))
val model = pipeline.fit(trainingDS)
def fit(ds: Dataset[_]) = {
...
train(ds)
}
def train(ds:Dataset[_]):LogisticRegressionModel = {
val instances: RDD[Instance] =
ds.select(...).rdd.map { // convert DS to RDD
case Row(...) => ...
}
instances.persist(...)
instances.treeAggregate(...)
}
ML pipeline Machine learning algorithm (LogisticRegression)
もし、DatasetをMLアルゴリズムの記述に使ったら
▪ ML Pipelineを構築するために、Datasetを使う
▪ MLアルゴリズムもDataset上のデータに対して処理を行う
– データ変換オーバヘッドが無くなる
– Catalystによる最適化が適用される(もしSPARK-14083がマージされたら)
37 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
val trainingDataset: Dataset = ...
val tokenizer = new Tokenizer()
val hashingTF = new HashingTF()
val lr = new LogisticRegression()
val pipeline = new Pipeline().setStages(
Array(tokenizer, hashingTF, lr))
val model = pipeline.fit(trainingDataset)
def train(ds:Dataset[_]):LogisticRegressionModel = {
val instances: Dataset[Instance] =
ds.select(...).rdd.map {
case Row(...) => ...
}
instances.persist(...)
instances.treeAggregate(...)
}
ML pipeline
Machine learning algorithm (LogisticRegression)
終わりに
▪ Datasetは、Spark 2.2以降でかなり速くなった
▪ Datasetの性能改善の源泉
– 無駄なデータ変換をへらす
– Serialization/Deserializationをなくす
– (ToDo)Catalystにおけるラムダ式の扱いの改善
▪ Datasetは、ニワトリと卵、状態に陥ってしまっている
– 性能が出ないから使わない
– 使わないから、性能が出なくてもissueが上がらない
▪ ぜひ、Datasetを使ってください
– そしてissueを投げて声をあげてみてください
– できればプルリクも ☺
38 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
Sparkコミュニティに飛び込もう!
by Apache Spark コミッタ 猿田さん
https://www.slideshare.net/hadoopxnttdata/apache-spark-commnity-nttdata-sarutak
Thank you
▪ @sameeragarwal, @hvanhovell, @gatorsmile, @cloud-fan, @ueshin,
@davies, @rxin, @joshrosen, @maropu, @viirya
▪ IBM CODAIT
39 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
1 of 39

Recommended

Istioサービスメッシュ入門 by
Istioサービスメッシュ入門Istioサービスメッシュ入門
Istioサービスメッシュ入門Yoichi Kawasaki
39.3K views52 slides
ストリームデータ分散処理基盤Storm by
ストリームデータ分散処理基盤Stormストリームデータ分散処理基盤Storm
ストリームデータ分散処理基盤StormNTT DATA OSS Professional Services
34.3K views62 slides
InfiniBand In-Network Computing Technology and Roadmap by
InfiniBand In-Network Computing Technology and RoadmapInfiniBand In-Network Computing Technology and Roadmap
InfiniBand In-Network Computing Technology and Roadmapinside-BigData.com
1.1K views31 slides
COBOL技術者のためのJava勉強会 by
COBOL技術者のためのJava勉強会COBOL技術者のためのJava勉強会
COBOL技術者のためのJava勉強会naka hide
2.7K views15 slides
Hadoop/Spark で Amazon S3 を徹底的に使いこなすワザ (Hadoop / Spark Conference Japan 2019) by
Hadoop/Spark で Amazon S3 を徹底的に使いこなすワザ (Hadoop / Spark Conference Japan 2019)Hadoop/Spark で Amazon S3 を徹底的に使いこなすワザ (Hadoop / Spark Conference Japan 2019)
Hadoop/Spark で Amazon S3 を徹底的に使いこなすワザ (Hadoop / Spark Conference Japan 2019)Noritaka Sekiyama
20.5K views61 slides
Hadoop and Kerberos by
Hadoop and KerberosHadoop and Kerberos
Hadoop and KerberosYuta Imai
9.4K views66 slides

More Related Content

What's hot

Amazon web services fonctionnement de quelques services by
Amazon web services   fonctionnement de quelques servicesAmazon web services   fonctionnement de quelques services
Amazon web services fonctionnement de quelques servicesPape Moussa SONKO
137 views14 slides
Docker活用パターンの整理 ― どう組み合わせるのが正解?! by
Docker活用パターンの整理 ― どう組み合わせるのが正解?!Docker活用パターンの整理 ― どう組み合わせるのが正解?!
Docker活用パターンの整理 ― どう組み合わせるのが正解?!Etsuji Nakai
8.3K views18 slides
Twitterのリアルタイム分散処理システム「Storm」入門 by
Twitterのリアルタイム分散処理システム「Storm」入門Twitterのリアルタイム分散処理システム「Storm」入門
Twitterのリアルタイム分散処理システム「Storm」入門AdvancedTechNight
65K views27 slides
VSCode Remoteでも画像コピペがしたいです! by
VSCode Remoteでも画像コピペがしたいです!VSCode Remoteでも画像コピペがしたいです!
VSCode Remoteでも画像コピペがしたいです!Taisuke Yamada
504 views42 slides
Apache Hadoopの未来 3系になって何が変わるのか? by
Apache Hadoopの未来 3系になって何が変わるのか?Apache Hadoopの未来 3系になって何が変わるのか?
Apache Hadoopの未来 3系になって何が変わるのか?NTT DATA OSS Professional Services
6.7K views48 slides
Cephのベンチマークをしました by
CephのベンチマークをしましたCephのベンチマークをしました
CephのベンチマークをしましたOSSラボ株式会社
8.7K views14 slides

What's hot(20)

Amazon web services fonctionnement de quelques services by Pape Moussa SONKO
Amazon web services   fonctionnement de quelques servicesAmazon web services   fonctionnement de quelques services
Amazon web services fonctionnement de quelques services
Pape Moussa SONKO137 views
Docker活用パターンの整理 ― どう組み合わせるのが正解?! by Etsuji Nakai
Docker活用パターンの整理 ― どう組み合わせるのが正解?!Docker活用パターンの整理 ― どう組み合わせるのが正解?!
Docker活用パターンの整理 ― どう組み合わせるのが正解?!
Etsuji Nakai8.3K views
Twitterのリアルタイム分散処理システム「Storm」入門 by AdvancedTechNight
Twitterのリアルタイム分散処理システム「Storm」入門Twitterのリアルタイム分散処理システム「Storm」入門
Twitterのリアルタイム分散処理システム「Storm」入門
AdvancedTechNight65K views
VSCode Remoteでも画像コピペがしたいです! by Taisuke Yamada
VSCode Remoteでも画像コピペがしたいです!VSCode Remoteでも画像コピペがしたいです!
VSCode Remoteでも画像コピペがしたいです!
Taisuke Yamada504 views
Mise en place d’une plateforme de formation IMS by Kokou Gaglo
Mise en place d’une plateforme de formation IMSMise en place d’une plateforme de formation IMS
Mise en place d’une plateforme de formation IMS
Kokou Gaglo6.8K views
Veeam 整合地端與 AWS 雲端的資料保護 (2021 版本) by Wales Chen
Veeam 整合地端與 AWS 雲端的資料保護 (2021 版本)Veeam 整合地端與 AWS 雲端的資料保護 (2021 版本)
Veeam 整合地端與 AWS 雲端的資料保護 (2021 版本)
Wales Chen418 views
Présentation de nagios by ilyassin
Présentation de nagiosPrésentation de nagios
Présentation de nagios
ilyassin3.6K views
RHEL7/CentOS7 NetworkManager徹底入門 by Etsuji Nakai
RHEL7/CentOS7 NetworkManager徹底入門RHEL7/CentOS7 NetworkManager徹底入門
RHEL7/CentOS7 NetworkManager徹底入門
Etsuji Nakai52.5K views
Kubernetes 疲れに Azure Container Apps はいかがでしょうか?(江東区合同ライトニングトーク 発表資料) by NTT DATA Technology & Innovation
Kubernetes 疲れに Azure Container Apps はいかがでしょうか?(江東区合同ライトニングトーク 発表資料)Kubernetes 疲れに Azure Container Apps はいかがでしょうか?(江東区合同ライトニングトーク 発表資料)
Kubernetes 疲れに Azure Container Apps はいかがでしょうか?(江東区合同ライトニングトーク 発表資料)
EthernetやCPUなどの話 by Takanori Sejima
EthernetやCPUなどの話EthernetやCPUなどの話
EthernetやCPUなどの話
Takanori Sejima18.2K views
大規模データ処理の定番OSS Hadoop / Spark 最新動向 - 2021秋 -(db tech showcase 2021 / ONLINE 発... by NTT DATA Technology & Innovation
大規模データ処理の定番OSS Hadoop / Spark 最新動向 - 2021秋 -(db tech showcase 2021 / ONLINE 発...大規模データ処理の定番OSS Hadoop / Spark 最新動向 - 2021秋 -(db tech showcase 2021 / ONLINE 発...
大規模データ処理の定番OSS Hadoop / Spark 最新動向 - 2021秋 -(db tech showcase 2021 / ONLINE 発...
並列分散処理基盤Hadoopの紹介と、開発者が語るHadoopの使いどころ (Silicon Valley x 日本 / Tech x Business ... by NTT DATA OSS Professional Services
並列分散処理基盤Hadoopの紹介と、開発者が語るHadoopの使いどころ (Silicon Valley x 日本 / Tech x Business ...並列分散処理基盤Hadoopの紹介と、開発者が語るHadoopの使いどころ (Silicon Valley x 日本 / Tech x Business ...
並列分散処理基盤Hadoopの紹介と、開発者が語るHadoopの使いどころ (Silicon Valley x 日本 / Tech x Business ...
kpackによるコンテナイメージのビルド by Masanori Nara
kpackによるコンテナイメージのビルドkpackによるコンテナイメージのビルド
kpackによるコンテナイメージのビルド
Masanori Nara1.6K views
NetApp FAS8000 特徴とメリットのまとめ(2Page) by Daiji Takigawa
NetApp FAS8000 特徴とメリットのまとめ(2Page)NetApp FAS8000 特徴とメリットのまとめ(2Page)
NetApp FAS8000 特徴とメリットのまとめ(2Page)
Daiji Takigawa3.5K views
[Cloud OnAir] Google Cloud とつなぐ色々な方法 〜 つなぐ方法をゼロからご紹介します〜 2019年1月31日 放送 by Google Cloud Platform - Japan
[Cloud OnAir] Google Cloud とつなぐ色々な方法 〜 つなぐ方法をゼロからご紹介します〜 2019年1月31日 放送[Cloud OnAir] Google Cloud とつなぐ色々な方法 〜 つなぐ方法をゼロからご紹介します〜 2019年1月31日 放送
[Cloud OnAir] Google Cloud とつなぐ色々な方法 〜 つなぐ方法をゼロからご紹介します〜 2019年1月31日 放送
DockerとPodmanの比較 by Akihiro Suda
DockerとPodmanの比較DockerとPodmanの比較
DockerとPodmanの比較
Akihiro Suda48K views

Similar to hscj2019_ishizaki_public

Sparkのクエリ処理系と周辺の話題 by
Sparkのクエリ処理系と周辺の話題Sparkのクエリ処理系と周辺の話題
Sparkのクエリ処理系と周辺の話題Takeshi Yamamuro
2.8K views25 slides
Introduction new features in Spark 3.0 by
Introduction new features in Spark 3.0Introduction new features in Spark 3.0
Introduction new features in Spark 3.0Kazuaki Ishizaki
994 views28 slides
PostgreSQL 12の話 by
PostgreSQL 12の話PostgreSQL 12の話
PostgreSQL 12の話Masahiko Sawada
7.6K views32 slides
Node.js勉強会 Framework Koa by
Node.js勉強会 Framework KoaNode.js勉強会 Framework Koa
Node.js勉強会 Framework Koakamiyam .
8.6K views35 slides
Apache Torqueについて by
Apache TorqueについてApache Torqueについて
Apache Torqueについてtako pons
2.2K views44 slides
Gorinphp0729 by
Gorinphp0729Gorinphp0729
Gorinphp0729akitsukada
385 views73 slides

Similar to hscj2019_ishizaki_public(20)

Sparkのクエリ処理系と周辺の話題 by Takeshi Yamamuro
Sparkのクエリ処理系と周辺の話題Sparkのクエリ処理系と周辺の話題
Sparkのクエリ処理系と周辺の話題
Takeshi Yamamuro2.8K views
Introduction new features in Spark 3.0 by Kazuaki Ishizaki
Introduction new features in Spark 3.0Introduction new features in Spark 3.0
Introduction new features in Spark 3.0
Kazuaki Ishizaki994 views
Node.js勉強会 Framework Koa by kamiyam .
Node.js勉強会 Framework KoaNode.js勉強会 Framework Koa
Node.js勉強会 Framework Koa
kamiyam .8.6K views
Apache Torqueについて by tako pons
Apache TorqueについてApache Torqueについて
Apache Torqueについて
tako pons2.2K views
Gorinphp0729 by akitsukada
Gorinphp0729Gorinphp0729
Gorinphp0729
akitsukada385 views
Gorinphp0729 by akitsukada
Gorinphp0729Gorinphp0729
Gorinphp0729
akitsukada725 views
Taming Distributed/Parallel Query Execution Engine of Apache Spark by Takeshi Yamamuro
Taming Distributed/Parallel Query Execution Engine of Apache SparkTaming Distributed/Parallel Query Execution Engine of Apache Spark
Taming Distributed/Parallel Query Execution Engine of Apache Spark
Takeshi Yamamuro1.4K views
React Native GUIDE by dcubeio
React Native GUIDEReact Native GUIDE
React Native GUIDE
dcubeio1.3K views
StackStormを活用した運用自動化の実践 by Shu Sugimoto
StackStormを活用した運用自動化の実践StackStormを活用した運用自動化の実践
StackStormを活用した運用自動化の実践
Shu Sugimoto3.2K views
言語アップデート -Scala編- by Kota Mizushima
言語アップデート -Scala編-言語アップデート -Scala編-
言語アップデート -Scala編-
Kota Mizushima2.2K views
Hadoop基盤上のETL構築実践例 ~多様なデータをどう扱う?~ by Sotaro Kimura
Hadoop基盤上のETL構築実践例 ~多様なデータをどう扱う?~Hadoop基盤上のETL構築実践例 ~多様なデータをどう扱う?~
Hadoop基盤上のETL構築実践例 ~多様なデータをどう扱う?~
Sotaro Kimura1.6K views
G-Tech2015 Hadoop/Sparkを中核としたビッグデータ基盤_20151006 by Cloudera Japan
G-Tech2015 Hadoop/Sparkを中核としたビッグデータ基盤_20151006G-Tech2015 Hadoop/Sparkを中核としたビッグデータ基盤_20151006
G-Tech2015 Hadoop/Sparkを中核としたビッグデータ基盤_20151006
Cloudera Japan2.1K views
JavaScript.Next by dynamis
JavaScript.NextJavaScript.Next
JavaScript.Next
dynamis 28.8K views
Asakusa FrameworkとScalaの密かな関係 by hishidama
Asakusa FrameworkとScalaの密かな関係Asakusa FrameworkとScalaの密かな関係
Asakusa FrameworkとScalaの密かな関係
hishidama2.2K views
Oracle Cloud Developers Meetup@東京 by tuchimur
Oracle Cloud Developers Meetup@東京Oracle Cloud Developers Meetup@東京
Oracle Cloud Developers Meetup@東京
tuchimur2K views
Hive on Spark を活用した高速データ分析 - Hadoop / Spark Conference Japan 2016 by Nagato Kasaki
Hive on Spark を活用した高速データ分析 - Hadoop / Spark Conference Japan 2016Hive on Spark を活用した高速データ分析 - Hadoop / Spark Conference Japan 2016
Hive on Spark を活用した高速データ分析 - Hadoop / Spark Conference Japan 2016
Nagato Kasaki16.6K views

More from Kazuaki Ishizaki

20230105_TITECH_lecture_ishizaki_public.pdf by
20230105_TITECH_lecture_ishizaki_public.pdf20230105_TITECH_lecture_ishizaki_public.pdf
20230105_TITECH_lecture_ishizaki_public.pdfKazuaki Ishizaki
414 views57 slides
20221226_TITECH_lecture_ishizaki_public.pdf by
20221226_TITECH_lecture_ishizaki_public.pdf20221226_TITECH_lecture_ishizaki_public.pdf
20221226_TITECH_lecture_ishizaki_public.pdfKazuaki Ishizaki
686 views75 slides
Make AI ecosystem more interoperable by
Make AI ecosystem more interoperableMake AI ecosystem more interoperable
Make AI ecosystem more interoperableKazuaki Ishizaki
816 views28 slides
Enabling Vectorized Engine in Apache Spark by
Enabling Vectorized Engine in Apache SparkEnabling Vectorized Engine in Apache Spark
Enabling Vectorized Engine in Apache SparkKazuaki Ishizaki
828 views58 slides
SQL Performance Improvements At a Glance in Apache Spark 3.0 by
SQL Performance Improvements At a Glance in Apache Spark 3.0SQL Performance Improvements At a Glance in Apache Spark 3.0
SQL Performance Improvements At a Glance in Apache Spark 3.0Kazuaki Ishizaki
879 views53 slides
SparkTokyo2019NovIshizaki by
SparkTokyo2019NovIshizakiSparkTokyo2019NovIshizaki
SparkTokyo2019NovIshizakiKazuaki Ishizaki
1.5K views22 slides

More from Kazuaki Ishizaki(20)

20230105_TITECH_lecture_ishizaki_public.pdf by Kazuaki Ishizaki
20230105_TITECH_lecture_ishizaki_public.pdf20230105_TITECH_lecture_ishizaki_public.pdf
20230105_TITECH_lecture_ishizaki_public.pdf
Kazuaki Ishizaki414 views
20221226_TITECH_lecture_ishizaki_public.pdf by Kazuaki Ishizaki
20221226_TITECH_lecture_ishizaki_public.pdf20221226_TITECH_lecture_ishizaki_public.pdf
20221226_TITECH_lecture_ishizaki_public.pdf
Kazuaki Ishizaki686 views
Make AI ecosystem more interoperable by Kazuaki Ishizaki
Make AI ecosystem more interoperableMake AI ecosystem more interoperable
Make AI ecosystem more interoperable
Kazuaki Ishizaki816 views
Enabling Vectorized Engine in Apache Spark by Kazuaki Ishizaki
Enabling Vectorized Engine in Apache SparkEnabling Vectorized Engine in Apache Spark
Enabling Vectorized Engine in Apache Spark
Kazuaki Ishizaki828 views
SQL Performance Improvements At a Glance in Apache Spark 3.0 by Kazuaki Ishizaki
SQL Performance Improvements At a Glance in Apache Spark 3.0SQL Performance Improvements At a Glance in Apache Spark 3.0
SQL Performance Improvements At a Glance in Apache Spark 3.0
Kazuaki Ishizaki879 views
In-Memory Evolution in Apache Spark by Kazuaki Ishizaki
In-Memory Evolution in Apache SparkIn-Memory Evolution in Apache Spark
In-Memory Evolution in Apache Spark
Kazuaki Ishizaki1.2K views
Looking back at Spark 2.x and forward to 3.0 by Kazuaki Ishizaki
Looking back at Spark 2.x and forward to 3.0Looking back at Spark 2.x and forward to 3.0
Looking back at Spark 2.x and forward to 3.0
Kazuaki Ishizaki1.5K views
20180109 titech lecture_ishizaki_public by Kazuaki Ishizaki
20180109 titech lecture_ishizaki_public20180109 titech lecture_ishizaki_public
20180109 titech lecture_ishizaki_public
Kazuaki Ishizaki1.2K views
20171212 titech lecture_ishizaki_public by Kazuaki Ishizaki
20171212 titech lecture_ishizaki_public20171212 titech lecture_ishizaki_public
20171212 titech lecture_ishizaki_public
Kazuaki Ishizaki959 views
Transparent GPU Exploitation for Java by Kazuaki Ishizaki
Transparent GPU Exploitation for JavaTransparent GPU Exploitation for Java
Transparent GPU Exploitation for Java
Kazuaki Ishizaki1.2K views
Making Hardware Accelerator Easier to Use by Kazuaki Ishizaki
Making Hardware Accelerator Easier to UseMaking Hardware Accelerator Easier to Use
Making Hardware Accelerator Easier to Use
Kazuaki Ishizaki1.3K views
Easy and High Performance GPU Programming for Java Programmers by Kazuaki Ishizaki
Easy and High Performance GPU Programming for Java ProgrammersEasy and High Performance GPU Programming for Java Programmers
Easy and High Performance GPU Programming for Java Programmers
Kazuaki Ishizaki6.9K views
20151112 kutech lecture_ishizaki_public by Kazuaki Ishizaki
20151112 kutech lecture_ishizaki_public20151112 kutech lecture_ishizaki_public
20151112 kutech lecture_ishizaki_public
Kazuaki Ishizaki7.3K views

hscj2019_ishizaki_public

  • 2. About Me – Kazuaki Ishizaki ▪ IBM Research – Tokyoで研究員をしています https://ibm.biz/ishizaki – コンパイラ最適化、言語処理系実装、並列処理、が専門 ▪ 1996年より、IBM Java(今はOpen J9)の実装にかかわる – 特に、PowerPC用の実行時コンパイラの実装リード ▪ 2018年9月より、Apache Sparkコミッタ(SQLモジュール) – 現在、Apache Sparkコミッタは日本に4人 ▪ 2018年よりACM Distinguished Member ▪ SNS – @kiszk – Slideshare: https://www.slideshare.net/ishizaki 2 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
  • 3. 今日のお話 ▪ DataFrameとDatasetでできることの違い ▪ DataFrameとDatasetで同じ処理を行ったときの、性能差は? ▪ DataFrameとDatasetは、内部をのぞいて見るとどのように違うか? ▪ Spark 2.xでどんな性能改善がされてきたか? ▪ まだ残されている性能改善の余地は? 3 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
  • 4. こんなことを知って役に立つのか? ▪ アプリケーションプログラマにとって – 高速に処理可能なMLパイプラインを書く助けになる ▪ 機械学習(ML)ライブラリ開発者にとって – RDDの代わりに、Datasetを使いたくなる かもしれない – Issueを投げたくなる ▪ SQLモジュールのコントリビュータにとって – プルリクを投げる余地があることが分かる 4 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
  • 5. DataFrame、Dataset、(とおまけでRDD) 5 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki SQLDataFrame (DF) Dataset (DS) RDD ラムダ式を使って処理を記述 コンパイル時に変数の型が分かる SQLのオペレータで処理を記述 df = (1 to 100).toDF.cache df.selectExpr(“value + 1”) ds = (1 to 100).toDS.cache ds.map(value => value + 1) rdd = sc.parallelize( (1 to 100)).cache rdd.map(value => value + 1)
  • 6. DataFrameもDatasetもできること ▪ 単純な演算 ▪ 合計などの集合演算 6 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki DataFrame (DF) Dataset (DS) df = (1 to 100).toDF df.agg(sum(“value”)) ds = (1 to 100).toDS ds.reduce(_ + _) ds = (1 to 100).toDS ds.map(value => value + 1) df = (1 to 100).toDF df.selectExpr(“value + 1”)
  • 7. DataFrameができなくてDatasetができること ▪ ループの記述 7 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki DataFrame (DF) Dataset (DS) ds = (1 to 100).toDS ds.map(value => { int a = 1; for (int i = 1; i <= value; i++) { a *= i; } return a; }) ループが無いと、機械学習のアルゴリズムが書けない…
  • 8. DF, DS, RDDはSpark内部でどう処理されているのか? – 書いたプログラムが直接実行されるのではなく、生成されたJavaコードが実 行される 8 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki From Structuring Apache Spark 2.0: SQL, DataFrames, Datasets And Streaming - by Michael Armbrust DS DF Catalyst 最適化器 // generated Java code // for DF and DS while (itr.hasNext()) { Row r = (Row)itr.next(); int v = r.getInt(0); … }
  • 9. DF, DS, RDDはSpark内部でどう処理されているのか? – 書いたプログラムが直接実行されるのではなく、生成されたJavaコードが実 行される – DFとDSを使ったプログラムは同じ最適化パスを通るので、 同様に最適化され、同じコードが生成され、同じ性能が出るはず?9 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki From Structuring Apache Spark 2.0: SQL, DataFrames, Datasets And Streaming - by Michael Armbrust DS DF Catalyst 最適化器 // generated Java code // for DF and DS while (itr.hasNext()) { Row r = (Row)itr.next(); int v = r.getInt(0); … }
  • 10. 単純な処理のDatasetプログラムでも遅い @Spark 2.0 ▪ スカラ整数変数への足し算が、DataFrameに比べて1.7倍遅い 10 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki 0 0.5 1 1.5 2 DataFrameの実行時間に対する相対値 DataFrame Dataset All experiments are done using 16-core Intel E2667-v3 3.2GHz, with 384GB mem, Ubuntu 16.04, OpenJDK 1.8.0u212-b13 with 256GB heap, Spark master=local[1] Spark branch-2.0 and branch-2.2, ds/df/rdd are cached 左のほうが高速 ds.map(value => value + 1) df.selectExpr(“value + 1”)
  • 11. 配列のDatasetプログラムではもっと遅い @Spark 2.0 ▪ 整数配列の生成が、DataFrameに比べて54倍遅い 11 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki 左のほうが高速 0 10 20 30 40 50 60 DataFrameの実行時間に対する相対値 DataFrame Dataset SPARK-16070参照 ds = Seq(Array(…), Array(…), …) .toDS.cache ds.map(a => Array(a(0))) df = Seq(Array(…), Array(…), …) .toDF(“a”).cache df.selectExpr(“Array(a[0])”)
  • 12. Spark 2.2では、これらのプログラムを高速化しました ▪ スカラ整数変数への足し算は、1.6倍速く ▪ 整数配列の生成は、4.5倍速く 12 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki どうやって? Catalystとコード生成を改良しました ds.map(value => value + 1) ds = Seq(Array(…), Array(…), …) .toDS.cache ds.map(a => Array(a(0)))
  • 13. このあとの話の流れ ▪ DataFrameとDatasetの紹介と現状 ▪ 先程の2つの例を深掘り – なぜDatasetは遅いのか? – Spark 2.2ではどのように改善したか? ▪ 別の例を深掘り – なぜDatasetは遅いのか? – 将来のSparkで改善する余地はどこにあるのか? ▪ DatasetはSpark MLパイプラインでどのように使われているか? ▪ 終わりに 13 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
  • 14. DataFrameでのスカラ整数を扱うプログラム ▪ 全てSparkが生成したコードを実行する ▪ int型の足し算を実行する、きれいなJavaコードが生成される – DataframeがSpark内でvalueがint型であることを知っている – Project Tungstenで高速化のために導入した列の独自データ構造表現から、整 数を読み出し、intを使ったJavaコードを生成する 14 while (itr.hasNext()) { // execute a row // get a value from a row in DF int value =((Row)itr.next()).getInt(0); // compute a new value int mapValue = value + 1; // store a new value to a row in DF outRow.write(0, mapValue); append(outRow); } // df: DataFrame for int … df.selectExpr(“value + 1”) コード 生成 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki Catalystで Javaコードを 生成 列の独自データ構造(Row) row.getInt(0) outRow.write(0, …)
  • 15. Datasetでのスカラ整数を扱うプログラム@Spark 2.0 ▪ ラムダ式はScalacのコードを、それ以外はSparkが生成したコードを実行 ▪ 4つのデータ型変換(intとIntegerオブジェクト)を含む、複雑なJavaコー ドが生成される – Scalaのラムダ式の標準インタフェース apply(Object) を使うため、Integerオブ ジェクトを使う必要がある 15 コード 生成 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki Catalystで Javaコードを 生成 // ds: Dataset[Int] … ds.map(value => value + 1) while (itr.hasNext()) { int value = ((Row)itr.next()).getInt(0); Object objValue = new Integer(value); int mapValue = ((Integer) mapFunc.apply(objVal)).toValue(); outRow.write(0, mapValue); append(outRow); } Object apply(Object obj) { int value = Integer(obj).toValue(); return new Integer(apply$II(value)); } int apply$II(int value) { return value + 1; } Scalacがラムダ式から 生成したコード
  • 16. Spark 2.2でどのように改善したか? ▪ DataFrameと同様に、 int型の足し算を実行する、きれいなJavaコードを 生成する(SPARK-19008) – Scalacが apply$II(int) というコードを出すことを知って、Sparkが生成した コードからをObjectを使わず、apply$II(int)を直呼びするコードを生成する 16 コード 生成 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki Catalystで Javaコードを 生成 // ds: Dataset[Int] … ds.map(value => value + 1) while (itr.hasNext()) { int value = ((Row)itr.next()).getInt(0); int mapValue = mapFunc.apply$II(value); outRow.write(0, mapValue); append(outRow); } int apply$II(int value) { return value + 1; } Scalacがラムダ式から 生成したコード
  • 17. Spark 2.2では、この場合はもう遅くない! ▪ Spark 2.0に比べて、1.6倍高速化された – DataFrameとの差は、わずか9% 17 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki 0 0.5 1 1.5 2 DataFrameの実行時間に対する相対値 DataFrame Dataset 左側のほうが高速 1.6xds.map(value => value + 1) df.selectExpr(“value + 1”)
  • 18. RDDとも比べてみると @ Spark 2.2 ▪ 性能差は、大きく縮まった 18 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki 0 0.5 1 1.5 2 DataFrameの実行時間に対する相対値 RDD DataFrame Dataset 9% 5% 左側のほうが高速 ds.map(value => value + 1) df.selectExpr(“value + 1”) df.map(value => value + 1)
  • 19. 生成されたJavaコードを見るには ▪ .debugCode()をつける – DataFrame – Dataset @ Spark 2.0 19 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki scala> import org.apache.spark.sql.execution.debug._ scala> spark.range(1, 100).selectExpr("id + 1").debugCodegen ... /* 099 */ boolean project_isNull = false; /* 100 */ /* 101 */ long project_value = -1L; /* 102 */ project_value = range_value + 1L; /* 103 */ project_rowWriter.write(0, project_value); /* 104 */ append(project_result); /* 105 */ ... scala> import org.apache.spark.sql.execution.debug._ scala> spark.range(1, 100).map(value => value + 1).debugCodegen ... /* 100 */ /* 101 */ boolean mapelements_isNull = false || deserializetoobject_isNull; /* 102 */ final long mapelements_value = mapelements_isNull ? -1L : (Long) mapelements_value1.apply(deserializetoobject_value); /* 103 */ ... ここで見てるのは ほんの一部です
  • 20. 生成されたJavaコードを見るのがしんどい人は ▪ .explain() をつけて、Catalystが最適化した結果の実行プランを見ると雰 囲気がわかる – DataFrame – Dataset @ Spark 2.0 – Dataset @ Spark 2.2 20 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki scala> (1 to 100).toDF.selectExpr("value + 1").explain == Physical Plan == LocalTableScan [(value + 1)#14] scala> (1 to 100).toDS.map(value => value + 1).explain == Physical Plan == *SerializeFromObject [input[0, int, false] AS value#24] +- *MapElements <function1>, obj#23: int +- *DeserializeToObject value#19: int, obj#22: int +- LocalTableScan [value#19] scala> (1 to 100).toDS.map(value => value + 1).explain == Physical Plan == *SerializeFromObject [input[0, int, true] AS value#14] +- *MapElements <function1>, obj#13: int +- *DeserializeToObject value#9: int, obj#12: int +- LocalTableScan [value#9]
  • 21. このあとの話の流れ ▪ DataFrameとDatasetの紹介と現状 ▪ 先程の2つの例を深掘り – なぜDatasetは遅いのか? – Spark 2.2ではどのように改善したか? ▪ 別の例を深掘り – なぜDatasetは遅いのか? – 将来のSparkで改善する余地はどこにあるのか? ▪ DatasetはSpark MLパイプラインでどのように使われているか? ▪ 終わりに 21 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
  • 22. DataFrameでの整数配列を扱うプログラム ▪ Project Tungstenで高速化のために導入した、配列用の独自データ構造を 通して、配列操作を行う 22 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki ArrayData inArray, outArray; while (itr.hasNext()) { inArray = ((Row)itr.next()).getArray(0); int value = inArray.getInt(0)); //a[0] outArray = new UnsafeArrayData(); ... outArray.setInt(0, value); //Array(a[0]) outArray.writeToMemory(outRow); append(outRow); } 配列の独自データ構造(ArrayData) inArray.getInt(0) outArray.setInt(0, …) // df: DataFrame for Array(Int) … df.selectExpr(“Array(a[0])”) Catalystで Javaコードを 生成 コード 生成
  • 23. Datasetでの整数配列を扱うプログラム ▪ ラムダ式用のJavaバイトコードでは、Project Tungstenの独自データ構造 を操作できないため、Javaオブジェクトとの間でserialization/ deserialzation (Ser/De)が必要になる 23 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki ArrayData inArray, outArray; while (itr.hasNext()) { inArray = ((Row)itr.next()).getArray(0); append(outRow); } 配列の独自データ構造(ArrayData) // ds: DataSet[Array(Int)] … ds.map(a => Array(a(0))) Catalystで Javaコードを 生成 コード 生成 Ser/De int[] mapArray = Array(a(0)); Ser/De Javaオブジェクト ラムダ式用の Javaバイトコード Deserialization Serialization
  • 24. Ser/Deをさらに深掘りすると… ▪ 遅い操作がてんこ盛り – Integer オブジェクトとintの間の データ変換 – 配列要素単位のコピー 24 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki // ds: DataSet[Array(Int)] … ds.map(a => Array(a(0))) Catalystで Javaコードを 生成 コード 生成 ArrayData inArray, outArray; while (itr.hasNext()) { inArray = ((Row)itr.next().getArray(0); append(outRow); } データ変換 配列要素単位のコピー 配列要素単位のコピー データ変換 配列要素単位のコピー Null checkを伴うデータコピー int[] mapArray = Array(a(0)); データ変換 配列要素単位のコピー Ser De Javaオブジェクトの作成 or 参照を伴う変換
  • 25. Spark 2.2でどのように改善したか? ▪ 遅いSer/Deを、速いarraycopyで置き換えたコードを生成する (SPARK-15985、SPARK-17490、SPARK-15962) 25 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki // ds: DataSet[Array(Int)] … ds.map(a => Array(a(0))) Catalystで Javaコードを 生成 コード 生成 ArrayData inArray, outArray; while (itr.hasNext()) { inArray = ((Row)itr.next().getArray(0); append(outRow); } int[] mapArray = Array(a(0)); arraycopy()を使う配列全体のコピー 配列全体のコピー 配列全体のコピー 配列全体のコピー
  • 26. Spark 2.2では、超極端には遅くない! ▪ でも、まだ12倍遅いです… 26 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki 0 10 20 30 40 50 60 DataFrameの実行時間に対する相対値 DataFrame Dataset 4.5x 12x 左側のほうが高速 ds = Seq(Array(…), Array(…), …) .toDS.cache ds.map(a => Array(a(0))) df = Seq(Array(…), Array(…), …) .toDF(“a”).cache df.selectExpr(“Array(a[0])”) map()メソッドで、計算時間がかかる 処理をしたら、無視できる …といいな
  • 27. RDDとも比べてみると ▪ DataFrame版は、RDD版より速い 27 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki ds = Seq(Array(…), Array(…), …) .toDS.cache ds.map(a => Array(a(0))) df = Seq(Array(…), Array(…), …) .toDF(“a”).cache df.selectExpr(“Array(a[0])”) 0 5 10 15 DataFrameの実行時間に対する相対値 RDD DataFrame Dataset 1.2 12 左側のほうが高速 rdd = sc.parallelize(Seq( Array(…), Array(…), …)).cache rdd.map(a => Array(a(0)))
  • 28. 実行プランを見てみると ▪ DataFrame ▪ DataSet @ Spark 2.0 ▪ Dataset @ Spark 2.2 28 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki scala> sc.parallelize(Seq(Array(1)), 1).toDF.selectExpr("Array(value[0])").explain == Physical Plan == *Project [array(value#39[0]) AS array(value[0])#47] +- *SerializeFromObject [staticinvoke(class org.apache.spark.sql.catalyst.expressions.UnsafeArrayData, ArrayType(IntegerType,false), fromPrimitiveArray, input[0, [I, true], true) AS value#39] +- Scan ExternalRDDScan[obj#38] scala> sc.parallelize(Seq(Array(1)), 1).toDS.map(a => Array(a(0))).explain == Physical Plan == *SerializeFromObject [newInstance(class org.apache.spark.sql.catalyst.util.GenericArrayData) AS value#11] +- *MapElements <function1>, obj#10: [I +- *DeserializeToObject cast(value#6 as array<int>).toIntArray, obj#9: [I +- Scan ExistingRDD[value#6] scala> sc.parallelize(Seq(Array(1)), 1).toDS.map(a => Array(a(0))).explain == Physical Plan == *SerializeFromObject [staticinvoke(class org.apache.spark.sql.catalyst.expressions.UnsafeArrayData, ArrayType(IntegerType,false), fromPrimitiveArray, input[0, [I, true], true) AS value#34] +- *MapElements <function1>, obj#33: [I +- Scan ExternalRDDScan[obj#28]
  • 29. ラムダ式が、独自データ構造を操作できないなら ▪ ラムダ式がProject Tungsten用の独自データ構造を操作できるように、ラ ムダ式を書き換えてしまえばよい ▪ プロトタイプを作ってみたところ、 Ser/Deを無くすことができて大きく 性能が改善された 29 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki while (itr.hasNext()) { inArray = ((Row)itr.next().getArray(0); outArray = mapFunc.applyTungsten(inArray); outArray.writeToMemory(outRow); append(outRow); } // ds: DataSet[Array(Int)] … ds.map(a => Array(a(0))) Catalystで Javaコードを 生成 コード 生成 “Accelerating Spark Datasets by inlining deserialization”, IPDPS2017という学会で発表済 配列の独自データ構造 1 1 apply(Object) 1011 applyTungsten (ArrayData) バイトコード 変換 a.getInt(0) a.setInt(0, …)
  • 30. このあとの話の流れ ▪ DataFrameとDatasetの紹介と現状 ▪ 先程の2つの例を深掘り – なぜDatasetは遅いのか? – Spark 2.2ではどのように改善したか? ▪ 別の例を深掘り – なぜDatasetは遅いのか? – 将来のSparkで改善する余地はどこにあるのか? ▪ DatasetはSpark MLパイプラインでどのように使われているか? ▪ 終わりに 30 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
  • 31. 単純処理が続くDatasetプログラムも遅い @Spark 2.2 ▪ スカラ整数変数への足し算を2回続けて実行すると、DataFrameに比べ て1.1倍遅い 31 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki 左のほうが高速 ds.map(value => value + 1) .map(value => value + 2) df.selectExpr(“value + 1”) .selectExpr(“value + 2”) rdd.map(value => value + 1) .map(value => value + 2) 0 0.5 1 1.5 DataFrameの実行時間に対する相対値 RDD DataFrame Dataset
  • 32. DataFrameでは、2つの足し算が1つになる ▪ Catalyst最適化器が、selectExpr()の中の式を足し算である、と理解し て2つの足し算をコード生成前に計算して、value+3、に変換する 32 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki while (itr.hasNext()) { Row row = (Row)itr.next(); int value = row.getInt(0); int mapValue = value + 3; projectRow.write(0, mapValue); append(projectRow); } df.selectExpr(“value + 1”) .selectExpr(“value + 2”) Catalystで Javaコードを 生成 コード 生成
  • 33. Datasetでは、足し算のメソッド呼び出しが残ったまま ▪ Catalyst最適化器は、メソッド呼び出しの先にあるscalacが生成したJava バイトコードが、整数の足し算である、と理解できないので、そのまま 残る 33 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki while (itr.hasNext()) { int value = ((Row)itr.next()).getInt(0); int mapValue = mapFunc1.apply$II(value); mapValue += mapFunc2.apply$II(mapValue); outRow.write(0, mapValue); append(outRow); } // ds: Dataset[Int] … ds.map(value => value + 1) .map(value => value + 2) Catalystで Javaコードを 生成 コード 生成 class MapFunc1 { int apply$II(int value) { return value + 1;}} class MapFunc2 { int apply$II(int value) { return value + 2;}} Scalacがラムダ式から 生成したコード
  • 34. CatalystがJavaバイトコードを理解できないのなら… ▪ 理解できるように改善すればいい(SPARK-14083) – 残念ながら、2年近く塩漬けのプルリクとなってる – 個人的には、このプルリクは前に進めたい 34 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki while (itr.hasNext()) { int value = ((Row)itr.next()).getInt(0); int mapValue = value + 3; outRow.write(0, mapValue); append(outRow); } // ds: Dataset[Int] … ds.map(value => value + 1) .map(value => value + 2) Catalystで Javaコードを 生成 コード 生成 class MapFunc1 { int apply$II(int value) { return value + 1;}} class MapFunc2 { int apply$II(int value) { return value + 2;}} Scalacがラムダ式から 生成したコード
  • 35. このあとの話の流れ ▪ DataFrameとDatasetの紹介と現状 ▪ 先程の2つの例を深掘り – なぜDatasetは遅いのか? – Spark 2.2ではどのように改善したか? ▪ 別の例を深掘り – なぜDatasetは遅いのか? – 将来のSparkで改善する余地はどこにあるのか? ▪ DatasetはSpark MLパイプラインでどのように使われているか? ▪ 終わりに 35 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki
  • 36. DatasetはSpark ML pipelineの中でどう使われている? ▪ ML Pipelineを構築するために、Datasetは使われている ▪ 個々のMLアルゴリズムを見ると、実は内部ではRDDに変換して処理を 行っている – 主に記述力(ループ、その他)の問題? – RDDとDatasetの変換は実行時オーバヘッドを発生する 36 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki val trainingDS: Dataset = ... val tokenizer = new Tokenizer() val hashingTF = new HashingTF() val lr = new LogisticRegression() val pipeline = new Pipeline().setStages( Array(tokenizer, hashingTF, lr)) val model = pipeline.fit(trainingDS) def fit(ds: Dataset[_]) = { ... train(ds) } def train(ds:Dataset[_]):LogisticRegressionModel = { val instances: RDD[Instance] = ds.select(...).rdd.map { // convert DS to RDD case Row(...) => ... } instances.persist(...) instances.treeAggregate(...) } ML pipeline Machine learning algorithm (LogisticRegression)
  • 37. もし、DatasetをMLアルゴリズムの記述に使ったら ▪ ML Pipelineを構築するために、Datasetを使う ▪ MLアルゴリズムもDataset上のデータに対して処理を行う – データ変換オーバヘッドが無くなる – Catalystによる最適化が適用される(もしSPARK-14083がマージされたら) 37 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki val trainingDataset: Dataset = ... val tokenizer = new Tokenizer() val hashingTF = new HashingTF() val lr = new LogisticRegression() val pipeline = new Pipeline().setStages( Array(tokenizer, hashingTF, lr)) val model = pipeline.fit(trainingDataset) def train(ds:Dataset[_]):LogisticRegressionModel = { val instances: Dataset[Instance] = ds.select(...).rdd.map { case Row(...) => ... } instances.persist(...) instances.treeAggregate(...) } ML pipeline Machine learning algorithm (LogisticRegression)
  • 38. 終わりに ▪ Datasetは、Spark 2.2以降でかなり速くなった ▪ Datasetの性能改善の源泉 – 無駄なデータ変換をへらす – Serialization/Deserializationをなくす – (ToDo)Catalystにおけるラムダ式の扱いの改善 ▪ Datasetは、ニワトリと卵、状態に陥ってしまっている – 性能が出ないから使わない – 使わないから、性能が出なくてもissueが上がらない ▪ ぜひ、Datasetを使ってください – そしてissueを投げて声をあげてみてください – できればプルリクも ☺ 38 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki Sparkコミュニティに飛び込もう! by Apache Spark コミッタ 猿田さん https://www.slideshare.net/hadoopxnttdata/apache-spark-commnity-nttdata-sarutak
  • 39. Thank you ▪ @sameeragarwal, @hvanhovell, @gatorsmile, @cloud-fan, @ueshin, @davies, @rxin, @joshrosen, @maropu, @viirya ▪ IBM CODAIT 39 DataFrameとDatasetの内部をのぞいてみる - Kazuaki Ishizaki