1)map操作
/**
* map(func):返回一个新的分布式数据集,由每个原元素经过func函数转换后组成
* 将原始集合中的每一个元素*7
* map的操作是一个one to one的操作
*/
private def mapMethod(sc: SparkContext) = {
val list = 1 to 10
val listRDD = sc.parallelize(list)
val bs = 7
println("listRDD's partition: " + listRDD.getNumPartitions)
val retRDD: RDD[Int] = listRDD.map(num => num * bs)
retRDD.foreach(num => println(num))
}
2)flatmap操作
/**
* flatMap(func):类似于map,但是每一个输入元素,
* 会被映射为0到多个输出元素(因此,func函数的返回值是一个Seq,而不是单一元素)
*
* flatMap是one to many
* @param sc
*/
private def flatMapMethod(sc: SparkContext) = {
val list = List(
"hello you",
"hello me he",
"you you"
)
val listRDD:RDD[String] = sc.parallelize(list)
val wordsRDD:RDD[String] = listRDD.flatMap{case line => {
line.split(" ")
}}
wordsRDD.foreach(println)
}
3)filter操作
/**
* filter(func): 返回一个新的数据集,由经过func函数后返回值为true的原元素组
成
* 过滤出集合中的偶数even,留下奇数odd
*/
private def filterMethod(sc: SparkContext) = {
val range = 1 until 10
val listRDD = sc.parallelize(range)
val filteredRDD = listRDD.filter{case num => {num % 2 != 0}}
filteredRDD.foreach(println)
}
4)sample操作
/**
* 采集抽样:
* 就是用样本空间来代替总体,查看总体数据的分布。
* 这个Spark的sample抽样是否非准确抽样,如果要抽取固定的数据量,只能自
己手动处理。
* 会在后面学习Spark如何解决数据倾斜的时候使用
* sample(withReplacement, frac, seed):
* 根据给定的随机种子seed,随机抽样出数量为frac的数据
*/
private def sampleMethod(sc: SparkContext) = {
val range = 1 to 100000
val listRDD = sc.parallelize(range)
val sampleRDD = listRDD.sample(true, 0.002)
sampleRDD.foreach(println)
println(s"sampleRDD的元素个数:${sampleRDD.count()}")
}
5)union操作
/**
* union(otherDataset): 返回一个新的数据集,由原数据集和参数联合而成
* 该操作类似于sql中的union all的操作(而sql中的union会做去重操作)
*/
private def unionMethod(sc: SparkContext) = {
val list1 = List(1, 2, 3, 4, 5)
val list2 = List(3, 5, 6, 8, 10)
val listRDD1 = sc.parallelize(list1)
val listRDD2 = sc.parallelize(list2)
val unionRDD = listRDD1.union(listRDD2)
unionRDD.foreach(println)
println("-----------------------------------")
val interRDD = listRDD1.intersection(listRDD2)//求rdd的交集
interRDD.foreach(println)
}
6)groupbykey操作
/**
* groupByKey([numTasks]):
* 在一个由(K,V)对组成的数据集上调用,返回一个(K,Iterable[V])对的数据集。
* 注意:默认情况下,使用8个并行任务进行分组,你可以传入numTask可选参数,
* 根据数据量设置不同数目的Task
* 这就是sql中的groupBy的操作
* 统计:文件E:/data/spark/topn.txt中每门课程的学员信息进行分组
*/
private def gbkMethod(sc: SparkContext) = {
val linesRDD:RDD[String] = sc.textFile("file:///E:/data/spark/topn.txt")
val course2InfoRDD:RDD[(String, String)] = linesRDD.map(line => {
val fields = line.split(" ")
val course = fields(0)
val name = fields(1)
val score = fields(2)
(course, name + "_" + score)
})
// course2InfoRDD.foreach(println)
//分组
val gbkRDD:RDD[(String, Iterable[String])] = course2InfoRDD.groupByKey()
// gbkRDD.foreach(t => {
// println(t._1 + "--->" + t._2)
// })
gbkRDD.foreach{case (course, infos) => {
println(s"${course} ---> ${infos}")
}}
//求出每门课中的成绩最高者和成绩
println("-----求出每门课中的成绩最高者和成绩------")
val course2MaxInfo:RDD[(String, String)] = gbkRDD.map{case (course, infos)
=> {
var max = Int.MinValue
var name = ""
for (info <- infos) {
val score = info.substring(info.indexOf("_") + 1).toInt
val _name = info.substring(0, info.indexOf("_"))
if(score >= max) {
max = score
name = _name
}
}
(course, name + "-" + max)
}}
course2MaxInfo.foreach(println)
}
7)reducebykey操作
/**
* reduceByKey(func, [numTasks]):
* 在一个(K,V)对的数据集上使用,返回一个(K,V)对的数据集,key相同的值,
* 都被使用指定的reduce函数聚合到一起。和groupByKey类似,任务的个数是可以
* 通过第二个可选参数来配置的。
*
* 在执行类似操作的时候,建议使用reduceByKey而不是使用groupByKey,因为
groupByKey的执行效率要低于reduceByKey,
* 究其原因主要在于groupByKey在计算的时候没有想reduceByKey一样的本地预聚合
combiner
* 而countByKey是一个action操作
*/
private def rbkMethod(sc: SparkContext) = {
val list = List(
"hello you",
"hello me he",
"you you"
)
val listRDD:RDD[String] = sc.parallelize(list)
val wordsRDD:RDD[String] = listRDD.flatMap{case line => {
line.split("\\s+")
}}
val pairsRDD = wordsRDD.map((_, 1))
val rbkRDD:RDD[(String, Int)] = pairsRDD.reduceByKey{case (v1, v2) =>
{v1 + v2}}
rbkRDD.foreach(println)
println("--------------groupByKey来完成reduceByKey的操作------------
-----")
val gbkRDDs:RDD[(String, Int)] = pairsRDD.groupByKey().map{case (word,
counts) => (word, counts.size)}
gbkRDDs.foreach(println)
println("--------------countByKey来完成reduceByKey的操作------------
-----")
val cbkMap = pairsRDD.countByKey()
cbkMap.foreach(println)
}
8)join操作
/**
* join(otherDataset, [numTasks]):
* 在类型为(K,V)和(K,W)类型的数据集上调用,返回一个(K,(V,W))对,
* 每个key中的所有元素都在一起的数据集
* 学生表student
* id name gender
* 1 余喆 女
* 2 高磊 男
* 3 任绍俊 男
* 4 梁光彩 女
* 5 白卓民 ladyboy
* 成绩表score
* id score sid
* 001 90 1
* 002 70 5
* 003 40 2
* 004 68.5 4
* 将学生信息及其考试成绩信息查询出来
* select
* stu.id,
* stu.name,
* stu.gender,
* s.score
* from student stu
* join score s on stu.id = s.sid
* sql中的join的类型:
* 交叉连接across join,连接没有on from student stu across join score s –
->产生笛卡尔积 ×
* 内连接inner join 等值连接,查询左右两张表中都拥有的数据
* 外连接 不等值连接
* 左外连接 left outer join
* 查询所有所有的数据,查询右表能在左表关联上的数据,查询不到的数据显
示为null
* 右外连接 right outer join
* 和做外链接相反
* 全连接 full outer join
* 左外连接 + 右外连接
*
*/
private def joinMethod(sc: SparkContext) = {
val stuList = List(
"1 余喆 女",
"2 高磊 男",
"3 任绍俊 男",
"4 梁光彩 女",
"5 白卓民 ladyboy"
)
val scoreList = List(
"001 90 1",
"002 70 5",
"003 40 2",
"004 68.5 4",
"005 78.5 9"
)
val stuRDD:RDD[String] = sc.parallelize(stuList)
val scoreRDD:RDD[String] = sc.parallelize(scoreList)
val stuId2Info:RDD[(String, String)] = stuRDD.map(line => {
val fields = line.split("\\s+")
val stuId = fields(0)
val name = fields(1)
val gender = fields(2)
(stuId, name + "," + gender)
})
val stuId2Score:RDD[(String, Double)] = scoreRDD.map(line => {
val fields = line.split("\\s+")
val stuId = fields(2)
val score = fields(1).trim.toDouble
(stuId, score)
})
println("----------------join之等值连接-------------------")
val joinInfo:RDD[(String, (String, Double))] =
stuId2Info.join(stuId2Score)
// joinInfo.foreach(t => {
// println(s"stuId:${t._1}==>info:${t._2._1}--${t._2._2}")
// })
joinInfo.foreach{case (stuId, (info, score)) => {
println(s"stuId:${stuId}==>info:${info}--${score}")
}}
println("--------------不等值连接之leftouterjoin-----------------")
val lojRDD:RDD[(String, (String, Option[Double]))] = stuId2Info.
leftOuterJoin(stuId2Score)
lojRDD.foreach{case (stuId, (info, option)) => {
println(s"stuId:${stuId}==>info:${info}—
${option.getOrElse(null)}")
}}
println("----------------不等值连接之rightouterjoin-----------------")
val rojRDD:RDD[(String, (Option[String], Double))] = stuId2Info.
rightOuterJoin(stuId2Score)
rojRDD.foreach{case (stuId, (option, score)) => {
println(s"stuId:${stuId}==>info:${option.getOrElse(null)}—
${score}")
}}
println("----------------不等值连接之fullouterjoin------------------")
val fojRDD:RDD[(String, (Option[String], Option[Double]))] =
stuId2Info.fullOuterJoin(stuId2Score)
fojRDD.foreach{case (stuId, (lOption, rOption)) => {
println(s"stuId:${stuId}==>info:${lOption.getOrElse(null)}—
${rOption.getOrElse(null)}")
}}
9)sortbykey操作
/**
* sparkcore中使用sortBy和sortByKey进行排序
* 按照学员的身高进行排序
* student
* id name height
* 1 黄术枝 172.5
* 2 孙天宝 178.5
* 3 李涛 180.5
* 4 姜威 170
* 5 闫建一 188
* sortByKey: ---->必须是k-v对
* 指的是分区内部有序,如果有多个分区进行排序,整体不一定有序,要想整体有
序,请设置numPartitions=1
* sortBy
* 其底层也是sortByKey
*/
private def sortMethod(sc: SparkContext) = {
val list = List(
"1 黄术枝 172.5",
"2 孙天宝 178.5",
"3 李涛 180.5",
"4 姜威 170",
"5 闫建一 188"
)
val stuRDD:RDD[String] = sc.parallelize(list)
//使用sortByKey进行排序--->转化数据为k-v对key进行排序,k--->身高
val height2Info:RDD[(Double, String)] = stuRDD.map(line => {
val fields = line.split("\\s+")
val id = fields(0)
val name = fields(1)
val height = fields(2).trim.toDouble
(height, id + "," + name)
})
val sortedRDD:RDD[(Double, String)] = height2Info.sortByKey
(numPartitions=1, ascending = false)
println("----------------sortByKey进行排序-------------------")
sortedRDD.foreach{case (height, idName) => {
println(s"${idName},${height}")
}}
println("----------------sortBy进行排序-------------------")
/**
* 使用给定的key对应的函数,对rdd进行排序,并返回有序的结果
*/
val sortedByRDD = stuRDD.sortBy[Double](
line => {
val fields = line.split("\\s+")
fields(2).trim.toDouble
}, false, 1
)(new Ordering[Double]() {
//升序:前面比后面,降序,后面比前面
override def compare(x: Double, y: Double) = {
x.compareTo(y)
}
}, ClassTag.Double.asInstanceOf[ClassTag[Double]])
sortedByRDD.foreach(println)
}
10)两个底层算组:combineByKey,aggregateByKey
package com.aura.bigdata.spark.core.p2
import org.apache.log4j.{Level, Logger}
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
import scala.collection.mutable.ArrayBuffer
/**
* 学习两个底层的算子:combineByKey,aggregateByKey
*
* 在研读reduceByKey源码的时候,看到将map的数据通过shuffle进行reduce的时
候,默认选择hash分区方式,将不同的key送到对应的分区中。
* 分区的id就是0到numPartitions-1,如果有3个分区,分区id就是0,1,2
* reduceByKey有map段的预聚合操作
*
* 同样,在看groupBykey的源码的时候,看到数据也是按照hashPartitioner方式进行
组织,同时官方建议如果我们需要计算分组内部的值得聚合做操
* 比如求每一个组的平均值,求和,最大值,最小值等待,这个建议使用combineByKey,
或者reduceByKey进行代替,以获得更高的性能。
* 究其原因在于groupByKey同样使用combineByKey实现,但是不同于reduceByKey的
时候,gbk没有本地预聚合。
*
* 如何自定分区:
* 1、如果手动在代码中已经制定了分区,那么就直接将该数据发送该分区,
* 2、如果没有执行,使用默认的defaultPartitioner(HashPartitioner)进行数据
的投送
*
* 使用combineByKey,aggregateByKey来分别模拟reduceByKey和groupByKey
*
* combineByKey和aggregateByKey的区别?
* 1、combineByKey和aggregateByKey的底层实现都是combineByKeyWithClassTag
方法,所以本质上没有区别
* 2、combineByKey更适合那些聚合前后数据类型不一致的rdd操作,aggregateByKey
更合适那些聚合前后数据类型一致的rdd操作。
* 为了完成reduceByKey或者groupByKey中完成的比较复杂的聚合操作,这个时候使
用combineByKey和aggregateByKey更能洞悉数据操作的底层过程。
*/
object _02SparkTransformationOps {
def main(args: Array[String]): Unit = {
Logger.getLogger("org.apache.hadoop").setLevel(Level.WARN)
Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
val conf = new SparkConf().setAppName("_02SparkTransformationOps")
.setMaster("local[2]")
val sc = new SparkContext(conf)
// cbk2rbkMethod(sc)
cbk2gbkMethod(sc)
sc.stop()
}
/*
使用combineByKey来模拟groupByKey
*/
private def cbk2gbkMethod(sc: SparkContext) = {
val linesRDD:RDD[String] = sc.textFile
("file:///E:/data/spark/topn.txt")
val course2InfoRDD:RDD[(String, String)] = linesRDD.map(line => {
val fields = line.split(" ")
val course = fields(0)
val name = fields(1)
val score = fields(2)
(course, name + "_" + score)
})
// course2InfoRDD.foreach(println)
//(chinese,CompactBuffer(ls_91, zs_90, zl_76, wb_95, sj_74, yj_98))
//(english,CompactBuffer(ww_56, zq_88, ts_87, ys_67, mz_77, gk_96))
// course2InfoRDD.groupByKey().foreach(println)
// val cbk2gbkRDD:RDD[(String, ArrayBuffer[String])] = course2InfoRDD.
combineByKey(createCombiner1, mergeValue1, mergeCombiners1)
val cbk2gbkRDD = course2InfoRDD.combineByKey(
nameScore => {
val ab = new ArrayBuffer[String]()
ab.append(nameScore)
ab
},
(buffer:ArrayBuffer[String], nameScore:String) => {
buffer.append(nameScore)
buffer
},
(buffer:ArrayBuffer[String], buffer1:ArrayBuffer[String]) => {
buffer.++(buffer1)
}
)
cbk2gbkRDD.foreach(println)
}
def createCombiner1(nameScore:String):ArrayBuffer[String] = {
val ab = ArrayBuffer[String]()
ab.append(nameScore)
ab
}
def mergeValue1(buffer:ArrayBuffer[String],
nameScore:String):ArrayBuffer[String] = {
buffer.append(nameScore)
buffer
}
def mergeCombiners1(buffer1:ArrayBuffer[String],
buffer2:ArrayBuffer[String]):ArrayBuffer[String] = {
buffer1.++(buffer2)
}
/**
* 使用combineByKey来模拟reduceByKey
* @param sc
*/
private def cbk2rbkMethod(sc: SparkContext) = {
val list = List(
"hello you",
"hello me he",
"hello shit he",
"you you"
)
val listRDD: RDD[String] = sc.parallelize(list)
val wordsRDD: RDD[String] = listRDD.flatMap { case line => {
line.split("\\s+")
}
}
val pairsRDD = wordsRDD.map((_, 1))
//使用combineByKey来模拟reduceByKey
// pairsRDD.reduceByKey(_+_)
val cbk2rbkRDD: RDD[(String, Int)] = pairsRDD.combineByKey
(createCombiner, mergeValue, mergeCombiners)
cbk2rbkRDD.foreach(println)
}
/**
* 第一个起始聚合操作,在每一个分区中,相同key只会执行一次该操作
* (k1, v1), (k1, v2)
* v1+v2
* 1+。。。+10
*
* var sum = 1
* for(i <- 2 to 10) {
* sum += i
* }
*
* 改createCombiner就相当于创建这个sum的过程,在每一个分区对应的相同
的key中只需要调用一次
*
* @return
*/
def createCombiner(num:Int) = {
println(s"---------createCombiner----------------${num}")
num
}
/**
* 当sum创建好之后,便开始循环遍历集合,给sum身上不断赋值数据
* 所以如果在某一个分区中的某一个key有N个值,当前方法会被调用N-1次
*/
def mergeValue(sum:Int, num:Int) = {
println(s"---------mergeValue----------------${sum}---->${num}")
sum + num
}
/**
* 当分区内部的数据计算完毕之后,便开始了相同key的分区间的计算
*/
def mergeCombiners(sum1:Int, sum2:Int) = {
println(s"------mergeCombiners------${sum1}---->${sum2}")
sum1 + sum2
}
}
11)使用aggregateByKey模拟reduceByKey和groupByKey
package com.aura.bigdata.spark.core.p2
import org.apache.log4j.{Level, Logger}
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
import scala.collection.mutable.ArrayBuffer
/**
* 使用aggregateByKey模拟reduceByKey和groupByKey
*
*/
object _03SparkTransformationOps {
def main(args: Array[String]): Unit = {
Logger.getLogger("org.apache.hadoop").setLevel(Level.WARN)
Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
val conf = new SparkConf().setAppName("_03SparkTransformationOps")
.setMaster("local[2]")
val sc = new SparkContext(conf)
// abk2RbkMethod(sc)
abk2GbkMethod(sc)
sc.stop()
}
/**
* 使用aggregateByKey模拟groupByKey
* @param sc
*/
private def abk2GbkMethod(sc: SparkContext) = {
val linesRDD:RDD[String]
= sc.textFile("file:///E:/data/spark/topn.txt")
val course2InfoRDD:RDD[(String, String)] = linesRDD.map(line => {
val fields = line.split(" ")
val course = fields(0)
val name = fields(1)
val score = fields(2)
(course, name + "_" + score)
})
val abk2gbk = course2InfoRDD.aggregateByKey(new
ArrayBuffer[String]())(
(buffer: ArrayBuffer[String], nameScore: String) => {
buffer.append(nameScore)
buffer
},
(buffer1: ArrayBuffer[String],buffer2: ArrayBuffer[String]) => {
buffer1.++(buffer2)
}
)
abk2gbk.foreach(println)
}
private def abk2RbkMethod(sc: SparkContext) = {
val list = List(
"hello you",
"hello me he",
"hello shit he",
"you you"
)
val listRDD: RDD[String] = sc.parallelize(list)
val wordsRDD: RDD[String] = listRDD.flatMap { case line => {
line.split("\\s+")
}
}
val pairsRDD = wordsRDD.map((_, 1))
//var sum = 0
val abk2rbk = pairsRDD.aggregateByKey(0)(seqOp, combOp)
pairsRDD.aggregateByKey(0)((sum, num) => sum + num, (sum1, sum2) =>
sum1+sum2)
abk2rbk.foreach(println)
}
/**
* 分区内的数据合并
* 某一个分区中的某一个Key有N个值,当前方法会被调用N次
*/
def seqOp(sum:Int, num:Int) = {
println("---------------seqOp---------------")
sum + num
}
/**
* 分区间的数据合并
*/
def combOp(sum1:Int, sum2:Int) = {
println("---------------combOp---------------")
sum1 + sum2
}
}
4,SparkRDD的action操作
package com.aura.bigdata.spark.core.p2
import org.apache.hadoop.io.{IntWritable, Text}
import org.apache.hadoop.io.compress.{DefaultCodec, SnappyCodec}
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat
import org.apache.log4j.{Level, Logger}
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
/**
* 学习SparkRDD的action操作
* action操作是spark作业job执行的动因
*/
object _04SparkActionOps {
def main(args: Array[String]): Unit = {
Logger.getLogger("org.apache.hadoop").setLevel(Level.WARN)
Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
val conf = new SparkConf().setAppName("_03SparkTransformationOps")
.setMaster("local[2]")
val sc = new SparkContext(conf)
val list = List(
"hello you",
"hello me he",
"hello shit he",
"you you"
)
val listRDD: RDD[String] = sc.parallelize(list)
val wordsRDD: RDD[String] = listRDD.flatMap { case line => {
line.split("\\s+")
}
}
val pairsRDD = wordsRDD.map((_, 1))
/*
reduce(func): 通过函数func聚集数据集中的所有元素。Func函数接受2个
参数,返回一个值。这个函数必须是关联性的,确保可以被正确的并发执行
该reduce操作和scala中的reduce操作一模一样
val list = 1 to 100
val listRDD = sc.parallelize(list)
val ret = listRDD.reduce((v1, v2) => v1 + v2)
*/
/*
collect():
在Driver的程序中,以数组的形式,返回数据集的所有元素。
这通常会在使用filter或者其它操作后,返回一个足够小的数据子集再使用,
直接将整个RDD集Collect返回,很可能会让Driver程序OOM
将RDD中各个分区中的数据,全都拉取到driver中。
*/
pairsRDD.collect().foreach(println)
/**
* count(): 返回数据集rdd的元素个数
*/
println("===========pairsRDD总共有" + pairsRDD.count() + "条记录。")
/*
take(n): 返回一个数组,由数据集的前n个元素组成。
注意,这个操作目前并非在多个节点之上并行执行,而是Driver程序所在机器,
单机计算所有的元素(Gateway的内存压力会增大,需要谨慎使用)
*/
println("=====================take(3)=====")
pairsRDD.take(3).foreach(println)
println("=====================takeOrdered(2)=====")
val retRDD = pairsRDD.reduceByKey(_+_)
retRDD.takeOrdered(2)(new Ordering[(String, Int)](){
override def compare(x: (String, Int), y: (String, Int)) = {
var ret = y._2.compareTo(x._2)
if(ret == 0) {
ret = x._1.compareTo(y._1)
}
ret
}
}).foreach(println)
// first(): 返回数据集的第一个元素(类似于take(1))
/*
saveAsTextFile(path):将数据集的元素,以textfile形式,保存到本地文件系统,
hdfs或者任何其它hadoop支持的文件系统。Spark将会调用每个元素的toString
方法,
并将它转换为文件中的一行文本
*/
retRDD.saveAsTextFile("file:///E:/data/spark/wc" +
System.currentTimeMillis())
/**
* saveAsSequenceFile(path):
* 将数据集的元素,以sequencefile的格式,保存到指定的目录下,本地系
统,hdfs或者任何其它hadoop支持的文件系统。RDD的元素必须由key-
value对组成,并都实现了Hadoop的Writable接口,或隐式可以转换为
* Writable(Spark包括了基本类型的转换,例如Int,Double,String等等)
*/
// retRDD.saveAsSequenceFile("file:///E:/data/spark/seq" +
System.currentTimeMillis())
retRDD.saveAsSequenceFile(
"file:///E:/data/spark/seq" + System.currentTimeMillis(),
Option(classOf[DefaultCodec])
)
// foreach(func): 在数据集的每一个元素上,运行函数func。这通常用于更新一
个累加器变量,或者和外部存储系统做交互
retRDD.saveAsNewAPIHadoopFile(
"file:///E:/data/spark/nahf" + System.currentTimeMillis(),
classOf[Text],
classOf[IntWritable],
classOf[TextOutputFormat[Text, IntWritable]]
)
sc.stop()
}
}
6,高级排序之求topN
package com.aura.bigdata.spark.core.p3
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
/**
* SparkRDD的TopN求值
*
*/
object _05SparkRDDTopNOps {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setMaster("local[*]")
.setAppName(s"${_05SparkRDDTopNOps.getClass.getSimpleName}")
val sc = new SparkContext(conf)
val linesRDD = sc.textFile("file:///E:/data/spark/core/10w行数据.txt")
val retRDD:RDD[(String, Int)] = linesRDD.flatMap(_.split("\\s+")).map((_,
1)).reduceByKey(_+_)
retRDD.sortByKey()
/**
* 求出该文件中单词出现次数最高的N(1, 3, 5, 7, 10)个值
*/
// retRDD.map{case (word, count) => (count, word)}.sortByKey(false,
1).take(5).foreach(println)
retRDD.takeOrdered(5)(new Ordering[(String, Int)](){
override def compare(x: (String, Int), y: (String, Int)) = {
y._2.compareTo(x._2)
}
}).foreach(println)
sc.stop()
}
}
7,二次排序
package com.aura.bigdata.spark.core.p3
import org.apache.spark.rdd.RDD
import org.apache.spark.serializer.KryoSerializer
import org.apache.spark.{SparkConf, SparkContext}
import scala.reflect.ClassTag
/**
* 二次排序
* 排序的依据不唯一,有多个排序指标
* 需求:
* 20 21
50 51
50 52
50 53
* 先按照第一列的升序,再按照第二列的降序?
* 1、排序,使用sortByKey
* 要按照key进行排序,问题是当前的排序字段有两个,怎么办? 必须要使用复合
key,才可以进行排序,
* 只能自定义对象进行排序
* 2、排序,使用sortBy
*/
object _06SparkRDDSecondSortOps {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setMaster("local[*]")
.setAppName(s"${_06SparkRDDSecondSortOps.getClass.getSimpleName}")
//spark提供的比java原生的序列化Serializable更加高效的一种序列化方
式
.set("spark.serializer", classOf[KryoSerializer].getName)
.registerKryoClasses(Array(classOf[SecondSort]))
val sc = new SparkContext(conf)
val linesRDD = sc.textFile("file:///E:/data/spark/secondsort.csv")
// sbkMethod1(linesRDD)
val sortedRDD:RDD[String] = linesRDD.sortBy(
line => line,
false,
1
)(new Ordering[String](){
/*
x: 1 2
y: 3 4
*/
override def compare(x: String, y: String) = {
val xFields = x.split("\\s+")
val yFields = y.split("\\s+")
val xFirst = xFields(0).trim.toInt
val yFirst = yFields(0).trim.toInt
val xSecond = xFields(1).trim.toInt
val ySecond = yFields(1).trim.toInt
var ret = xFirst.compareTo(yFirst)
if(ret == 0) {
ret = ySecond.compareTo(xSecond)
}
ret
}
}, ClassTag.Object.asInstanceOf[ClassTag[String]])
sortedRDD.foreach(println)
sc.stop()
}
private def sbkMethod1(linesRDD: RDD[String]) = {
val ssRDD = linesRDD.map(line => {
val fields = line.split("\\s+")
val first = fields(0).trim.toInt
val second = fields(1).trim.toInt
(new SecondSort(first, second), null)
})
// ssRDD.foreach(println)
val sbkRDD = ssRDD.sortByKey(true, 1)
sbkRDD.foreach { case (ss, tag) => {
println(ss)
}
}
}
}
/**
* scala和java中的排序的对象
* Ordered ----->Comparable
* Ordering ----->Comparator
*/
class SecondSort(val first:Int, val second:Int) extends Ordered[SecondSort] /*with Serializable*/ {
override def toString: String = this.first + "\t" + this.second
//先按照第一列的升序,再按照第二列的降序?
override def compare(that: SecondSort) = {
var ret = this.first.compareTo(that.first)
if(ret == 0) {
ret = that.second.compareTo(this.second)
}
ret
}
}
未序列化的错误:
需要序列化的原因是因为需要通过JVM,也就是说需要将多个分区的数据拉区到一起进
行操作,若是只动用一个分区,则不需要序列化
8,分组求topN
package com.aura.bigdata.spark.core.p3
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
import scala.collection.mutable
/**
* 分组排序-->分组topN
* course name score
* chinese ls 91
english ww 56
chinese zs 90
求出每门课程成绩Top3,怎么办?
1、假设只有一个课程,直接将该课程的成绩放到集合中进行排序即可。
2、现在是多门课程,要求出的是每门课程成绩Top3,必须要把每一门课程的所有的信息
进行单独的排序
现在的问题,如何将不同课程的信息进行归类,也就是说把语文课的信息放在一起,
英语课的成绩放在一起,因为只有
该科目的信息放在一起才可以进行科目内的排序,并求出top3.
分组就要用到groupByKey
RDD[String, Iterable[String]]
*/
object _07SparkRDDGroupSortOps {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setMaster("local[*]")
.setAppName(s"${_05SparkRDDTopNOps.getClass.getSimpleName}")
val sc = new SparkContext(conf)
val linesRDD = sc.textFile("file:///E:/data/spark/topn.txt")
val course2Info:RDD[(String, String)] = linesRDD.map(line => {
val course = line.substring(0, line.indexOf(" "))
val info = line.substring(line.indexOf(" ") + 1)
(course, info)
})
val course2Infos:RDD[(String, Iterable[String])] =
course2Info.groupByKey()
course2Infos.foreach(println)
//要求每门课程的top3
val course2Top3Infos:RDD[(String, mutable.TreeSet[String])] =
course2Infos.map{case (course, infos) => {
/*
infos是该门课程的所有的成绩信息,最后只需要3条,所以我们的组
内排序就在该map算子中完成
排序的集合?TreeSet,使用比较器完成自定义的比较
x: ls 91
y: zs 90
*/
var ts = new mutable.TreeSet[String]()(new Ordering[String](){
override def compare(x: String, y: String) = {
val xScore = x.substring(x.indexOf(" ") + 1).trim.toInt
val yScore = y.substring(y.indexOf(" ") + 1).trim.toInt
yScore.compareTo(xScore)
}
})
for(info <- infos) {
ts.add(info)
if(ts.size > 3) {
ts = ts.dropRight(1)
}
}
// //取前3
// (course, ts.take(3))
(course, ts)
}}
course2Top3Infos.foreach(println)
sc.stop()
}
}
9,分组求topN二
package com.aura.bigdata.spark.core.p3
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
/**
* 分组排序-->分组topN
* course name score
* chinese ls 91
english ww 56
chinese zs 90
求出每门课程成绩Top3,怎么办?
1、假设只有一个课程,直接将该课程的成绩放到集合中进行排序即可。
2、现在是多门课程,要求出的是每门课程成绩Top3,必须要把每一门课程的所有的信息
进行单独的排序
现在的问题,如何将不同课程的信息进行归类,也就是说把语文课的信息放在一起,
英语课的成绩放在一起,因为只有
该科目的信息放在一起才可以进行科目内的排序,并求出top3.
分组就要用到groupByKey
RDD[String, Iterable[String]]
*/
object _08SparkRDDGroupSortOps {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setMaster("local[*]")
.setAppName(s"${_05SparkRDDTopNOps.getClass.getSimpleName}")
val sc = new SparkContext(conf)
val linesRDD = sc.textFile("file:///E:/data/spark/topn.txt")
val course2Info:RDD[(String, String)] = linesRDD.map(line => {
val course = line.substring(0, line.indexOf(" "))
val info = line.substring(line.indexOf(" ") + 1)
(course, info)
})
val course2Infos:RDD[(String, ArrayBuffer[String])] =
course2Info.combineByKey(
createCombiner,
mergeValue,
mergeCombiners
)
course2Infos.foreach(println)
//要求每门课程的top3
val course2Top3Infos:RDD[(String, mutable.TreeSet[String])] =
course2Infos.map{case (course, infos) => {
/*
infos是该门课程的所有的成绩信息,最后只需要3条,所以我们的组
内排序就在该map算子中完成
排序的集合?TreeSet,使用比较器完成自定义的比较
x: ls 91
y: zs 90
*/
var ts = new mutable.TreeSet[String]()(new Ordering[String](){
override def compare(x: String, y: String) = {
val xScore = x.substring(x.indexOf(" ") + 1).trim.toInt
val yScore = y.substring(y.indexOf(" ") + 1).trim.toInt
yScore.compareTo(xScore)
}
})
for(info <- infos) {
ts.add(info)
if(ts.size > 3) {
ts = ts.dropRight(1)
}
}
// //取前3
// (course, ts.take(3))
(course, ts)
}}
course2Top3Infos.foreach(println)
sc.stop()
}
def createCombiner(info:String):ArrayBuffer[String] = {
val ab = new ArrayBuffer[String]()
ab.append(info)
ab
}
def mergeValue(buffer:ArrayBuffer[String], info:String) = {
buffer.append(info)
buffer
}
def mergeCombiners(buffer1:ArrayBuffer[String],
buffer2:ArrayBuffer[String]) = {
val buffer = buffer1.++(buffer2)
buffer
}
}
10,分组求topN三:
package com.aura.bigdata.spark.core.p3
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
import scala.collection.mutable
/**
* 分组排序-->分组topN
* course name score
* chinese ls 91
english ww 56
chinese zs 90
求出每门课程成绩Top3,怎么办?
1、假设只有一个课程,直接将该课程的成绩放到集合中进行排序即可。
2、现在是多门课程,要求出的是每门课程成绩Top3,必须要把每一门课程的所有的信
息进行单独的排序
现在的问题,如何将不同课程的信息进行归类,也就是说把语文课的信息放在一
起,英语课的成绩放在一起,因为只有
该科目的信息放在一起才可以进行科目内的排序,并求出top3.
分组就要用到groupByKey
RDD[String, Iterable[String]]
终极优化
边分组一遍排序
*/
object _08SparkRDDGroupSortOps {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setMaster("local[*]")
.setAppName(s"${_05SparkRDDTopNOps.getClass.getSimpleName}")
val sc = new SparkContext(conf)
val linesRDD = sc.textFile("file:///E:/data/spark/topn.txt")
val course2Info:RDD[(String, String)] = linesRDD.map(line => {
val course = line.substring(0, line.indexOf(" "))
val info = line.substring(line.indexOf(" ") + 1)
(course, info)
})
val course2Infos = course2Info.combineByKey(
createCombiner,
mergeValue,
mergeCombiners
)
course2Infos.foreach(println)
sc.stop()
}
def createCombiner(info:String):mutable.TreeSet[String] = {
val ts = new mutable.TreeSet[String]()(new Ordering[String](){
override def compare(x: String, y: String) = {
val xScore = x.substring(x.indexOf(" ") + 1).trim.toInt
val yScore = y.substring(y.indexOf(" ") + 1).trim.toInt
yScore.compareTo(xScore)
}
})
ts.add(info)
ts
}
def mergeValue(ts:mutable.TreeSet[String], info:String):mutable.TreeSet[String] = {
ts.add(info)
if(ts.size > 3) {
ts.dropRight(1)//删除→_→的元素
} else {
ts
}
}
def mergeCombiners(ts1:mutable.TreeSet[String],
ts2:mutable.TreeSet[String]):mutable.TreeSet[String] = {
// val ts = ts1.++:(ts2)
// if(ts.size > 3) {
// ts.dropRight(ts.size - 3)
// } else {
// ts
// }
ts2.foreach(info => {
ts1.add(info)
})
if(ts1.size > 3) {
ts1.dropRight(ts1.size - 3)
} else {
ts1
}
}
}