sparkジョブがあり、hdfsから8レコードのファイルを取得し、単純な集計を行ってそれをhdfsに保存します。これを行うと、何百ものタスクがあることに気づきました。
また、なぜこれに複数の仕事があるのかわかりません。仕事は何かが起こったときのようなものだと思いました。理由は推測できますが、このコードの内部では、1つのジョブであり、複数のジョブではなく段階に分解する必要があることを理解しています。なぜそれが段階に分解されないのですか、なぜそれが仕事に分解されるのですか?
200を超えるタスクについては、データの量とノードの量はごくわずかであるため、1つの集計といくつかのフィルターしかない場合、データの各行に25のタスクほどあることは意味がありません。なぜ、アトミック操作ごとに、パーティションごとに1つのタスクしかないのですか?
ここに関連するscalaコード-
import org.Apache.spark.sql._
import org.Apache.spark.sql.types._
import org.Apache.spark.SparkContext._
import org.Apache.spark.SparkConf
object TestProj {object TestProj {
def main(args: Array[String]) {
/* set the application name in the SparkConf object */
val appConf = new SparkConf().setAppName("Test Proj")
/* env settings that I don't need to set in REPL*/
val sc = new SparkContext(appConf)
val sqlContext = new SQLContext(sc)
import sqlContext.implicits._
val rdd1 = sc.textFile("hdfs://node002:8020/flat_files/miscellaneous/ex.txt")
/*the below rdd will have schema defined in Record class*/
val rddCase = sc.textFile("hdfs://node002:8020/flat_files/miscellaneous/ex.txt")
.map(x=>x.split(" ")) //file record into array of strings based spaces
.map(x=>Record(
x(0).toInt,
x(1).asInstanceOf[String],
x(2).asInstanceOf[String],
x(3).toInt))
/* the below dataframe groups on first letter of first name and counts it*/
val aggDF = rddCase.toDF()
.groupBy($"firstName".substr(1,1).alias("firstLetter"))
.count
.orderBy($"firstLetter")
/* save to hdfs*/
aggDF.write.format("parquet").mode("append").save("/raw/miscellaneous/ex_out_agg")
}
case class Record(id: Int
, firstName: String
, lastName: String
, quantity:Int)
}
以下は、アプリケーションをクリックした後のスクリーンショットです
以下は、ID 0の特定の「ジョブ」を表示するときのステージショーです
以下は、200以上のタスクがあるステージをクリックしたときの画面の最初の部分です
リクエストに応じて、ジョブID 1のステージは次のとおりです
200タスクのジョブID 1のステージの詳細は次のとおりです
これは古典的なSparkの質問です。
読み取りに使用される2つのタスク(2番目の図のステージID 0)は、2に設定されたdefaultMinPartitions
設定です。このパラメーターは、REPL _sc.defaultMinPartitions
_。[環境]タブのSpark UIにも表示されます。
GitHubの code を見て、これがまさに何が起こっているかを確認できます。読み取り時にさらにパーティションを使用する場合は、sc.textFile("a.txt", 20)
などのように、それをパラメーターとして追加するだけです。
ここで興味深いのは、第2ステージ(2番目の図のステージID 1)にある200のパーティションです。まあ、シャッフルがあるたびに、SparkはRDDをシャッフルするパーティションの数を決定する必要があります。ご想像のとおり、デフォルトは200です。
あなたはそれを変更することができます:
_sqlContext.setConf("spark.sql.shuffle.partitions", "4”)
_
この構成でコードを実行すると、200個のパーティションが存在しないことがわかります。このパラメータの設定方法は、一種の芸術です。多分あなたが持っているコアの数の2倍(または何でも)を選択してください。
Spark 2.0はRDDをシャッフルするためのパーティションの最適な数を自動的に推測する方法を持っていると思います。それを楽しみにしています!
最後に、取得するジョブの数は、結果として得られた最適化されたDataframeコードの結果RDDアクションの数に関係しています。 Spark仕様を読むと、各RDDアクションが1つのジョブをトリガーすることを示しています。アクションにDataframeまたはSparkSQLが含まれる場合、Catalystオプティマイザは実行計画を理解し、RDDベースのコードを生成してそれを実行します。ケースで2つのアクションを使用する理由を正確に述べるのは困難です。最適化されたクエリプランを調べて、何が行われているかを正確に確認する必要がある場合があります。
同様の問題が発生しています。しかし、私のシナリオでは、並列化しているコレクションは、Sparkによってスケジュールされたタスクの数よりも少ない要素を持っています(sparkが時々奇妙に動作する原因となる)。パーティション番号この問題を修正することができました。
それはこのようなものでした:
collection = range(10) # In the real scenario it was a complex collection
sc.parallelize(collection).map(lambda e: e + 1) # also a more complex operation in the real scenario
次に、Sparkログで見ました:
INFO YarnClusterScheduler: Adding task set 0.0 with 512 tasks