从0开始学习spark(5)RDD常用算子用法训练(附习题答案)(aggregateByKey与combineByKey)!!!

本文介绍了Spark RDD的常用算子,重点讲解了aggregateByKey和combineByKey的用法,并提供了练习题及答案,帮助读者深入理解和掌握这两个高级聚合算子。此外,还给出了拉勾网职位数据的分析练习,包括不同地点的招聘数量、学历与经验的联合分组、大数据类工作的学历需求等分析任务。
摘要由CSDN通过智能技术生成

在这里插入图片描述

每日福利来一个,话不多说,我们直接开始今天的spark RDD的实战练习代码,我们学习编程,还是要多实战,在实战中我们才能领悟到平时很难理解的知识点,下面我们开始我们今天的训练吧!
没有看前面的同学可以回顾一下:

4.Spark Rdd常用算子和RDD必备知识
3.spark core 核心知识
2.spark 之 wordcount入门
1.spark 入门讲解

接下来就是我们今天的重点RDD常用算子的练习:

常见的transformation算子练习:

/**
  * 主要学习SparkTransformation的操作算子
  * 1、map:将集合中每个元素乘以7
  * 2、filter:过滤出集合中的奇数
  * 3、flatMap:将行拆分为单词
  * 4、sample:根据给定的随机种子seed,随机抽样出数量为frac的数据
  * 5、union:返回一个新的数据集,由原数据集和参数联合而成
  * 6、groupByKey:对数组进行 group by key操作 慎用
  * 7、reduceByKey:统计每个班级的人数
  * 8、join:打印关联的组合信息
  * 9、sortByKey:将学生身高进行排序
  * 10、combineByKey
  * 11、aggregateByKey
  */
object _01SparkTransformationOps1 {
    def main(args: Array[String]): Unit = {
        Logger.getLogger("org.apache.hadoop").setLevel(Level.WARN)
        Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
        Logger.getLogger("org.project-spark").setLevel(Level.WARN)
        val conf = new SparkConf()
            .setMaster("local[2]")
            .setAppName(s"${_01SparkTransformationOps1.getClass.getSimpleName}")
        val sc = new SparkContext(conf)
        val list = List(1, 2, 3, 4, 5, 6, 7)
//        transformationMap_01(list, sc)
//        transformationFlatMap_02(sc)
//        transformationFilter_03(list, sc)
//        transformationSample_04(sc)
//        transformationUnion_05(sc)
//        transformationGBK_06(sc)
//        transformationRBK_07(sc)
//        transformationJOIN_08(sc)
        transformationUnion_05(sc)
        sc.stop()
    }

    /**
      * sortByKey:将学生成绩进行排序
      *     分区内部有序
      * 学生表stu:id   name    chinese-score
      *
      */
    def transformationsbk_09(sc:SparkContext): Unit = {
        val stuList = List(
            "1  王浩玉 93.5",
            "2  贾小红 56.5",
            "3  薛亚曦 60.5",
            "4  宋其 125"
        )
        val stuRDD = sc.parallelize(stuList)
        println("------------------sortByKey----------------------")
        val score2InfoRDD:RDD[(Double, String)] = stuRDD.map { case (line) => {
            val fields = line.split("\\s+")
            (fields(2).toDouble, line)
        }}
        score2InfoRDD.sortByKey(false, numPartitions = 1).foreach(println)
        println("------------------sortBy----------------------")
        val sbkRDD2:RDD[String] = stuRDD.sortBy(line => line, false, 1)(
            new Ordering[String](){//按照成绩排序
                override def compare(x: String, y: String) = {
                    val xScore = x.split("\\s+")(2).toDouble
                    val yScore = y.split("\\s+")(2).toDouble
                    yScore.compareTo(xScore)
                }
            },
            ClassTag.Object.asInstanceOf[ClassTag[String]]
        )
        sbkRDD2.foreach(println)
    }

    /**
      * join: 打印关联的组合信息
      *    关联操作中rdd的类型必须(K, V)
      *    inner join:等值连接  返回左右两张表中能对应上的数据
      *    left/right outer join:左(右)外连接--->
      *         返回左(右)表所有数据,右(左)表能对应上的话显示,对应不上的话显示为null
      *    left/right full outer join
      *         返回左右两张表中都有的数据:左外连接+右外连接
      * 一张学生信息表stu,一张班级信息表class
      *     stu--->  stu_id  stu_name    cid
      *     class--> cid    cname
      * 现在要求查询以下信息:
      *     stu_id stu_name cname
      *  用SQL:
      *     select
      *         s.stu_id,
      *         s.stu_name,
      *         c.cname
      *     from stu s
      *     left join class c on s.cid = c.cid
      * @param sc
      */
    def  transformationJOIN_08(sc:SparkContext): Unit = {
        val stu = List(
            "1  郑祥楷 1",
            "2  王佳豪 1",
            "3  刘鹰 2",
            "4  宋志华 3",
            "5  刘帆 4",
            "6  OLDLi 5"
        )
        val cls = List(
            "1 1807bd-bj",
            "2 1807bd-sz",
            "3 1807bd-wh",
            "4 1807bd-xa",
            "7 1805bd-bj"
        )
        val stuRDD = sc.parallelize(stu)
        val clsRDD = sc.parallelize(cls)
        val cid2STURDD:RDD[(String, String)] = stuRDD.map{case line => {
            val fields = line.split("\\s+")
            (fields(2), line)
        }}
        val cid2ClassRDD:RDD[(String, String)] = clsRDD.map{case line => {
            val fields = line.split("\\s+")
            (fields(0), fields(1))
        }}
        //两张表关联--join
        println("---------inner join-------------")
        val cid2InfoRDD:RDD[(String, (String, String))] = cid2STURDD.join(cid2ClassRDD)
        cid2InfoRDD.foreach(println)
        println("---------left join-------------")
        val cid2LefJoinRDD:RDD[(String, (String, Option[String]))] = cid2STURDD.leftOuterJoin(cid2ClassRDD)
        cid2LefJoinRDD.foreach(println)
        println("---------full join-------------")
        val cid2FullJoinRDD:RDD[(String, (Option[String], Option[String]))] = cid2STURDD.fullOuterJoin(cid2ClassRDD)
        cid2FullJoinRDD.foreach(println)
    }
    /**
      *
      * 一张表,student表
      *     stu_id  stu_name   class_id
      *  统计每个班级的人数
      *  相同的统计下,reduceByKey要比groupByKey效率高,因为在map操作完毕之后发到reducer之前
      *  需要先进行一次本地的预聚合,每一个mapper(对应的partition)执行一次预聚合
      * @param sc
      */
    def  transformationRBK_07(sc:SparkContext): Unit = {
        val list = List(
            "1  郑祥楷 1807bd-bj",
            "2  王佳豪 1807bd-bj",
            "3  刘鹰 1807bd-sz",
            "4  宋志华 1807bd-wh",
            "5  刘帆 1807bd-xa",
            "6  何昱 1807bd-xa"
        )
        val listRDD = sc.parallelize(list)
        println("分区个数:" + listRDD.getNumPartitions)
        val cid2Count = listRDD.map { case (line) => {
            val fields = line.split("\\s+")
            (fields(2), 1)
        }}
        cid2Count.reduceByKey(_+_).foreach(println)
    }
    /**
      * groupByKey:对数组进行 group by key操作 慎用
      * 一张表,student表
      *     stu_id  stu_name   class_id
      * 将学生按照班级进行分组,把每一个班级的学生整合到一起
      * 建议groupBykey在实践开发过程中,能不用就不用,主要是因为groupByKey的效率低,
      * 因为有大量的数据在网络中传输,而且还没有进行本地的预处理
      * 我可以使用reduceByKey或者aggregateByKey或者combineByKey去代替这个groupByKey
      */
    def  transformationGBK_06(sc:SparkContext): Unit = {
        val list = List(
            "1  郑祥楷 1807bd-bj",
            "2  王佳豪 1807bd-bj",
            "3  刘鹰 1807bd-sz",
            "4  宋志华 1807bd-wh",
            "5  刘帆 1807bd-xa",
            "6  何昱 1807bd-xa"
        )
        val listRDD = sc.parallelize(list)
        println("分区个数:" + listRDD.getNumPartitions)
        val cid2StuInfo = listRDD.map { case (line) => {
            val fields = line.split("\\s+")

            (fields(2), line)
        }}
        val gbkRDD = cid2StuInfo.groupByKey()
        gbkRDD.foreach{case (cid, stus) => {
            println(s"$cid ---> ${stus} ----> ${stus.size}")
        }}
    }
    /**
      * union:返回一个新的数据集,由原数据集和参数联合而成
      *   该union操作和sql中的union all操作一模一样
      */
    def  transformationUnion_05(sc:SparkContext): Unit = {
        val list1 = List(1, 2, 3, 4, 5)
        val list2 = List(6, 5, 4, 7, 9)
        val lRDD1 = sc.parallelize(list1)
        val lRDD2 = sc.parallelize(list2)

        lRDD1.union(lRDD2).foreach(t => print(t + " "))
    }

    /**
      * sample:根据给定的随机种子seed,随机抽样出数量为frac的数据
      * 参数:
      *     withReplacement:true或者false
      *         true:代表有放回的抽样
      *         false:代表无放回的抽样
      *     fraction:抽取样本空间占总体的比例(分数的形式传入)
      *         without replacement: 0 <= fraction <= 1
      *         with replacement: fraction >= 0
      *     seed:随机数生成器
      *     new Random().nextInt(10)
      *     注意:我们使用sample算子不能保证提供集合大小就恰巧是rdd.size * fraction,
      * 结果大小会在前面数字上下浮动
      *   sample算子,在我们后面学习spark调优(dataskew)的时候,可以用的到
      */
    def transformationSample_04(sc:SparkContext): Unit = {
        val list = 0 to 99999
        val listRDD = sc.parallelize(list)
        val sampleRDD = listRDD.sample(false, 0.05)
        println(s"sampleRDD的集合大小:${sampleRDD.count()}")
    }

    /**
      * filter:过滤出集合中的奇数(even)
      */
    def transformationFilter_03(list:List[Int], sc:SparkContext): Unit = {
        val listRDD = sc.parallelize(list    )
        val filterRDD = listRDD.filter(num => {
//            1 / 0
            num % 2 == 0
        })
        filterRDD.foreach(println)
    }

    /**
      * 3、flatMap:将行拆分为单词
      *     和map算子类似,只不过呢,rdd形态转化对应为one-to-many
      * @param sc
      */
    def transformationFlatMap_02(sc:SparkContext): Unit = {
        val list = List(
            "lu jia hui",
            "chen zhi xiang"
        )
        val listRDD = sc.parallelize(list)
        listRDD.flatMap(line => line.split("\\s+")).foreach(println)
    }
    /**
      * 1、map:将集合中每个元素乘以7
      *   map是最常用的转换算子之一,将原rdd的形态,转化为另外一种形态,
      *   需要注意的是这种转换是one-to-one
      * @param sc
      */
    def transformationMap_01(list:List[Int], sc:SparkContext): Unit = {
        val bs = 7
        val listRDD = sc.parallelize(list)
        val retRDD = listRDD.map(num => num * bs)
        retRDD.foreach(println)
    }
}

常用的action算子练习:

/*
    1、reduce:
        执行reduce操作,返回值是一个标量
    2、collect: 慎用
        将数据从集群中的worker上拉取到dirver中,所以在使用的过程中药慎用,意外拉取数据过大造成driver内存溢出OOM(OutOfMemory)
        NPE(NullPointerException)
        所以在使用的使用,尽量使用take,或者进行filter再拉取
    3、count:返回当前rdd中有多少条记录
        select count(*) from tbl;
    4、take:take(n)
        获取rdd中前n条记录
        如果rdd数据有序,可以通过take(n)求TopN
    5、first:take(1)
        获取rdd中的第一条记录
    6、saveAsTextFile:
        将rdd中的数据保存到文件系统中
    7、countByKey:和reduceByKey效果相同,但reduceByKey是一个Transformation
        统计相同可以出现的次数,返回值为Map[String, Long]
    8、foreach:略 遍历
 */
object _04SparkActionOps extends App {
//    Logger.getLogger("org.apache.hadoop").setLevel(Level.WARN)
//    Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
//    Logger.getLogger("org.project-spark").setLevel(Level.WARN)
    val conf = new SparkConf()
        .setMaster("local[2]")
        .setAppName(s"${_03SparkTransformationOps.getClass.getSimpleName}")
    val sc = new SparkContext(conf)

    val list = List(
        "5  刘帆 1807bd-xa",
        "2  王佳豪 1807bd-bj",
        "8  邢宏 1807bd-xa",
        "3  刘鹰 1807bd-sz",
        "4  宋志华 1807bd-wh",
        "1  郑祥楷 1807bd-bj",
        "7  张雨 1807bd-bj",
        "6  何昱 1807bd-xa"
    )

    val listRDD: RDD[String] = sc.parallelize(list)
    val list1 = 1 to 9
    val listRDD1 = sc.parallelize(list1)
    //reduce:统计rdd中的和
    val 和 = listRDD1.reduce((v1, v2) => v1 + v2)
    println()
    //2 count
    println(s"listRDD1的条数:${listRDD1.count()}")
    // 3 take 获取rdd中的n条记录
    val take: Array[Int] = listRDD1.take(3)
    println(take.mkString("[", ",", "]"))
    private val first: Int = listRDD1.first()
    println(first)
    val top3:Array[Int] = listRDD1.takeOrdered(3)(new Ordering[Int]{
        override def compare(x: Int, y: Int) = {
            y.compareTo(x)
        }
    })
    println(top3.mkString("[", ",", "]"))
    println("---------------saveAsTextFile---------------------")
//    listRDD.saveAsTextFile("E:/data/spark/out")
    listRDD.saveAsObjectFile("E:/data/spark/out1")
    println("---------------saveAsHadoop/SequenceFile---------------------")
    val cid2InfoRDD:RDD[(String, String)] = listRDD.map{case line => {
        val fields = line.split("\\s+")
        (fields(2), line)
    }}

    /**
      * saveAsHadoopFile()  ---> org.apache.hadoop.mapred.OutputFormat 借口
      * saveAsNewAPIHadoopFile() --> org.apache.hadoop.mapreduce.OutputFormat 抽象类
      * job.setOutputFormat(xxx.classs)
      *
      *
      *  path: String   --->将rdd数据存储的目的地址
         keyClass: Class[_], mr中输出记录包含key和value,需要指定对应的class
         valueClass: Class[_],
         job.setOutputKeyClass()
         job.setOutputValueClass()
         outputFormatClass: Class[_ <: NewOutputFormat[_, _]] 指定对应的Format来完成数据格式化输出
         TextOutputFormat
      */
    cid2InfoRDD.saveAsNewAPIHadoopFile(
        "E:/data/spark/out2",
        classOf[Text],
        classOf[Text],
        classOf[TextOutputFormat[Text, Text]]
    )

    //countByKey作用就是记录每一个key出现的次数,作用同reduceByKey(_+_)
    private val cid2Count: collection.Map[String, Long] = cid2InfoRDD.countByKey()

    for((k, v) <- cid2Count) {
        println(k + "---" + v)
    }

    sc.stop()
}


在这些基本的了解之后,给大家来两个高级调优的聚合算子的用过:

combineByKey

combineByKey 与aggregateByKey类似,都调用了combineByKeyWithClassTag,在aggregateByKey中的

第一个参数是zero value,此函数的第一个参数需要提供一个初始化函数,通过第一个函数完成分区内计算,通过第二个函数完成分区间计算:

createCombiner:V=>C turns V to C ,C is an element list;

mergeValue:(C,V)=>C merge V to C by appending V to the end of the list.

mergeCombiners:(C,C)=>C to combine two Cs into one.

def combineByKeyC:RDD[(K,C)]

def combineByKey[C](createCombiner:V=>C,mergeValue:(C,V)=>C,mergeCombiners:(C,C)=>C,partitioner:Partitioner,mapSideCombine:Boolean = true,serializer:Serializer = null):RDD[(K,C)]

在这里插入图片描述
练习:

/**
  * 使用combineByKey和aggregateByKey来模拟groupByKey和reduceByKey
  * 不管combineByKey还是aggregateByKey底层都是使用combineByKeyWithClassTag来实现的
  *
  * 这两个有啥区别?
  *
  */
object _02SparkTransformationOps {
    def main(args: Array[String]): Unit = {
        Logger.getLogger("org.apache.hadoop").setLevel(Level.WARN)
        Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
        Logger.getLogger("org.project-spark").setLevel(Level.WARN)
        val conf = new SparkConf()
            .setMaster("local[2]")
            .setAppName(s"${_02SparkTransformationOps.getClass.getSimpleName}")
        val sc = new SparkContext(conf)

        val list = List(
            "5  刘帆 1807bd-xa",
            "2  王佳豪 1807bd-bj",
            "8  邢宏 1807bd-xa",
            "3  刘鹰 1807bd-sz",
            "4  宋志华 1807bd-wh",
            "1  郑祥楷 1807bd-bj",
            "7  张雨 1807bd-bj",
            "6  何昱 1807bd-xa"
        )
//        cbk2rbk(sc, list)
        cbk2gbk(sc, list)

        sc.stop()
    }

    def cbk2gbk(sc:SparkContext, list:List[String]): Unit = {
        val listRDD = sc.parallelize(list)
        println("分区个数:" + listRDD.getNumPartitions)
        val cid2Info:RDD[(String, String)] = listRDD.map { case (line) => {
            val fields = line.split("\\s+")
            (fields(2), line)
        }}

        val cbk2gbk:RDD[(String, ArrayBuffer[String])] = cid2Info.combineByKey(
            line => ArrayBuffer[String](line),
            (ab:ArrayBuffer[String], line:String) => {
                ab.append(line)
                ab
            },
            (ab1:ArrayBuffer[String], ab2:ArrayBuffer[String]) => {
                ab1.appendAll(ab2)
                ab1
            }
        )
        cbk2gbk.foreach(println)
    }
    /**
      * 使用combineByKey来模拟reduceByKey
      * @param sc
      * @param list
      */
    def cbk2rbk(sc:SparkContext, list:List[String]): Unit = {
        val listRDD = sc.parallelize(list)
        println("分区个数:" + listRDD.getNumPartitions)
        val cid2Info:RDD[(String, String)] = listRDD.map { case (line) => {
            val fields = line.split("\\s+")
            (fields(2), line)
        }}
        cid2Info.foreachPartition(patition => {
            patition.foreach(println)
        })
        val cid2Counts = cid2Info.combineByKey(createCombiner, mergeValue, mergeCombiners)
        cid2Counts.foreach(println)
    }

    /**
      * V是被聚合的rdd中k-v键值对中的value的类型
      * C是经过聚合操作之后又v转化成的类型
      * 当前方法,rdd中一个key,在一个分区中,只会创建/调用一次,做数据类型初始化
      * 比如:hello这个key,在partition0和partition1中都有出现
      * 在partition0中聚合的时候createCombiner之被调用一次
      *
      * @return
      */
    def createCombiner(line:String):Int = {
        val fields = line.split("\\s+")
        println("-----createCombiner---> " + fields(2))
        1
    }

    /**
      * scala代码,求1+。。。+10
      * var sum = 0
      * for(i <- 1 to 10) {
      *     sum = sum + i
      * }
      * println(sum)
      * mergeValue就类似于上面的代码
      * 合并同一个分区中,相同key对应的value数据,在一个分区中,相同的key会被调用多次
      * @return
      */
    def mergeValue(sum:Int, line:String):Int = {
        val fields = line.split("\\s+")
        println(">>>-----mergeValue---> " + fields(2))
        sum + 1
    }

    /**
      * 相同key对应分区间的数据进行合并
      * @return
      */
    def mergeCombiners(sum1:Int, sum2:Int):Int = {
        println(">>>-----mergeCombiners--->>> sum1: " + sum1 + "--->sum2: " + sum2)
        sum1 + sum2
    }
}


aggregateByKey

aggregateByKey 和reduceByKey类似,但更具灵活性,可以自定义在分区内和分区间的聚合操作,有三种调用方式:

def aggregateByKeyU:ClassTag(seqOp:(U,V)=>U,comb:(U,U)=>U):RDD[K,U]

seqOp:(U,V)=>U 和zeroValue 完成分区内计算,分区间计算通过comb:(U,U)=>U完成。

def aggregateByKeyU:ClassTag(seqOp:(U,V)=>U,comb:(U,U)=>U):RDD[K,U]

def aggregateByKeyU:ClassTag(seqOp:(U,V)=>U,comb:(U,U)=>U):RDD[K,U]

在这里插入图片描述
练习:

/**
  * 使用combineByKey和aggregateByKey来模拟groupByKey和reduceByKey
  * 不管combineByKey还是aggregateByKey底层都是使用combineByKeyWithClassTag来实现的
  *
  * 这两个有啥区别?
  *
  * 1、本质上combineByKey和aggregateByKey都是通过combineByKeyWithClassTag来实现的,只不过实现的细节或者方式不大一样。
  * 2、combineByKey更适合做聚合前后数据类型不一样的操作,aggregateByKey更适合做聚合前后数据类型一致的操作
  *  因为我们可以在combineByKey提供的第一个函数中完成比较复杂的初始化操作,而aggregateByKey的第一个参数是一个值
  * 3、我们使用时最简单的版本,而在实际生产过程中,一般都是相对比较复杂的版本,还有其它参数的,比如partitioner,
  * mapSideCombine。
  *     partitioner制定并行度,
  *     mapSideCombine控制是否执行本地预聚合
  *
  */
object _03SparkTransformationOps {
    def main(args: Array[String]): Unit = {
        Logger.getLogger("org.apache.hadoop").setLevel(Level.WARN)
        Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
        Logger.getLogger("org.project-spark").setLevel(Level.WARN)
        val conf = new SparkConf()
            .setMaster("local[2]")
            .setAppName(s"${_03SparkTransformationOps.getClass.getSimpleName}")
        val sc = new SparkContext(conf)

        val list = List(
            "5  刘帆 1807bd-xa",
            "2  王佳豪 1807bd-bj",
            "8  邢宏 1807bd-xa",
            "3  刘鹰 1807bd-sz",
            "4  宋志华 1807bd-wh",
            "1  郑祥楷 1807bd-bj",
            "7  张雨 1807bd-bj",
            "6  何昱 1807bd-xa"
        )
//        abk2rbk(sc, list)
        abk2gbk(sc, list)

        sc.stop()
    }

    def abk2gbk(sc:SparkContext, list:List[String]): Unit = {
        val listRDD = sc.parallelize(list)
        println("分区个数:" + listRDD.getNumPartitions)
        val cid2Info:RDD[(String, String)] = listRDD.map { case (line) => {
            val fields = line.split("\\s+")
            (fields(2), line)
        }}

        val abk2gbk:RDD[(String, ArrayBuffer[String])] = cid2Info.aggregateByKey(ArrayBuffer[String]())(
            (ab:ArrayBuffer[String], line:String) => {
                ab.append(line)
                ab
            },
            (ab1:ArrayBuffer[String], ab2:ArrayBuffer[String]) => {
                ab1.appendAll(ab2)
                ab1
            }
        )
//        abk2gbk.foreach(println)
    }

    /**
      * 使用aggregateByKey来模拟reduceByKey
      * @param sc
      * @param list
      */
    def abk2rbk(sc:SparkContext, list:List[String]): Unit = {
        val listRDD = sc.parallelize(list)
        println("分区个数:" + listRDD.getNumPartitions)
        val cid2Info:RDD[(String, String)] = listRDD.map { case (line) => {
            val fields = line.split("\\s+")
            (fields(2), line)
        }}

        val cid2rbkRDD:RDD[(String, Int)] = cid2Info.aggregateByKey(0)(
            (sum:Int, line:String) => {
                sum + 1
            },
            (sum1:Int, sum2:Int) => {
                sum1 + sum2
            }
        )
        cid2rbkRDD.foreach(println)
    }

}



最后我们做一些练习巩固一下常用算子:

练习 1//通过并行化生成 rdd 
val rdd1 = sc.parallelize(List(5, 6, 4, 7, 3, 8, 2, 9, 1, 10)) 
//对 rdd1 里的每一个元素乘 2 然后排序 
val rdd2 = rdd1.map(_ * 2).sortBy(x => x, true) 
//过滤出大于等于十的元素 
val rdd3 = rdd2.filter(_ >= 10) 
//将元素以数组的方式在客户端显示
 rdd3.collect 
练习 2: 
val rdd1 = sc.parallelize(Array("a b c", "d e f", "h i j")) 
//将 rdd1 里面的每一个元素先切分在压平 
val rdd2 = rdd1.flatMap(_.split(' ')) 
rdd2.collect 
练习 3:
val rdd1 = sc.parallelize(List(5, 6, 4, 3)) 
val rdd2 = sc.parallelize(List(1, 2, 3, 4)) 
//求并集 val rdd3 = rdd1.union(rdd2) 
//求交集 val rdd4 = rdd1.intersection(rdd2) 
//去重 rdd3.distinct.collect rdd4.collect 
练习 4: 
val rdd1 = sc.parallelize(List(("tom", 1), ("jerry", 3), ("kitty", 2)))
 val rdd2 = sc.parallelize(List(("jerry", 2), ("tom", 1), ("shuke", 2))) 
 //求 jion
  val rdd3 = rdd1.join(rdd2) rdd3.collect 
  //求并集 
  val rdd4 = rdd1 union rdd2 
  //按 key 进行分组 
  rdd4.groupByKey rdd4.collect 
练习 5: 
val rdd1 = sc.parallelize(List(("tom", 1), ("tom", 2), ("jerry", 3), ("kitty", 2))) 
val rdd2 = sc.parallelize(List(("jerry", 2), ("tom", 1), ("shuke", 2))) //cogroup 
val rdd3 = rdd1.cogroup(rdd2) 
//注意 cogroup 与 groupByKey 的区别 
rdd3.collect 
练习 6: 
val rdd1 = sc.parallelize(List(1, 2, 3, 4, 5)) 
//reduce 聚合 
val rdd2 = rdd1.reduce(_ + _) rdd2.collect 
练习 7: 
val rdd1 = sc.parallelize(List(("tom", 1), ("jerry", 3), ("kitty", 2),  ("shuke", 1))) 
val rdd2 = sc.parallelize(List(("jerry", 2), ("tom", 3), ("shuke", 2), ("kitty", 5))) 
val rdd3 = rdd1.union(rdd2) 
//按 key 进行聚合 
val rdd4 = rdd3.reduceByKey(_ + _) rdd4.collect 
//按 value 的降序排序 val rdd5 = rdd4.map(t => (t._2, t._1)).sortByKey(false).map(t => (t._2, t._1)) rdd5.collect 

想要了解更多,访问下面的地址 http://homepage.cs.latrobe.edu.au/zhe/ZhenHeSparkRDDAPIExamples.html



拉钩网职位数据练习题

数据的sql文件 和txt文件,和习题答案练习代码我都已经为你们准备好了在我的github上:
https://github.com/chenjian-520/sparkStudent

下面是课后练习:答案我已经放到github上面,有兴趣的朋友可以看看:
(数据文件我也放到了github上)


数据样式:
1 Java高级 北苑 信息安全,大数据,架构 闲徕互娱 20k-40k 本科 经验5-10年 游戏 不需要融资

字段:
id job addr tag company salary edu exp type level

中文解释
id 工作岗位 地址 标签 公司 薪资 学历 经验 类型 融资级别

需求:

1、求出每个不同地点的招聘数量,输出需求量最大的10个地方,以及岗位需求量

#2、求出使用学历和经验作为联合分组条件,那种搭配的需求是最多的

3、求出大数据类工作(job字段包含"大数据",“hadoop”,"spark"就算大数据类工作)岗位对学历的要求,不同学历的需求量和占比

#4、求出不同融资级别的公司,在招聘大数据类工作岗位时,在学历和经验一致的条件下,薪资会高出多少。

	本科		1-3年	A轮-B轮		2000-3000
	本科		1-3年	B轮-C轮		2100-4500
	.......
	本科		3-5年	A轮-B轮		3000-6000
	本科		3-5年	B轮-C轮		4000-5000
	.....
	研究生		1-3年	A轮-B轮		4000-5000
	......

	(4000-5000)  ------  (平均最少薪资-平均最大薪资)

5、求出不同标签的公司数量和招聘数量(只输出招聘需求最大的50个标签)
公司数量和招聘数量,由高到低排序,如果公司数量相等,按照招聘数量的降序排列

结果样式:
高级,5232,1414
金融,4865,995
资深,3717,1080
Java,3531,1154
大数据,3375,831
........

在这里插入图片描述
下次我们还要来学习哟!!!
记得点赞加关注!!! 不迷路 !!!
人活着真累:上车得排队,爱你又受罪,吃饭没香味,喝酒容易醉,挣钱得交税!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蛋蛋淡淡定

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值