Spark基础排序+二次排序(java+scala)

本文深入探讨了排序算法的基础概念,包括一次排序与二次排序的具体实现方式,并提供了多种编程语言下的实例,如 Scala、Java 和 Python 的排序操作演示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.基础排序算法 

2.二次排序算法 

3.更高级别排序 

4.排序算法内幕 

1.基础排序算法

sc.textFile("/data/putfile.txt").flatMap(_.split(" ")).map(word=>(word,1)).reduceByKey(_+_,1).map(pair=>(pair._2,pair._1)).sortByKey(false).map(pair=>(pair._2,pair._1)).collect

//key value交换

sc.setLogLevel("WARN")

2.二次排序算法 

所谓二次排序就是指排序的时候考虑两个维度(有可能10次排序) 

Java版本

package com.dt.java.spark;

 

import akka.util.HashCode;

import scala.math.Ordered;

 

import java.io.Serializable;

 

//实现Ordered接口(scala的)

public class SecondarySort implements Ordered<SecondarySort>,Serializable {

//自定义二次排序的key

private int first;

private int second;

 

public int getFirst() {

return first;

}

 

public void setFirst(int first) {

this.first = first;

}

 

public int getSecond() {

return second;

}

 

public void setSecond(int second) {

this.second = second;

}

 

public SecondarySort(int first,int second)

{

this.first =first;

this.second=second;

}

 

@Override

public int compare(SecondarySort that) {

if (this.first - that.getFirst()!=0)

{

return this.first - that.getFirst();

}else

{

return this.second - that.getSecond();

}

 

}

 

@Override

public boolean $less(SecondarySort that) {

if(this.first < that.getFirst())

{

return true;

}else if(this.first == that.getFirst() && this.second < that.getSecond())

{

return true;

}

return false;

}

 

@Override

public boolean $greater(SecondarySort that) {

 

if(this.first > that.getFirst()){

return true;

}else if(this.first == that.getFirst() && this.second > that.second)

{

return true;

}

return false;

}

 

@Override

public boolean $less$eq(SecondarySort that) {

if(this.$less(that)){

return true;

}else if(this.first == that.getFirst() && this.second == that.second)

{

return true;

}

return false;

}

 

@Override

public boolean $greater$eq(SecondarySort that) {

if(this.$greater(that))

{

return true;

}else if(this.first == that.getFirst() && this.second == that.getSecond())

{

return true;

}

return false;

}

 

@Override

public int compareTo(SecondarySort that) {

if (this.first - that.getFirst()!=0)

{

return this.first - that.getFirst();

}else

{

return this.second - that.getSecond();

}

}

 

@Override

public boolean equals(Object o) {

if (this == o) return true;

if (o == null || getClass() != o.getClass()) return false;

 

SecondarySort that = (SecondarySort) o;

 

if (first != that.first) return false;

return second == that.second;

 

}

 

@Override

public int hashCode() {

int result = first;

result = 31 * result + second;

return result;

}

}

 

 

 

package com.dt.java.spark;

 

import org.apache.spark.SparkConf;

import org.apache.spark.api.java.JavaPairRDD;

import org.apache.spark.api.java.JavaRDD;

import org.apache.spark.api.java.JavaSparkContext;

import org.apache.spark.api.java.function.Function;

import org.apache.spark.api.java.function.PairFunction;

import org.apache.spark.api.java.function.VoidFunction;

import scala.Tuple2;

 

//二次排序,具体实现步骤

//第一步:按照Ordered和Serrializable接口实现自定义排序的Key

//第二步:将要进行二次排序的文件加载进来生成《key,value》类型的RDD

//第三步:使用sortByKey基于自定义的Key进行二次排序

//第四步:去除掉排序的key,,只保留排序结果

public class SecondarySortApp {

public static void main(String[] args){

 

SparkConf conf = new SparkConf().setAppName("SecondarySortApp").setMaster("local");

JavaSparkContext sc = new JavaSparkContext(conf);

 

JavaRDD lines = sc.textFile("D:\\JavaWorkspaces\\sparkproject\\sparktest.txt");

 

JavaPairRDD,String> pairs = lines.mapToPair(new PairFunction, SecondarySort, String>() {

@Override

public Tuple2, String> call(String line) throws Exception {

String[] splited = line.split(" ");

SecondarySort key = new SecondarySort(Integer.valueOf(splited[0]),Integer.valueOf(splited[1]));

return new Tuple2, String>(key,line);

}

}

);

 

JavaPairRDD,String> sorted = pairs.sortByKey();//完成二次排序

//过滤掉排序后自定的key,保留排序的结果

JavaRDD secondarysorted = sorted.map(new Function, String>, String>() {

@Override

public String call(Tuple2, String> sortedContent) throws Exception {

return sortedContent._2();

}

}

);

//

secondarysorted.foreach(new VoidFunction() {

@Override

public void call(String sorted) throws Exception {

System.out.println(sorted);

}

});

}

}//生成默认的构造器

 

Scala版本

package com.dt.scala.spark

 

 

 

class SecondarySort(val first:Int, val second:Int) extends Ordered[SecondarySort] with Serializable{

override def compare(that: SecondarySort): Int = {

if(this.first - that.first != 0)

{

this.first - that.first

}else {

this.second - that.second

}

 

}

}

 

package com.dt.scala.spark

 

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

 

 

object SecondarySortApp {

def main (args: Array[String]) {

//第一步;创建spark的配置对象sparkconf

 

val conf = new SparkConf()//创建sparkconf对象

conf.setAppName("SecondarySortApp")//设置应用程序的名称

conf.setMaster("local")//设置本地运行

 

//创建sparkcontext对象,sparkcontext是程序的唯一入口

 

val sc = new SparkContext(conf)

 

val lines = sc.textFile("D:\\JavaWorkspaces\\sparkproject\\sparktest.txt")

 

val pairWithSortkey = lines.map(line =>(

new SecondarySort( line.split(" ")(0).toInt,line.split(" ")(1).toInt),line

))

 

val sorted = pairWithSortkey.sortByKey(false)

 

val sortedResult = sorted.map(sortedline => sortedline._2)

sortedResult.collect.foreach(println)

}

}

 

作业2:阅读RangePartitioner源码 

1、scala 实现二次排序 2;自己阅读RangePartitioner

 

***********排序****************
在 Python 中以字符串顺序对整数进行自定义排序
rdd.sortByKey(ascending=True, numPartitions=None, keyfunc = lambda x: str(x))

在 Scala 中以字符串顺序对整数进行自定义排序
val input: RDD[(Int, Venue)] = ...
implicit val sortIntegersByString = new Ordering[Int] {
override def compare(a: Int, b: Int) = a.toString.compare(b.toString)
}
rdd.sortByKey()

在 Java 中以字符串顺序对整数进行自定义排序
class IntegerComparator implements Comparator<Integer> {
public int compare(Integer a, Integer b) {
return String.valueOf(a).compareTo(String.valueOf(b))
}
}
rdd.sortByKey(comp)

val kv1=sc.parallelize(List((5, 2), (3, 4), (4, 2)))

scala> kv1.sortByKey().foreach(print) //无顺序
(5,2)(3,4)(4,2)

scala> kv1.sortByKey().foreach(print) //无顺序
(3,4)(5,2)(4,2)

scala> kv1.sortByKey().collect   //升序
res2: Array[(Int, Int)] = Array((3,4), (4,2), (5,2))

scala> kv1.sortByKey(false).collect  //降序
res3: Array[(Int, Int)] = Array((5,2), (4,2), (3,4))

scala> print(implicitly[Ordering[Int]])
scala.math.Ordering$Int$@c88a842

implicit val sortM = new Ordering[Int] {
override def compare(a: Int, b: Int) = b-a
}

scala> kv1.sortByKey().collect
res5: Array[(Int, Int)] = Array((5,2), (4,2), (3,4))

implicit val sortM1 = new Ordering[Int] {
override def compare(a: Int, b: Int) = a-b
}

scala> print(implicitly[Ordering[Int]])
<console>:28: error: ambiguous implicit values:
 both value sortM of type => Ordering[Int]
 and value sortM1 of type => Ordering[Int]
 match expected type Ordering[Int]
       print(implicitly[Ordering[Int]])
       
scala> kv1.sortByKey().collect
<console>:31: error: value sortByKey is not a member of org.apache.spark.rdd.RDD[(Int, Int)]
       kv1.sortByKey().collect
           ^
           

***********sortBy函数*********************************
scala> val data = List(3,1,90,3,5,12)
data: List[Int] = List(3, 1, 90, 3, 5, 12)

scala> val rdd = sc.parallelize(data)
rdd: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:26

scala> rdd.collect
res0: Array[Int] = Array(3, 1, 90, 3, 5, 12)

scala> rdd.sortBy(x => x).collect
res1: Array[Int] = Array(1, 3, 3, 5, 12, 90)

scala> rdd.sortBy(x => x, false).collect
res2: Array[Int] = Array(90, 12, 5, 3, 3, 1)

scala> val result = rdd.sortBy(x => x, false)
result: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[15] at sortBy at <console>:28

scala> result.partitions.size
res3: Int = 4

scala> val result = rdd.sortBy(x => x, false, 1)
result: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[18] at sortBy at <console>:28

scala> result.partitions.size
res4: Int = 1


***********sortByKey函数*********************************
scala>  val a = sc.parallelize(List("wyp", "iteblog", "com", "397090770", "test"), 2)
a: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[19] at parallelize at <console>:24

scala> val b = sc. parallelize (1 to a.count.toInt , 2)
b: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[20] at parallelize at <console>:26

scala> val c = a.zip(b)
c: org.apache.spark.rdd.RDD[(String, Int)] = ZippedPartitionsRDD2[21] at zip at <console>:28

scala> c.sortByKey().collect
res5: Array[(String, Int)] = Array((397090770,4), (com,3), (iteblog,2), (test,5), (wyp,1))

scala> val b = sc.parallelize(List(3,1,9,12,4),2)
b: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[27] at parallelize at <console>:24

scala> val c = b.zip(a)
c: org.apache.spark.rdd.RDD[(Int, String)] = ZippedPartitionsRDD2[28] at zip at <console>:28

scala> c.sortByKey().collect
res8: Array[(Int, String)] = Array((1,iteblog), (3,wyp), (4,test), (9,com), (12,397090770))

implicit val sortIntegersByString = new Ordering[Int]{
 override def compare(a: Int, b: Int) =
 a.toString.compare(b.toString)}
 
scala> implicit val sortIntegersByString = new Ordering[Int]{
     |  override def compare(a: Int, b: Int) =
     |  a.toString.compare(b.toString)}
sortIntegersByString: Ordering[Int] = $anon$1@50514648

scala> c.sortByKey().collect
res9: Array[(Int, String)] = Array((1,iteblog), (12,397090770), (3,wyp), (4,test), (9,com))


***********Spark二次排序*********************************
scala> val at=List((2,2),(1,31),(4,4),(1,11),(2,2),(1,31),(4,4),(1,21),(1,1),(2,2),(1,6),(3,8),(1,11),(3,23),(3,3),(2,22),(1,11),(3,3),(2,2),(3,8),(1,6),(0,5),(4,4))
at: List[(Int, Int)] = List((2,2), (1,31), (4,4), (1,11), (2,2), (1,31), (4,4), (1,21), (1,1), (2,2), (1,6), (3,8), (1,11), (3,23), (3,3), (2,22), (1,11), (3,3), (2,2), (3,8), (1,6), (0,5), (4,4))

scala> val kv1=sc.parallelize(at)
kv1: org.apache.spark.rdd.RDD[(Int, Int)] = ParallelCollectionRDD[43] at parallelize at <console>:32

scala> kv1.sortByKey(false).collect
res16: Array[(Int, Int)] = Array((4,4), (4,4), (4,4), (3,8), (3,23), (3,3), (3,3), (3,8), (2,2), (2,2), (2,2), (2,22), (2,2), (1,31), (1,11), (1,31), (1,21), (1,1), (1,6), (1,11), (1,11), (1,6), (0,5))

--先按first降序再按second升序
class SortByTwice(val first:Int,val second:Int) extends Ordered[SortByTwice] with Serializable{
def compare(that:SortByTwice):Int={
 if(this.first-that.first!=0){
   return that.first-this.first
 } else{
   return this.second-that.second
 }
}
}


scala> kv1.map(x=>new SortByTwice(x._1,x._2)).sortBy(x=>x).map(x=>(x.first,x.second)).collect
res18: Array[(Int, Int)] = Array((4,4), (4,4), (4,4), (3,3), (3,3), (3,8), (3,8), (3,23), (2,2), (2,2), (2,2), (2,2), (2,22), (1,1), (1,6), (1,6), (1,11), (1,11), (1,11), (1,21), (1,31), (1,31), (0,5))

scala> kv1.map(x=>new SortByTwice(x._1,x._2)).sortBy(x=>x).map(x=>(x.first,x.second)).collect.foreach(println)
(4,4)
(4,4)
(4,4)
(3,3)
(3,3)
(3,8)
(3,8)
(3,23)
(2,2)
(2,2)
(2,2)
(2,2)
(2,22)
(1,1)
(1,6)
(1,6)
(1,11)
(1,11)
(1,11)
(1,21)
(1,31)
(1,31)
(0,5)

scala> kv1.map(x=>(new SortByTwice(x._1,x._2),x)).sortByKey().map(x=>x._2).collect.foreach(println)
(4,4)
(4,4)
(4,4)
(3,3)
(3,3)
(3,8)
(3,8)
(3,23)
(2,2)
(2,2)
(2,2)
(2,2)
(2,22)
(1,1)
(1,6)
(1,6)
(1,11)
(1,11)
(1,11)
(1,21)
(1,31)
(1,31)
(0,5)

--先按first升序再按second降序
scala> kv1.map(x=>(new SortByTwice(x._1,x._2),x)).sortByKey(false).map(x=>x._2).collect.foreach(println)
(0,5)
(1,31)
(1,31)
(1,21)
(1,11)
(1,11)
(1,11)
(1,6)
(1,6)
(1,1)
(2,22)
(2,2)
(2,2)
(2,2)
(2,2)
(3,23)
(3,8)
(3,8)
(3,3)
(3,3)
(4,4)
(4,4)
(4,4)

scala> print(implicitly[Ordering[SortByTwice]])
scala.math.LowPriorityOrderingImplicits$$anon$6@5343c732

 

通过groupBy进行二次排序(也有一种情况是需要将Key进行groupBy的Key,Value二次排序)
scala> kv1.groupByKey.map(x=>(x._1,x._2.toList.sortWith(_>_))).collect.foreach(println)
(4,List(4, 4, 4))
(0,List(5))
(1,List(31, 31, 21, 11, 11, 11, 6, 6, 1))
(2,List(22, 2, 2, 2, 2))
(3,List(23, 8, 8, 3, 3))

scala> kv1.groupByKey.map(x=>(x._1,x._2.toList.sortWith(_<_))).collect.foreach(println)
(4,List(4, 4, 4))
(0,List(5))
(1,List(1, 6, 6, 11, 11, 11, 21, 31, 31))
(2,List(2, 2, 2, 2, 22))
(3,List(3, 3, 8, 8, 23))

<think>好的,用户的问题是关于如何使用sortby实现二次排序,或者有没有相关的示例。我需要先理解什么是二次排序二次排序通常指的是在排序时,先按一个字段排序,如果该字段相同,则再按另一个字段排序。例如,先按成绩降序,成绩相同的再按姓名升序。 接下来,我需要回忆一下sortby函数的使用方法。在Python中,sort或sorted函数的key参数可以接收一个函数,这个函数返回一个元组,元组中的元素就是排序的依据。例如,当处理一个包含多个字段的数据时,可以返回一个元组,包含主要排序字段和次要排序字段。比如,对于列表中的元素是字典或元组的情况,可以指定多个键。 然后,我需要考虑用户可能的场景。用户可能有一个包含多个字段的数据结构,比如学生信息,每个学生有姓名、分数、年龄等,需要先按分数排序,分数相同再按年龄排序。这时候,使用sortby的话,可以给key参数传递一个lambda函数,返回(分数,年龄)这样的元组。但要注意排序的顺序,如果需要降序或升序,可能需要调整符号或者使用reverse参数。 另外,用户可能来自不同的编程语言背景,比如ScalaJava,但这里的问题标签是Python,所以需要以Python为例。不过,用户提供的引用中有ScalaJava的例子,可能需要说明不同语言中的实现方式,但主要回答Python的。 需要检查引用的资料是否相关。例如,引用[3]提到了Hive中的distribute by和sort by,引用[4]是SparksortByKey和sortBy,这可能涉及到分布式系统中的二次排序。但用户的问题更偏向于一般编程语言中的实现,比如Python。不过用户可能是在Spark环境下使用,所以可能需要分别说明。 在Python中,sorted函数和列表的sort方法都支持通过key函数进行自定义排序。对于二次排序,可以构造一个元组作为排序键,元组的每个元素对应一个排序条件。例如,sorted(list, key=lambda x: (x[1], x[0]))会先按第二个元素排序,再按第一个元素排序。 同时,如果需要不同的排序顺序,比如一个升序一个降序,可以在元组中使用负数或者反转参数。例如,sorted(list, key=lambda x: (-x[1], x[0])),这样第一个字段降序,第二个升序。 还要注意,如果排序的字段不是数字,可能需要转换类型或者使用其他方式处理。例如,字符串可能需要使用不同的方式逆序,但通常直接使用reverse参数可能不够,因为reverse会影响整个元组的排序,而不仅仅是单个字段。这时候可能需要自定义排序函数或者使用多个排序步骤,但Python的排序是稳定的,所以可以分多次排序,先排次要条件,再排主要条件。不过对于二次排序,通常更高效的是使用元组作为键。 在示例方面,可以举一个简单的列表,里面包含元组,然后展示如何用sortby进行二次排序。比如,学生成绩列表,先按分数降序,再按姓名升序。代码可能是这样的: students = [('Alice', 85, 20), ('Bob', 85, 19), ('Charlie', 90, 21)] sorted_students = sorted(students, key=lambda x: (-x[1], x[0])) 这样,首先按分数降序(通过取负数),然后按姓名升序排列。 另外,用户提到“sortby的二次排序功能”,可能需要解释在Spark中的使用,比如RDD的sortBy方法。这时候可以给出Spark的示例,比如: rdd.sortBy(lambda x: (x.field1, x.field2), ascending=[False, True]) 这会先按field1降序,再按field2升序排序。需要说明不同框架下的实现可能不同,但核心思想都是通过复合键来排序。 还需要考虑用户可能的疑问,比如如何处理多个排序条件的不同顺序,或者如何处理非数字类型的逆序。这时候需要给出相应的解决方案,比如对字符串使用负号不行,可以设置reverse参数,或者在key函数中转换。 总结回答的结构:先解释二次排序的概念,然后给出Python中的实现方法,包括基本示例和不同排序顺序的处理,接着可能扩展到Spark等框架中的使用,最后总结注意事项和常见问题。</think>### 如何实现基于多字段的二次排序? #### 核心思路 二次排序即**先按主字段排序,主字段相同时再按次字段排序**。在编程中可通过以下方式实现: 1. **构造复合键**:将多个排序字段组合为元组作为排序依据 2. **控制排序方向**:通过符号反转或参数设置实现升序/降序 #### Python实现示例 ```python # 示例数据:包含姓名、分数、年龄的学生列表 students = [('Bob', 85, 19), ('Alice', 85, 20), ('Charlie', 90, 21)] # 按分数降序,分数相同时按姓名升序排列 sorted_students = sorted(students, key=lambda x: (-x[1], x[0])) print(sorted_students) # 输出:[('Charlie', 90, 21), ('Alice', 85, 20), ('Bob', 85, 19)] ``` #### 进阶应用 1. **混合排序方向**:若需部分字段降序、部分升序 ```python # 分数降序,年龄升序 sorted_students = sorted(students, key=lambda x: (-x[1], x[2])) ``` 2. **非数值字段处理**:对字符串字段需通过`reverse`参数控制方向 ```python # 姓名降序,分数升序(需分两步进行稳定排序) students.sort(key=lambda x: x[1]) # 次要条件先排序 students.sort(key=lambda x: x[0], reverse=True) # 主要条件后排序 ``` #### Spark框架实现 在分布式计算中,可通过`sortBy`指定多字段排序: ```scala val rdd = sc.parallelize(students) // 按分数降序,年龄升序 val sortedRDD = rdd.sortBy(x => (-x._2, x._3), ascending = true) ``` #### 注意事项 - **元组顺序**:复合键元组中字段顺序决定优先级[^3] - **类型一致性**:复合键内字段需支持比较操作 - **性能影响**:大数据量时建议使用分布式框架如Spark[^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值