object WordCount {
def main(args: Array[String]): Unit = {
//创建spark配置,设置应用程序名字
//val conf = new SparkConf().setAppName("ScalaWordCount")
val conf = new SparkConf().setAppName("ScalaWordCount").setMaster("local[4]")
//创建spark执行的入口
val sc = new SparkContext(conf)
//指定以后从哪里读取数据创建RDD(弹性分布式数据集)
val lines: RDD[String] = sc.textFile("hdfs://node-4:9000/wc1", 1)
//分区数量
partitionsNum=lines.partitions.length
//切分压平
val words: RDD[String] = lines.flatMap(_.split(" "))
//将单词和一组合
val wordAndOne: RDD[(String, Int)] = words.map((_, 1))
//按key进行聚合
val reduced:RDD[(String, Int)] = wordAndOne.reduceByKey(_+_)
//排序
val sorted: RDD[(String, Int)] = reduced.sortBy(_._2, false)
//将结果保存到HDFS中
reduced.saveAsTextFile(args(1))
//释放资源
sc.stop()
}
}
过程解析
-
调用textFile()生成了两个RDD, HadoopRDD[(K,V)],MapPartitionsRDD[String]。 HadoopRDD[(K,V)],把hadoop存储系统的文件转成(K,V),Key中存储的是所取这一行偏移量(LongWritable),Value存储的是这一行的内容(Text形式),l类似Map中的输入。每个分区读取各自的输入切片
-
MapPartitionsRDD[String],可以将取出上个RDD产生的(K,V)中的Value
并且将其Text转成String -
调用flatMap(_.split(" "))的时候,其实也是生成MapPartitionsRDD[String]MapPartitionsRDD[String],功能是切分单词并且压平
-
调用map((_, 1))的时候,其实也是生成MapPartitionsRDD[(String,Int)],功能是从把string转成(String,Int)
-
调用reduceByKey(+)的时候,会先将数据写入磁盘,然后调用ShullfeRDD(String,Int),该RDD分为两个阶段,第一个是局部聚合,第二个是全局聚合,根据Key将属于自己的数据通过网络从各个分区拉去过来
-
调用saveAsTextFile(args(1))的时候,在这里调用MapPartitionsRDD[NullWritable,Text],功能是将数据整理,并且转成[NullWritable,Text],以便存储在存储系统当中,类似MapReduce中的Reduce的输出
-
输出到HDFS,生成两个文件,因为有两个分区
在此过程产生了6个rdd。共有两个Stage,每个Stage两个个task,两种Task。
RDD、Partition以及task的关系
两种task ,ShuffleMapTask和ResultTask,根据Shullfe切分。
- ShuffleMapTask:也可叫MapTask,在Shullfe的前面,负责读数据,计算处理数据,然后中间结果写入磁盘
- ResultTask:也可叫ReduceTask,在Shullfe的后面,负责从上游拉取数据,计算处理数据,将数据写入存储系统
Stage同样也是根据 Shuffle划分,然后在每个Stage中,有多少个分区,就有多少个task
经过Shullfe后,分区数量可以改变