待排序数据:
D 4
A 6
A 3
A 1
D 7
B 6
C 2
代码:
#二次排序
from operator import gt
from pyspark import SparkContext, SparkConf
# 定义一个类,用于排序的键(根据column1的值降序,column1的值相等根据column2的值降序)
class SecondarySortKey():
def __init__(self, k):
self.column1 = k[0]
self.column2 = k[1]
def __gt__(self, other):
# 如果第一列相等,则比较第二列
if other.column1 == self.column1:
return gt(self.column2,other.column2)
# 否则直接比较第一个组件
else:
return gt(self.column1, other.column1)
if __name__ == '__main__':
conf = SparkConf().setAppName('spark_sort').setMaster('local[1]')
sc = SparkContext(conf=conf)
# 文件路径
file="file:home/zzp/PycharmProjects/SecondarySort/file4.txt"
# 读取文件内容,创建RDD
rdd1 = sc.textFile(file)
# 过滤掉空行
rdd2 = rdd1.filter(lambda x: (len(x.strip()) > 0))
# 将每一行分割为两部分,第一部分作为键,第二部分转换为整数,并与原行一起构成元组 ((A,4),"A 4")
rdd3 = rdd2.map(lambda x: ((x.split(" ")[0], int(x.split(" ")[1])), x))
# 将键映射为自定义的SecondarySortKey对象,用于排序 x[0]=(A,4) x[1]="A 4"
rdd4 = rdd3.map(lambda x: ( SecondarySortKey(x[0]) , x[1]))
# 根据SecondarySortKey对象进行升序排序
rdd5 = rdd4.sortByKey()
# 提取排序后的值(原文件行"A 4")
rdd6 = rdd5.map(lambda x: x[1])
# 将结果保存为文本文件,这里先通过repartition(1)确保所有结果都写入同一个分区
rdd6.repartition(1).saveAsTextFile("file:///home/zzp/PycharmProjects/SecondarySort/result")
运行结果:
A 1
A 3
A 6
B 6
C 2
D 4
D 7
答疑解惑:
1.这段SecondarySortKey()代码是什么意思,若接收数据为(B,6),(A,4),(A,1),说明SecondarySortKey()处理过程 ???
1.SecondarySortKey()是什么意思,若接收数据为(B,6),(A,4),(A,1),说明SecondarySortKey()处理过程 ???
class SecondarySortKey():
def __init__(self, k):
self.column1 = k[0]
self.column2 = k[1]
def __gt__(self, other):
# 如果第一列相等,则比较第二列
if other.column1 == self.column1:
return gt(self.column2,other.column2)
# 否则直接比较第一个组件
else:
return gt(self.column1, other.column1)
这段代码定义了一个名为SecondarySortKey的类,该类用于处理二元组的排序。其主要目的是实现一个自定义的比较方法,以根据两个组件进行排序。
__init__(self, k):这是类的构造函数,用于初始化对象。它接受一个二元组k作为输入,并将k的第一个元素存储在self.column1中,将第二个元素存储在self.column2中。
__gt__(self, other):这是一个特殊的魔法方法,用于定义“大于”操作。当使用>运算符比较两个SecondarySortKey对象时,这个方法会被调用。
如果两个对象的column1相等,则比较它们的column2。如果self.column2大于other.column2,则返回True,表示self大于other。
如果column1不相等,则直接比较column1。如果self.column1大于other.column1,则返回True。
现在,对于给定的数据(B,6), (A,4), (A,1),处理过程如下:
假设我们首先将这三个二元组转换为SecondarySortKey对象。
(B,6) 转换为 SecondarySortKey(B, 6)
(A,4) 转换为 SecondarySortKey(A, 4)
(A,1) 转换为 SecondarySortKey(A, 1)
假设我们要对这三个对象进行排序。排序算法(如Python的内置sorted函数或列表的sort方法)会使用__gt__方法来比较对象。
排序过程:
首先,(A,1) 和 (A,4) 会被比较。由于它们的column1(即第一个元素)相同(都是A),所以会比较它们的column2。由于1小于4,所以(A,1)会排在(A,4)前面。
接着,(B,6) 与已经排序好的(A,1) 和 (A,4) 比较。由于(B,6)的column1(即B)与(A,1)和(A,4)的column1(即A)不同,所以直接比较column1。由于B在字母顺序上大于A,所以(B,6)会排在(A,1)和(A,4)之后。
最后,我们已经知道(A,1)排在(A,4)前面,所以最终的排序顺序是:(A,1), (A,4), (B,6)。
2.为什么(A,1) 和 (A,4) 会被先比较,明明(B,6)是第一个数据 ???
2.为什么(A,1) 和 (A,4) 会被先比较,明明(B,6)是第一个数据 ???
在排序算法中,比较的顺序并不完全取决于数据在输入列表中的顺序。
实际上,排序算法会根据比较的结果和所使用的具体算法(例如,快速排序、归并排序、堆排序等)来决定下一步比较哪两个元素。
对于以上例子,虽然(B,6)是输入列表中的第一个数据,但在排序过程中,算法会根据比较的结果动态地选择比较的元素对。
因此,(A,1)和(A,4)可能在某个阶段被选择出来进行比较,而(B,6)则可能在稍后的阶段与其他元素进行比较。
重要的是,无论比较的顺序如何,最终的结果应该是一致的,即排序算法应该能够正确地根据__gt__方法定义的顺序对所有元素进行排序。
在这个特定的例子中,由于(A,1)和(A,4)的第一个元素相同,它们会基于第二个元素进行比较。
而(B,6)的第一个元素与它们不同,所以它会与已排序好的部分(在这里是(A,1)和(A,4))的某个元素进行比较,具体是哪个元素取决于排序算法的内部逻辑。
总的来说,虽然输入的顺序是(B,6), (A,4), (A,1),但排序算法并不保证按照这个顺序来比较元素。
算法会根据其内部逻辑和__gt__方法的比较结果来动态地决定比较的顺序,以确保最终得到一个正确的排序结果。