20. RDDの変換例②flatmap()
01Spark Overview
Sparkの概要
英文を要素にもつRDD
RDD
Partition
Element
I am from Fukuoka
Hello Apache Spark
Tokyo Institute of Technology
I
am
from
Fukuoka
Hello
Apache
Spark
Tokyo
Institute
Technology
of
単語に分割したRDD例えばこのようなプログラムの場合flatmapの操作
は右図のようになります。
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.FlatMapFunction;
import java.util.Arrays;
/**
* Created by hirokinaganuma on 2016/10/11.
*/
public class Sample03 {
public static void main(String[] args) throws Exception {
String master;
if (args.length > 0) {
master = args[0];
} else {
master = "local";
}
JavaSparkContext sc = new JavaSparkContext(master, "basicavg",
System.getenv("SPARK_HOME"), System.getenv("JARS"));
JavaRDD<String> input = sc.textFile("bin/input/flatmap/*.txt");
JavaRDD<String> result = input.flatMap(
new FlatMapFunction<String, String>() {
public Iterable<String> call(String x) {
return Arrays.asList(x.split(" "));
}
}
);
result.saveAsTextFile("bin/output/output03");
sc.stop();
}
}
Sample03.java
28. LogicalPlan
02Flow of Spark processing
Sparkの処理の流れについて
package org.apache.spark.examples
import java.util.Random
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.SparkContext._
/**
* Usage: GroupByTest [numMappers] [numKVPairs] [valSize] [numReducers]
*/
object GroupByTest {
def main(args: Array[String]) {
val sparkConf = new SparkConf().setAppName("GroupBy Test")
var numMappers = 100
var numKVPairs = 10000
var valSize = 1000
var numReducers = 36
val sc = new SparkContext(sparkConf)
val pairs1 = sc.parallelize(0 until numMappers, numMappers).flatMap { p =>
val ranGen = new Random
var arr1 = new Array[(Int, Array[Byte])](numKVPairs)
for (i <- 0 until numKVPairs) {
val byteArr = new Array[Byte](valSize)
ranGen.nextBytes(byteArr)
arr1(i) = (ranGen.nextInt(Int.MaxValue), byteArr)
}
arr1
}.cache
// Enforce that everything has been calculated and in cache
pairs1.count
println(pairs1.groupByKey(numReducers).count)
sc.stop()
}
}
GroupByTest.scala
29. 02Flow of Spark processing
Sparkの処理の流れについて
【ポイント】
SparkConfが初期化される。
numMappers=100, numKVPairs=10,000, valSize=1000, numReducers=36として初期
化される。
SparkContextが初期化され、Driverに必要なオブジェクトとアクター類が生成される。
各Mapperではarr1: Array[(Int, Byte[])]を生成し、numKVPairs個の要素を保持する。各Int
値はランダムの整数値となっており、各Byte配列のサイズはvalSizeとなっている。 arr1のサ
イズはnumKVPairs * (4 + valSize) より10MBと計算されるため、pairs1のサイズは
numMappers * Size(arr1)より1000MBとなる。
各Mapperはarr1をメモリ上にキャッシュするよう指定されている。
count()アクションが全Mapper上のarr1の要素数の合計を取得するよう動作し、結果は
numMappers * numKVPairsから1,000,000となる。このアクションによって実際にarr1の
計算がおこなわれ、キャッシュされる。
groupByKeyオペレーションはキャッシュされたpairs1に対して実行される。Reducer数(=
パーティション数)はnumReducersで示される。 理論上、もしhash(key)が上手く分散され
た場合、各ReducerはnumMappers * numKVPairs / numReducerより27,777個の(Int,
Array[Byte])ペアを受信する。そのため、各Reducer上におけるデータサイズはSize(pairs1)
/ numReducerより27MBとなる。
Reducerは同一のIntキー値を保持するレコードをマージし、(Int, List(Byte[], Byte[], ...,
Byte[]))の結果を生成する。
最後にcount()アクションが各Reducer上でのレコード数の合計値を取得し、最終的な結果は
paris1中のキー重複を排除した個数となる。
package org.apache.spark.examples
import java.util.Random
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.SparkContext._
/**
* Usage: GroupByTest [numMappers] [numKVPairs] [valSize] [numReducers]
*/
object GroupByTest {
def main(args: Array[String]) {
val sparkConf = new SparkConf().setAppName("GroupBy Test")
var numMappers = 100
var numKVPairs = 10000
var valSize = 1000
var numReducers = 36
val sc = new SparkContext(sparkConf)
val pairs1 = sc.parallelize(0 until numMappers, numMappers).flatMap { p =>
val ranGen = new Random
var arr1 = new Array[(Int, Array[Byte])](numKVPairs)
for (i <- 0 until numKVPairs) {
val byteArr = new Array[Byte](valSize)
ranGen.nextBytes(byteArr)
arr1(i) = (ranGen.nextInt(Int.MaxValue), byteArr)
}
arr1
}.cache
// Enforce that everything has been calculated and in cache
pairs1.count
println(pairs1.groupByKey(numReducers).count)
sc.stop()
}
}
GroupByTest.scala
LogicalPlan
30. LogicalPlan
02Flow of Spark processing
Sparkの処理の流れについて
package org.apache.spark.examples
import java.util.Random
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.SparkContext._
/**
* Usage: GroupByTest [numMappers] [numKVPairs] [valSize] [numReducers]
*/
object GroupByTest {
def main(args: Array[String]) {
val sparkConf = new SparkConf().setAppName("GroupBy Test")
var numMappers = 100
var numKVPairs = 10000
var valSize = 1000
var numReducers = 36
val sc = new SparkContext(sparkConf)
val pairs1 = sc.parallelize(0 until numMappers, numMappers).flatMap { p =>
val ranGen = new Random
var arr1 = new Array[(Int, Array[Byte])](numKVPairs)
for (i <- 0 until numKVPairs) {
val byteArr = new Array[Byte](valSize)
ranGen.nextBytes(byteArr)
arr1(i) = (ranGen.nextInt(Int.MaxValue), byteArr)
}
arr1
}.cache
// Enforce that everything has been calculated and in cache
pairs1.count
println(pairs1.groupByKey(numReducers).count)
sc.stop()
}
}
GroupByTest.scala