Spark RDD编程初级的实践代码,遇到问题写不下去的同学不妨来看看,重新打开自己的思路!

希望这篇文章可以帮助你理解Spark RDD的初级应用。

    任务描述
    相关知识
        RDD的创建
        RDD的转换操作
        RDD的行动操作
        计算图书平均销量的示例
    测试说明

任务描述
本关任务:编写Spark独立应用程序实现数据去重。
本关任务:编写Spark独立应用程序实现整合排序。
本关任务:编写Spark独立应用程序实现求平均值。

相关知识
为了完成本关任务,你需要掌握:RDD的创建;RDD的转换操作;RDD的行动操作。

写在前面

        对于RDD而言,每一次转换操作都会产生新的RDD,供给下一个操作使用。RDD的转换过程是惰性求值的,也就是说,整个转换过程只是记录了转换的轨迹,并不会发生真正的计算,只有遇到行动操作时,才会触发真正的计算。

第1关:数据去重 

        对于两个输入文件A和B,编写Spark独立应用程序,对两个文件进行合并、剔除其中重复的内容并排序,得到一个新文件C。

import org.apache.spark.SparkContext
import org.apache.spark.SparkConf
import org.apache.spark.HashPartitioner

object RemDup {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("RemDup").setMaster("local")
    val sc = new SparkContext(conf)

    //输入文件fileA.txt和fileB.txt已保存在本地文件系统/root/step1_files目录中
    val dataFile = "file:///root/step1_files"
    val data = sc.textFile(dataFile, 2)

    /********** Begin **********/

    //第一步:执行过滤操作,把空行丢弃。
    val rdd_1 = data.filter(_.trim().length > 0)

    //第二步:执行map操作,取出RDD中每个元素,去除尾部空格并生成一个(key, value)键值对。
    val rdd_2 = rdd_1.map(line => (line.trim, ""))

    //第三步:执行groupByKey操作,把所有key相同的value都组织成一个value-list。
    val rdd_3 = rdd_2.groupByKey()

    //第四步:对RDD进行重新分区,变成一个分区,
    //在分布式环境下只有把所有分区合并成一个分区,才能让所有元素排序后总体有序。
    val rdd_4 = rdd_3.partitionBy(new HashPartitioner(1))

    //第五步:执行sortByKey操作,对RDD中所有元素都按照key的升序排序。
    val rdd_5 = rdd_4.sortByKey()

    //第六步:执行keys操作,将键值对RDD中所有元素的key返回,形成一个新的RDD。
    val rdd_6 = rdd_5.keys

    //第七步:执行collect操作,以数组的形式返回RDD中所有元素。
    val rdd_7 = rdd_6.collect()

    //第八步:执行foreach操作,并使用println打印出数组中每个元素的值。
    println("") //注意:此行不要修改,否则会影响测试结果,在此行之后继续完成第八步的代码。
    rdd_7.foreach(println)
    
    /********** End **********/
  }
}

第二关:整合排序

        假设某个目录下有多个文本文件,每个文件中每一行内容均为一个整数。要求读取所有文件中的整数,进行排序后,输出到一个新的文件中,输出的内容为每行两个整数,第一个整数为第二个整数的排序位次,第二个整数为原待排序的整数。

import org.apache.spark.SparkContext
import org.apache.spark.SparkConf
import org.apache.spark.HashPartitioner

object FileSort {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("FileSort").setMaster("local")
    val sc = new SparkContext(conf)

    //输入文件file1.txt、file2.txt和file3.txt已保存在本地文件系统/root/step2_files目录中
    val dataFile = "file:///root/step2_files"
    val data = sc.textFile(dataFile, 3)

    /********** Begin **********/

    //第一步:执行过滤操作,把空行丢弃。
    val rdd_1 = data.filter(_.trim().length > 0)

    //第二步:执行map操作,取出RDD中每个元素,去除尾部空格并转换成整数,生成一个(key, value)键值对。
    val rdd_2 = rdd_1.map(line => (line.trim.toInt, ""))

    //第三步:对RDD进行重新分区,变成一个分区,
    //在分布式环境下只有把所有分区合并成一个分区,才能让所有元素排序后总体有序。
    val rdd_3 = rdd_2.partitionBy(new HashPartitioner(1))

    //第四步:执行sortByKey操作,对RDD中所有元素都按照key的升序排序。
    val rdd_4 = rdd_3.sortByKey()

    //第五步:执行keys操作,将键值对RDD中所有元素的key返回,形成一个新的RDD。
    val rdd_5 = rdd_4.keys

    //第六步:执行map操作,取出RDD中每个元素,生成一个(key, value)键值对,
    //其中key是整数的排序位次,value是原待排序的整数。
    var index = 0
    val rdd_6 = rdd_5.map(t => {
      index = index + 1
      (index, t)
    })

    //第七步:执行collect操作,以数组的形式返回RDD中所有元素。
    val rdd_7 = rdd_6.collect()

    //第八步:执行foreach操作,依次遍历数组中每个元素,分别取出(key, value)键值对中key和value,
    
    //按如下格式输出:key value
    println("") //注意:此行不要修改,否则会影响测试结果,在此行之后继续完成第八步的代码。
    rdd_7.foreach(t => println(t._1 + " " + t._2))

    /********** End **********/
  }
}

第三关:求平均值

        每个输入文件表示学生某门课程的成绩,输入文件中每行内容由两个字段组成,第一个字段是学生姓名,第二个字段是学生的成绩;编写Spark独立应用程序求出所有学生的平均成绩,并输出到一个新文件中。

import org.apache.spark.SparkContext
import org.apache.spark.SparkConf

object AvgScore {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("AvgScore").setMaster("local")
    val sc = new SparkContext(conf)

    //输入文件AlgorithmScore.txt、DataBaseScore.txt和PythonScore.txt已保存在本地文件系统/root/step3_files目录中
    val dataFile = "file:///root/step3_files"
    val data = sc.textFile(dataFile)

    /********** Begin **********/
    //第一步:执行过滤操作,把空行丢弃。
    val rdd_1 = data.filter(_.trim().length > 0)

    //第二步:执行map操作,取出RDD中每个元素(即一行文本),以空格作为分隔符将一行文本拆分成两个字符串,
    //拆分后得到的字符串封装在一个数组对象中,成为新的RDD中一个元素。
    var rdd_2 = rdd_1.map(line => line.split(" "))

    //第三步:执行map操作,取出RDD中每个元素(即字符串数组),取字符串数组中第一个元素去除尾部空格,
    //取字符串数组中第二个元素去除尾部空格并转换成整数,并由这两部分构建一个(key, value)键值对。
    val rdd_3 = rdd_2.map(t => (t(0).trim, t(1).trim.toInt))

    //第四步:执行mapValues操作,取出键值对RDD中每个元素的value,使用x=>(x,1)这个匿名函数进行转换。
    val rdd_4 = rdd_3.mapValues(x => (x, 1))

    //第五步:执行reduceByKey操作,计算出每个学生所有课程的总分数和总课程门数。
    val rdd_5 = rdd_4.reduceByKey((x, y) => (x._1 + y._1, x._2 + y._2))

    //第六步:执行mapValues操作,计算出每个学生的平均成绩。
    val rdd_6 = rdd_5.mapValues(x => (x._1.toDouble / x._2))

    //第七步:执行collect操作,以数组的形式返回RDD中所有元素。
    val rdd_7 = rdd_6.collect()
    
    //第八步:执行foreach操作,按如下格式打印出每个学生的平均成绩:姓名 成绩,其中成绩要求保留两位小数。
    println("") //注意:此行不要修改,否则会影响测试结果,在此行之后继续完成第八步的代码。
    rdd_7.foreach(t => {
      val abc = t._2
      println(t._1 + " " + f"$abc%1.2f")
    })
    /********** End **********/
  }
}