spark编程实战(二) —— 中位数

最近正在看《Spark大数据处理:技术、应用与性能优化》这本书,然后对于最后一章的编程实战比较感兴趣。但是上面写的算法个人觉得还不是很简洁,无法体现出scala的优点,所以稍作了一些修改,仅供参考。

设计思路
海量数据求中位数有很多解决方案。 假设海量数据已经预先排序本例的解决方案为:将
整个数据空间划分为K个桶。 第一轮,在mapPartition阶段先将每个分区内的数据划分为K个
桶,统计桶中的数据量,然后通过reduceByKey聚集整个RDD每个桶中的数据量。 第二轮,
根据桶统计的结果和总的数据量,可以判读数据落在哪个桶里,以及中位数的偏移量
(offset)。 针对这个桶的数据进行排序或者采用Top K的方式,获取到偏移为offset的数
据。

代码实现:

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

object Wedian {


  def main(args: Array[String]): Unit = {

    val conf = new SparkConf()
      .setAppName("Wedian")
      .setMaster("local")

    val sc = new SparkContext(conf)
    //读取数据
    val dataRDD = sc.textFile("./data/num.txt")
      .flatMap(_.split(" "))
      .map(x => x.toInt)
    //将一定范围内的数据分区,比如数据1,2,3,4,5,6 如果num/4会将1,2,3放入一个分区,4放入一个分区,5,6放入一个分区。相当于将归并,减少计算量,切记不能用求余,目的为了保证数据的有序性。
    val mappedDataRDD = dataRDD.map(num => (num / 4, num))
      .sortByKey()
    //统计每个分区元素个数
    val countRDD = dataRDD.map(num => (num / 4, 1))
      .reduceByKey((a, b) => (a + b)).sortByKey()

    //将RDD转换成map形式,用于后续计算
    val data_count = countRDD.collectAsMap()
    //计算元素总个数
    val sum = data_count.map(s => s._2).sum
    
    //中位数所在分区的末尾元素的偏移量
    var temp = 0
    //中位数前一个分区的末尾元素的偏移量
    var temp_1 = 0
    //所处在第几个分区
    var index = 0
    //中位数的偏移量
    var mid = 0
    //计算中位数在整个元素的位置
    if (sum % 2 != 0) mid = sum / 2 + 1 else mid = sum / 2
    
    //分区总个数
    val count = countRDD.count()

    var flag = 1
    //scala中没有break语句,所以利用守卫跳出循环
    for (i <- 0 to count.toInt - 1 if flag == 1) {
      temp = temp + data_count(i)
      temp_1 = temp - data_count(i)
      if (mid <= temp) {
        index = i
        flag = 0
      }
    }
    
    println(mid +" "+ index +" "+temp+" "+temp_1)
    //计算中位数在当前分区的偏移量
    val offset = mid - temp_1
    //利用过滤将这个分区内的所有数取出来,将中位数以前的该分区内的所有数取出来,再取最后一个数既是中位数
    val result = mappedDataRDD.filter(x => x._1 == index).takeOrdered(offset)

    println(result(offset-1)._2)
    
    sc.stop()
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

BigCabbageFy

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

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

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

打赏作者

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

抵扣说明:

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

余额充值