我将提出实际问题但请先承担我的用例。我有以下用例,比如我从某个地方得到rddStud
:
val rddStud: RDD[(String,Student)] = ???
其中'String' - 一些随机字符串和'Student' - case class Student(name: String, id: String, arrivalTime: Long, classId: String)
我只使用学生作为例子 - 实际的业务逻辑有很多不同的复杂类,有很多字段。
我希望实现的目标 - 具有相同id
的学生必须按其arrivalTime
的升序处理。
这就是我正在做的事情:
//Get RDD from Student.id -> Student
val studMapRdd: RDD[(String,Student)] = rddStud.map(tuple => {
val student = tuple._2
(student.id,student)
})
//Make sure all students with same student.id are in same partition.
//I can potentially use groupByKey/combineByKey.... etc, but I don't see much performance difference
val studPartitionRdd: RDD[(String,Student)] = studMapRdd.partitionBy(new HashPartitioner(studMapRdd.getNumPartitions))
val studSortedRdd: RDD[(String,Student)] = studPartitionRdd.sortBy({ case(studentId,student} =>
student.arrivalTime
}, ascending = true)
studSortedRdd.foreachPartition(itr =>{
itr.foreach{ case (studentId, student) => {
val studentName = student.name
val time = student.arrivalTime
//send for additional processing studentName and time combination
}
})
我的问题是:
非常感谢。
答案 0 :(得分:2)
同步(foreach(Partition)
)和异步(foreach(Partition)Async
)提交之间的选择以及元素和分区访问之间的选择都不会影响执行顺序。在第一种情况下,阻塞与非阻塞执行的重要区别在于,在第二种情况下,数据暴露的方式,但实际执行机制或多或少相同。
重新分区后的排序不是一种有效的方法。 sortBy
将触发完全随机播放,并且不会保留现有数据分发。如果您想保留现有数据布局,可以在后续mapPartitions
阶段进行排序,甚至可以更好地使用repartitionAndSortWithinPartitions
。
class StudentIdPartitioner[V](n: Int) extends org.apache.spark.Partitioner {
def numPartitions: Int = n
def getPartition(key: Any): Int = {
val x = key.asInstanceOf[Student].id.hashCode % n
x + (if (x < 0) n else 0)
}
}
val rddStud: RDD[Student] = ???
val partitioner = new StudentIdPartitioner(rddStud.getNumPartitions)
val arrTimeOrdering = scala.math.Ordering.by[Student, Long](_.arrivalTime)
{
implicit val ord = arrTimeOrdering
rddStud.map((_, null)).repartitionAndSortWithinPartitions(partitioner)
}