Spark(流媒体)RDD foreachPartitionAsync功能/工作

时间:2016-06-28 00:39:12

标签: scala apache-spark spark-streaming rdd

我将提出实际问题但请先承担我的用例。我有以下用例,比如我从某个地方得到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
    }
})

我的问题是:

  1. 如果我使用foreachPartitionAsync - 它会并行处理所有分区,但每个分区中的元素按顺序排列?如果没有,那么foreachPartitionAsync和foreachAsync之间的区别是什么?
  2. 重新分区后的分类方法是否合理?或者,如果您可以建议在上述逻辑中进行任何优化?
  3. 非常感谢。

1 个答案:

答案 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)
}