一:准备

1.源数据

  

2.上传数据

  

二:TopN程序编码

1.程序

 package com.ibeifeng.bigdata.spark.core

 import java.util.concurrent.ThreadLocalRandom

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

 /**
* 分组TopN:按照第一个字段分组;同一组中,按照第二个字段进行排序;每一组中,获取出现最多的前K个数据。
* Created by ibf on 01/15.
*/
object GroupedTopN {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setMaster("local[*]")
.setAppName("grouped-topn")
//.set("spark.eventLog.enabled", "true")
//.set("spark.eventLog.dir", "hdfs://hadoop-senior01:8020/spark-history") val sc = SparkContext.getOrCreate(conf) // ==========具体代码逻辑========================
// 原始数据存储的路径, 需要自己上传
val path = "/user/beifeng/spark/groupedtopk/groupsort.txt"
val K = 3 // 构建rdd
val rdd = sc.textFile(path) // rdd操作
val word2CountRDD = rdd
.filter((line: String) => {
// 过滤空字符串,所以非空的返回true
!line.isEmpty
})
.map(line => {
// 按照空格分隔字段
val arr = line.split(" ")
// 将数据转换为二元组
(arr(0), arr(1).toInt)
}) // 如果一个RDD被多次使用,该RDD需要进行缓存操作
word2CountRDD.cache() // 直接使用groupByKey函数进行统计,这种方式存在OOM的情况
/*
val resultRDD = word2CountRDD
.groupByKey() // 按照第一个字段进行分组
.map(tuple => {
// 同一组的数据中获取前K个元素
// 获取对应分组
val word = tuple._1
// 获取前K个元素(最大的k个元素), list默认排序是升序, 所以采用takeRight从后往前获取K个元素(此时的K个元素就是最大的K个元素); 最后对K个元素进行反转,最终结果元素是从大到小排序的
val topk = tuple._2.toList.sorted.takeRight(K).reverse
// 返回结果
(word, topk)
})
*/ /*
* groupByKey存在OOM异常
* 解决方案:采用两阶段聚合操作
* 两阶段聚合可以解决的一些常见:
* 1. 聚合操作中存储的OOM异常
* 2. 聚合操作中存在的数据倾斜问题
* 聚合操作:分区、排序、reduceByKey.....
* */
val random = ThreadLocalRandom.current()
val resultRDD2 = word2CountRDD
.map(tuple => {
// 第一阶段第一步:在key前加一个随机数
((random.nextInt(100), tuple._1), tuple._2)
})
.groupByKey() // 第一阶段的第二步:按照修改后的key进行聚合操作
.flatMap(tuple => {
// 第一阶段的第三步:对一组value进行聚合操作
// 获取对应分组
val word = tuple._1._2
// 获取前K个
val topk = tuple._2.toList.sorted.takeRight(K).reverse
// 返回结果
topk.map(count => (word, count))
})
.groupByKey() // 第二阶段第一步:按照原本的key进行聚合操作
.map(tuple => {
// 第二阶段第二步: 获取前k个元素
val word = tuple._1
val topk = tuple._2.toList.sorted.takeRight(K).reverse
// 返回结果
(word, topk)
}) // 结果输出
resultRDD2.foreach(println)
/*
resultRDD2.foreachPartition(iter => {
// foreachPartition该函数常用于将RDD的数据输出到第三方的数据存储系统中,比如:redis、mongoDB
/*
* 1. 创建连接
* 2. 对iter进行迭代,进行数据输出
* 3. 关闭连接
* */
iter.foreach(println)
})
*/ // 如果RDD有cache,需要去除cache
word2CountRDD.unpersist() // ==========具体代码逻辑======================== sc.stop()
}
}

2.结果

  

3.注意点

  Spark中不支持二次排序,如果想实现二次排序,需要根据业务的执行逻辑使用两阶段聚合来进行操作

二:优化

1.两阶段聚合

  

020 Spark中分组后的TopN,以及Spark的优化(重点)的更多相关文章

  1. 如何在spark中读写cassandra数据 ---- 分布式计算框架spark学习之六

    由于预处理的数据都存储在cassandra里面,所以想要用spark进行数据分析的话,需要读取cassandra数据,并把分析结果也一并存回到cassandra:因此需要研究一下spark如何读写ca ...

  2. Spark中的编程模型

    1. Spark中的基本概念 Application:基于Spark的用户程序,包含了一个driver program和集群中多个executor. Driver Program:运行Applicat ...

  3. Spark中的Phoenix Dynamic Columns

    代码及使用示例:https://github.com/wlu-mstr/spark-phoenix-dynamic phoenix dynamic columns HBase的数据模型是动态的,很多系 ...

  4. MySQL 排名、分组后组内排名、取各组的前几名 及排名后更新插入数据表中

    一.排名 /*普通排名:从1开始,顺序往下排*/ AS rank ) r ORDER BY score; /*并列排名:相同的值是相同的排名*/ SELECT cs.* , CASE WHEN @p= ...

  5. Spark:求出分组内的TopN

    制作测试数据源: c1 85 c2 77 c3 88 c1 22 c1 66 c3 95 c3 54 c2 91 c2 66 c1 54 c1 65 c2 41 c4 65 spark scala实现 ...

  6. sql-实现select取行号、分组后在分组内排序、每个分组中的前n条数据

    表结构设计: 实现select取行号 sql局部变量的2种方式 set @name='cm3333f'; select @id:=1; 区别:set 可以用=号赋值,而select 不行,必须使用:= ...

  7. [MySQL]MySQL数据库中如何查询分组后每组中的最后一条记录?

    原文地址:https://codedefault.com/s/how-can-i-retrieve-the-last-record-in-each-group-mysql 问题描述 比如,在MySQL ...

  8. SQL获取分组后取某字段最大一条记录(求每个类别中最大的值的列表)

    获取分组后取某字段最大一条记录 方法一:(效率最高) select * from test as a where typeindex = (select max(b.typeindex) from t ...

  9. 024 关于spark中日志分析案例

    1.四个需求 需求一:求contentsize的平均值.最小值.最大值 需求二:请各个不同返回值的出现的数据 ===> wordCount程序 需求三:获取访问次数超过N次的IP地址 需求四:获 ...

随机推荐

  1. Linux - 压缩

    tar  tar zxvpf gz.tar.gz # 解包tar.gz 不指定目录则全解压; -C 放到指定目录 包中的目录: -o 是强制覆盖: tar zcvpf /$path/gz.tar.gz ...

  2. UE4的AI学习(1)——基本概念

    AI学习当中,不学习行为树基本概念就不能明白具体实例中的操作意义,但是没有经过具体实例实验,又觉得基本概念抽象难以理解.建议先泛读(1)(2)后再对具体的细节进行死磕,能较深的理解行为树的具体概念.第 ...

  3. 第4月第10天 iOS项目 mvc

    1. 一个uiviewcontroller发送网络请求,解析数据后放在数组里.如果是多个网络请求,就要多个成员变量存储.那是不是可以单独出一个model来解析数据,存储数据呢. 如果有一个Reques ...

  4. undefined reference问题总结

    http://ticktick.blog.51cto.com/823160/431329 http://blog.sina.com.cn/s/blog_605f5b4f01018xeu.html ht ...

  5. ServiceMesh了解一下

    http://www.servicemesh.cn/?/article/70 https://zhuanlan.zhihu.com/p/33196550

  6. JavaScript学习 - 基础(三) - 运算符

    js运算符 1.算数运算符 包括 加(+) .减-() .乘(*).除(/).余数(%) 减号 还可以表示为 负号 例如: -1,-3 加号 还可以用于字符串拼接 例如: 'a' + 'b' = 'a ...

  7. [转]python 装饰器

    以前你有没有这样一段经历:很久之前你写过一个函数,现在你突然有了个想法就是你想看看,以前那个函数在你数据集上的运行时间是多少,这时候你可以修改之前代码为它加上计时的功能,但是这样的话是不是还要大体读读 ...

  8. SpringMVC——SpringMVC简介

    Spring web mvc 和Struts2 都属于表现层的框架,它是Spring 框架的一部分,我们可以从Spring 的整体结构中看得出来:

  9. linux挂载硬盘以及卸载硬盘

    1.在vmware添加硬盘 2.输入fdisk -l 查看新增加的硬盘 3.分区初始化 4.指定文件系统 5.修改fstab文件 fstab: 6.刷新验证 mount -a 挂载定义在/etc/fs ...

  10. 一份通过IPC$和lpk.dll感染方式的病毒分析报告

    样本来自52pojie论坛,从事过两年渗透开始学病毒分析后看到IPC$真是再熟悉不过. 1.样本概况 1.1 样本信息 病毒名称:3601.exe MD5值:96043b8dcc7a977b16a28 ...