大家:
好!在spark中对数据进行排序,是在实际工作中是经常用到的,本文是通过样例类的形式在实现用户自定义排序。
准备样例数据,这是第一步,我习惯将数据放在一个文件中。测试文件目录为,C:\test\sort.txt, 样例数据以下所示:
apple 5 5288
sansung 5 5888
huawei 1 3788
mi 4 3799
sony 3 3799
lg 4 2499
说明: 1 数据之间按照TAB键进行隔开 2 样例数据共三列(商品名称,权重,价格)
先用spark的常规的sort的排序,代码如下所示:
package day04
import org.apache.spark.{SparkConf, SparkContext}
/**
* Created by Administrator on 2017/9/24.
* 功能: 演示用户自定义排序 自己写的两个sortBy 是不行的
*
*/
object UserDefinedSort1 {
def main(args: Array[String]): Unit = {
val conf=new SparkConf().setAppName("UserDefinedSort1").setMaster("local[2]")
val sc=new SparkContext(conf)
val lines=sc.textFile("c://test//sort.txt")
val rdd=lines.map(line=>{
val f=line.split("\t")
(f(0),f(1),f(2))
})
// println(rdd.collect().toBuffer)
// val sort=rdd.sortBy(_._2,true).sortBy(_._3,false)
val sort=rdd.sortBy(_._2,true)
val sort1=sort.sortBy(_._3,true)
println(sort1.collect().toBuffer)
sc.stop()
}
}
为了验证实验的效果,我做了以下的尝试,在此仅仅截取核心的代码和结果进行展示
val sort=rdd.sortBy(_._2,true)
println(sort.collect().toBuffer)
--true 结果 说明单个字段是按照从小到大的,其余字段没有参与排序
ArrayBuffer((huawei,1,3788), (sony,3,3799), (mi,4,3799), (lg,4,2499), (apple,5,5288), (sansung,5,5888))
val sort=rdd.sortBy(_._2,false)
println(sort.collect().toBuffer)
--false 结果 说明单个字段是按照从大到小的,其余字段没有参与排序
ArrayBuffer((apple,5,5288), (sansung,5,5888), (mi,4,3799), (lg,4,2499), (sony,3,3799), (huawei,1,3788))
val sort=rdd.sortBy(_._2,false)
val sort1=sort.sortBy(_._3,false)
println(sort1.collect().toBuffer)
---先按照等级降序,再按照价格降序。 可以看到,没有按照预期的效果进行展现,似乎只有价格降序起了作用
ArrayBuffer((sansung,5,5888), (apple,5,5288), (mi,4,3799), (sony,3,3799), (huawei,1,3788), (lg,4,2499))
val sort=rdd.sortBy(_._2,true)
val sort1=sort.sortBy(_._3,false)
println(sort1.collect().toBuffer)
--先按照等级升序,在同一个等级内按照价格降序,可以看到,没有按照预期的效果进行展现,似乎只有价格降序起了作用
ArrayBuffer((sansung,5,5888), (apple,5,5288), (sony,3,3799), (mi,4,3799), (huawei,1,3788), (lg,4,2499))
val sort=rdd.sortBy(_._2,false)
val sort1=sort.sortBy(_._3,true)
println(sort1.collect().toBuffer)
---先按照等级降序,再按照价格升序, 可以看到,没有按照预期的效果进行展现,似乎只有价格升序起了作用
ArrayBuffer((lg,4,2499), (huawei,1,3788), (mi,4,3799), (sony,3,3799), (apple,5,5288), (sansung,5,5888))
val sort=rdd.sortBy(_._2,true)
val sort1=sort.sortBy(_._3,true)
println(sort1.collect().toBuffer)
---先按照等级升序,再按照价格升序, 可以看到,没有按照预期的效果进行展现,似乎只有价格升序起了作用
ArrayBuffer((lg,4,2499), (huawei,1,3788), (sony,3,3799), (mi,4,3799), (apple,5,5288), (sansung,5,5888))
可以看到,单个的sort是没有问题的。但是,如果涉及到两个字段的排序,就有问题了,而这往往是实际工作中需要的。
为此,引入了样例类,代码以下所示:
package day04
import org.apache.spark.{SparkConf, SparkContext}
/**
* Created by Administrator on 2017/9/24.
* 功能: 演示用户自定义排序 继承Ordered 类,重写compare方法
*
*/
// 先定义一个样例类
case class Goods(val simi:Int,val price:Int) extends Ordered[Goods] with Serializable
{
override def compare(that:Goods):Int={
if(this.price==that.price){
that.simi-this.simi //如果价格相等,权重从大到小
}else{
this.price-that.price //价格从小到大排序
}
}
}
object UserDefinedSort {
def main(args: Array[String]): Unit = {
val conf=new SparkConf().setAppName("UserDefinedSort").setMaster("local[2]")
val sc=new SparkContext(conf)
val lines=sc.textFile("c://test//sort.txt")
val rdd=lines.map(line=>{
val f=line.split("\t")
(f(0),f(1).toInt,f(2).toInt)
})
val sort=rdd.sortBy(x=>Goods(x._2,x._3),true)
println(sort.collect().toBuffer)
}
}
核心点: 先定义一个样例类 实现Ordered 类,重写compare方法 ,以及序列化
程序运行结果以下所示:
ArrayBuffer((lg,4,2499), (huawei,1,3788), (mi,4,3799), (sony,3,3799), (apple,5,5288), (sansung,5,5888))
说明: 1 如果在程序的第35行,排序的时候将true修改为了false,结果为以下的所示:
--false val sort=rdd.sortBy(x=>Goods(x._2,x._3),false)
ArrayBuffer((sansung,5,5888), (apple,5,5288), (sony,3,3799), (mi,4,3799), (huawei,1,3788), (lg,4,2499))
个人认为,这样的写法相当于又绕了一层,容易混淆。建议把所有的排序规则都写在compare方法内