Spark-Core分组求TOPN的六种不同的实现方式

案例:计算学科最受欢迎老师TopN

1.需求:根据网站的行为日志,统计每个学科最受欢迎老师的TopN,即按照学科分组,在每一个组内进行排序

2. 样例数据:

http://bigdata.51doit.cn/laozhang

http://bigdata.51doit.cn/laozhang

http://bigdata.51doit.cn/laozhao

http://bigdata.51doit.cn/laozhao

http://bigdata.51doit.cn/laozhao

http://bigdata.51doit.cn/laozhao

http://bigdata.51doit.cn/laozhao

http://bigdata.51doit.cn/laoduan

http://bigdata.51doit.cn/laoduan

http://javaee.51doit.cn/xiaozhang

http://javaee.51doit.cn/xiaozhang

http://javaee.51doit.cn/laowang

http://javaee.51doit.cn/laowang

http://javaee.51doit.cn/laowang

 

数据格式:http://学科.51doit.cn/老师名称

3.六种不同的实现方式:

3.1 第一种方法:调用groupBy按照学科进行分组,然后将value对应的迭代器toList,将数据全部加载到内存中,然后在调用List的sortBy方法进行排序,然后再调用take取TopN

package com.zxx.spark.day06

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

/**
 * 第一种方法是将迭代器中的数据都收集到内存中然后在内存中进行排序,
 * 这种方法只针对于少量数据适合都加载到内存中,
 * 如果是海量数据则有可能出现内存溢出的问题
 */
object FavoriteTeacherDemo1 {
  def main(args: Array[String]): Unit = {
    //求每一学科最受欢迎的老师TopN
    //先创建SparkContext和集群建立链接
    val conf: SparkConf = new SparkConf().setAppName(this.getClass.getName)
    //添加一个判断,判断是否设置为集群或是,还是本地模式
    val flag: Boolean = args(0).toBoolean
    if (flag) {
      conf.setMaster("local[*]")
    }
    val sc: SparkContext = new SparkContext(conf)
    //创建RDD
    val rdd: RDD[String] = sc.textFile(args(1))
    //    http: / / bigdata.51doit.cn/laozhang
    //将读取到的数据进行切割和处理
    val subjectAndTeacherOne: RDD[((String, String), Int)] = rdd.map(e => {
      val sp: Array[String] = e.split("/")
      val url: Array[String] = sp(2).split("\\.")
      ((url(0), sp(3)), 1)
    })
    //subjectAndTeacherOne:((bigdata,laozhao),1), ((bigdata,laozhao),1), ((bigdata,laozhao),1),
    //将数据按照学科和老师进行联合作为key进行聚合
    val reduced: RDD[((String, String), Int)] = subjectAndTeacherOne.reduceByKey(_ + _)
    //然后在按照学科进行分组
    val grouped: RDD[(String, Iterable[((String, String), Int)])] = reduced.groupBy(_._1._1)
    //第一种方法是将迭代器中的数据都收集到内存中然后在内存中进行排序,这种方法只针对于少量数据适合都加载到内存中,如果是海量数据则有可能出现内存溢出的问题
    val res: RDD[(String, List[((String, String), Int)])] = grouped.mapValues(it => {
      val sorted: List[((String, String), Int)] = it.toList.sortBy(-_._2).take(3)
      sorted
    })
    println(res.collect().toBuffer)
  }
}

3.2 第二种方法:第二种方法是将每个学科过滤出来,然后单独对每一个学科进行排序,求topN,(不分组),这样就是将所有学科放在一个数组中,然后只对一个学科进行排序,这样就可以避免分组,减少一次shuffle,这样做虽然减少了一次shuffle,但是提交了3次job

package com.zxx.spark.day06

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD

/**
 * 第二种方式,是将每个学科过滤出来,然后单独对每一个学科进行求topN(底层调用了有界优先队列,不需要排序),利用for循环,遍历所有学科
 * 需要将要过滤的所有学科放在一个数组中
 */
object FavoriteTeacherDemo2 {
  def main(args: Array[String]): Unit = {
    //求每一学科最受欢迎的老师TopN
    //先创建SparkContext和集群建立链接
    val conf: SparkConf = new SparkConf().setAppName(this.getClass.getName)
    //添加一个判断,判断是否设置为集群或是,还是本地模式
    val flag: Boolean = args(0).
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值