Spark- 计算每个学科最受欢迎的老师
日志类型
测试数据
http://bigdata.myit.com/zhangsan
http://bigdata.myit.com/zhangsan
http://bigdata.myit.com/zhangsan
http://bigdata.myit.com/zhangsan
http://bigdata.myit.com/zhangsan
http://java.myit.com/lisi
http://java.myit.com/lisi
http://java.myit.com/lisi
计算每个学科最受欢迎的老师
package mypro
import java.net.URL
import org.apache.log4j.{Level, Logger}
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkContext, SparkConf}
/**
* Created by 166 on 2017/9/5.
*/
object FavTeacher {
def main(args: Array[String]) {
Logger.getLogger("org.apache.spark").setLevel(Level.OFF)
val conf = new SparkConf().setAppName(this.getClass.getName).setMaster("local[2]")//local[*]代表用多个线程跑,2代表用两个线程跑
val sc = new SparkContext(conf)
//读取数据
val lines: RDD[String] = sc.textFile(args())
//整理数据
val subjectAndTeacher:RDD[(String,String)]=lines.map(line=> {
val url = new URL(line)
val host = url.getHost
val subject = host.substring(, host.indexOf("."))
val teacher = url.getPath.substring() //去掉路径前面的"/"
(subject, teacher)
})
//聚合
val reduce = subjectAndTeacher.map((_,)).reduceByKey(_+_)
//println(reduce.collect().toBuffer)
//按学科分组
val grouped: RDD[(String, Iterable[((String, String), Int)])] = reduce.groupBy(_._1._1)//迭代器不能排序,需要将它变成List。
//二次排序
val result: RDD[(String, List[((String, String), Int)])] = grouped.mapValues(_.toList.sortBy(_._2).reverse.take())//用scala的语法,会把数据全部加载到内存后再做排序,数据量大的时候会有性能问题,内存溢出的问题,不建议这样使用,
val arr: Array[(String, List[((String, String), Int)])] = result.collect()
println(arr.toBuffer)
}
}
另种角度来实现,过滤多次提交
package com.rz.spark.base
import java.net.URL
import org.apache.log4j.{Level, Logger}
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
// 过滤多次提交
object GroupFavTeacher2 {
def main(args: Array[String]): Unit = {
Logger.getLogger("org.apache.spark").setLevel(Level.OFF)
val conf = new SparkConf().setMaster("local[2]").setAppName(this.getClass.getSimpleName)
val sc = new SparkContext(conf)
val topN = args(1).toInt
val subject = Array("bigdata","javaee","php")
// 读取数据
val lines: RDD[String] = sc.textFile(args(0))
// 整理数据 http://bigdata.myit.cn/laozhang
val subjectAndTeacher= lines.map(line => {
val url = new URL(line)
val host = url.getHost
val subject = host.substring(0, host.indexOf("."))
val teacher = url.getPath.substring(1) // 去掉前面的/
((subject, teacher),1)
})
// 聚合
val reduced = subjectAndTeacher.reduceByKey(_+_)
// 缓存到内存,因为多次过滤都是使用同一个rdd,缓存到内存可以提高反复使用的性能
val cache = reduced.cache()
for (sb <- subject){
val sorted = cache.filter(_._1._1 == sb).sortBy(_._2,false).take(topN)
println(sorted.toBuffer)
}
sc.stop()
}
}
使用自定义分区器将每个学科的数据shuffle到独自的分区,在分区内进行排序取topN
package com.rz.spark.base
import java.net.URL
import org.apache.log4j.{Level, Logger}
import org.apache.spark.rdd.RDD
import org.apache.spark.{Partitioner, SparkConf, SparkContext}
// 自定义分区器
import scala.collection.mutable
// 过滤多次提交
object GroupFavTeacher3 {
def main(args: Array[String]): Unit = {
Logger.getLogger("org.apache.spark").setLevel(Level.OFF)
val conf = new SparkConf().setMaster("local[2]").setAppName(this.getClass.getSimpleName)
val sc = new SparkContext(conf)
val topN = args().toInt
val subject = Array("bigdata","javaee","php")
// 读取数据
val lines: RDD[String] = sc.textFile(args())
// 整理数据 http://bigdata.myit.cn/laozhang
val subjectAndTeacher= lines.map(line => {
val url = new URL(line)
val host = url.getHost
val subject = host.substring(, host.indexOf("."))
val teacher = url.getPath.substring() // 去掉前面的/
((subject, teacher),)
})
// 聚合
val reduced = subjectAndTeacher.reduceByKey(_+_)
// 计算我们有多少学科
val sujects: Array[String] = reduced.map(_._1._1).distinct().collect()
// 自定义一个分区器,并且按照指定的分区器进行分区
val subjectPartitoner = new SubjectPartitoner(sujects)
// partitionBy按照指定的分区规则进行分区
val partitioned: RDD[((String, String), Int)] = reduced.partitionBy(subjectPartitoner)
// 如果一次拿出一个分区(可以操作一个分区的数据)
val sorted = partitioned.mapPartitions(it => {
// 将迭代器转成List,然后排序,再转成迭代器返回
it.toList.sortBy(_._2).reverse.take(topN).toIterator // 按数值排序
})
val result = sorted.collect()
println(result.toBuffer)
sc.stop()
}
// 自定义分区器
class SubjectPartitoner(sbs: Array[String]) extends Partitioner{
// 相当于主构造器(new 的时候会执行一次)
// 用于存放规则的一个map
val rules = new mutable.HashMap[String, Int]()
var i =
for (sb <- sbs){
rules.put(sb,i)
i +=
}
// 返回分区的数量(下一个RDD有多少分区)
override def numPartitions: Int = sbs.length
// 根据传入的key计算分区标号
// Key是一个无组(String, String)
override def getPartition(key: Any): Int ={
// 获取学科名称
val subject = key.asInstanceOf[(String, String)]._1
// 根据规则计算分区编号
rules(subject)
}
}
}
上面的方式会有多次shuffle,reduceByKey聚合数据的时候shuffle一次,使用自定义分区器重新对数据进行分析又shuffle了一次。我们可以尽可能的减少shuffle的过程,我们可以在reduceByKey的时候手动使用自定分区器进行分区,reduceByKey默认使用的是。HashPartitioner。
package com.rz.spark.base
import java.net.URL
import org.apache.log4j.{Level, Logger}
import org.apache.spark.rdd.RDD
import org.apache.spark.{Partitioner, SparkConf, SparkContext}
// 自定义分区器且减少shuffle
import scala.collection.mutable
// 过滤多次提交
object GroupFavTeacher4 {
def main(args: Array[String]): Unit = {
Logger.getLogger("org.apache.spark").setLevel(Level.OFF)
val conf = new SparkConf().setMaster("local[2]").setAppName(this.getClass.getSimpleName)
val sc = new SparkContext(conf)
val topN = args().toInt
val subject = Array("bigdata","javaee","php")
// 读取数据
val lines: RDD[String] = sc.textFile(args())
// 整理数据 http://bigdata.myit.cn/laozhang
val subjectAndTeacher= lines.map(line => {
val url = new URL(line)
val host = url.getHost
val subject = host.substring(, host.indexOf("."))
val teacher = url.getPath.substring() // 去掉前面的/
((subject, teacher),)
})
// 计算我们有多少学科
val sujects: Array[String] = subjectAndTeacher.map(_._1._1).distinct().collect()
// 自定义一个分区器,并且按照指定的分区器进行分区
val subjectPartitoner = new SubjectPartitoner2(sujects)
// 聚合,聚合是按照指定的分区器进行分区
// 该RDD一个分区内仅有一个学科的数据
val reduced: RDD[((String, String), Int)] = subjectAndTeacher.reduceByKey(subjectPartitoner,_+_)
// 如果一次拿出一个分区(可以操作一个分区的数据)
val sorted = reduced.mapPartitions(it => {
// 将迭代器转成List,然后排序,再转成迭代器返回
it.toList.sortBy(_._2).reverse.take(topN).toIterator // 按数值排序
})
// 收集数据
val result = sorted.collect()
println(result.toBuffer)
sc.stop()
}
// 自定义分区器
class SubjectPartitoner2(sbs: Array[String]) extends Partitioner{
// 相当于主构造器(new 的时候会执行一次)
// 用于存放规则的一个map
val rules = new mutable.HashMap[String, Int]()
var i =
for (sb <- sbs){
rules.put(sb,i)
i +=
}
// 返回分区的数量(下一个RDD有多少分区)
override def numPartitions: Int = sbs.length
// 根据传入的key计算分区标号
// Key是一个无组(String, String)
override def getPartition(key: Any): Int ={
// 获取学科名称
val subject = key.asInstanceOf[(String, String)]._1
// 根据规则计算分区编号
rules(subject)
}
}
}
Spark- 计算每个学科最受欢迎的老师的更多相关文章
- 大数据学习day22------spark05------1. 学科最受欢迎老师解法补充 2. 自定义排序 3. spark任务执行过程 4. SparkTask的分类 5. Task的序列化 6. Task的多线程问题
1. 学科最受欢迎老师解法补充 day21中该案例的解法四还有一个问题,就是当各个老师受欢迎度是一样的时候,其排序规则就处理不了,以下是对其优化的解法 实现方式五 FavoriteTeacher5 p ...
- 大数据学习day21-----spark04------1. 广播变量 2. RDD中的cache 3.RDD的checkpoint方法 4. 计算学科最受欢迎老师TopN
1. 广播变量 1.1 补充知识(来源:https://blog.csdn.net/huashetianzu/article/details/7821674) 之所以存在reduce side jo ...
- Spark计算模型
[TOC] Spark计算模型 Spark程序模型 一个经典的示例模型 SparkContext中的textFile函数从HDFS读取日志文件,输出变量file var file = sc.textF ...
- spark计算两个DataFrame的差集、交集、合集
spark 计算两个dataframe 的差集.交集.合集,只选择某一列来对比比较好.新建两个 dataframe : import org.apache.spark.{SparkConf, Spar ...
- 【原创 Hadoop&Spark 动手实践 7】Spark 计算引擎剖析与动手实践
[原创 Hadoop&Spark 动手实践 7]Spark计算引擎剖析与动手实践 目标: 1. 理解Spark计算引擎的理论知识 2. 动手实践更深入的理解Spark计算引擎的细节 3. 通过 ...
- 【Spark深入学习 -13】Spark计算引擎剖析
----本节内容------- 1.遗留问题解答 2.Spark核心概念 2.1 RDD及RDD操作 2.2 Transformation和Action 2.3 Spark程序架构 2.4 Spark ...
- Java进行spark计算
首先在Linux环境安装spark: 可以从如下地址下载最新版本的spark: https://spark.apache.org/downloads.html 这个下载下来后是个tgz的压缩包,解压后 ...
- 使用spark 计算netflow数据初探
spark是一个高性能的并发的计算平台,而netflow是一种一般来说数量级很大的数据.本文记录初步使用spark 计算netflow数据的大致过程. 本文包括以下过程: 1. spark环境的搭建 ...
- Spark计算均值
作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 转载请注明出处 用spark来快速计算分组的平均值,写法很便捷,话不多说上代码 object ColumnVal ...
随机推荐
- 计算机图形学(二)输出图元_6_OpenGL曲线函数_2_中点画圆算法
中点画圆算法 如同光栅画线算法,我们在每一个步中以单位间隔取样并确定离指定圆近期的像素位置.对于给定半径r和屏幕中心(xc,yc),能够先使用算法计算圆心在坐标原点(0, 0)的圆的像素 ...
- 利用NIO的Selector处理服务器-客户端模型
package NIOTEST; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocket ...
- iOS swift NSClassFromString将字符串转换成类名
在oc中将字符串转换成类名直接调用NSClassFromString("classname")即可,但是到了swift中变的麻烦多了 swift中如果要将字符串转换为类型需要以下几 ...
- Android View中getViewTreeObserver().addOnGlobalLayoutListener() (转)
转自:Android View中getViewTreeObserver().addOnGlobalLayoutListener() 我们知道在oncreate中View.getWidth和View.g ...
- ASP.NET动态网站制作(23)-- ADO.NET(2)
前言:这节课老师请高级班的E老师过来代课,还是接着老师讲的内容继续深入,修改了上节课老师写的部分代码. 内容: 1.数据库本质就是一个软件,这个软件帮助我们把数据有序地存储起来,当我们需要数据的时候帮 ...
- ASP.NET动态网站制作(21)-- C#(4)
前言:这节课是C#讲解的第四节课,主要围绕面向对象的三大特性展开.上节课已经把封装讲完了,这节课讲继承和多态. 内容: 1.继承:写程序的时候有些信息是公共的,可以将这些公共的信息写在父类里,增强代码 ...
- Idea 远程调试jenkins 项目
1.Jenkins配置 jenkins 服务启动时 需要在jvm启动项里加入如下代码: -Xdebug -Xrunjdwp:transport=dt_socket,suspend=n,server=y ...
- C#通过代码彻底结束桌面进程explorer,解决自动重启问题
C# 通过代码 Process.Kill 方法杀死桌面进程后,会自动重启 其实可以通过 Taskkill 指令结束桌面进程, 在命令行查看 taskkill 帮助, TASKKILL [/S syst ...
- OpenCV玩耍(一)批量resize一个文件夹里的所有图像
鉴于用caffe做实验的时候,里面牵扯到一个问题是必须将训练集和测试集都转成256*256的图像,而官网给出的代码又不会用,所以我用opencv转了.其实opencv只转一幅图会很简单,关键在于“批量 ...
- 九度OJ 1350:二叉树的深度 (二叉树)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:1044 解决:614 题目描述: 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长 ...