![](/img/trans.png)
[英]Sorting an RDD in Apache Spark using mapPartitions and reduce
[英]Sorting using spark
我需要对RDD进行排序。 排序需要在我的记录的多个字段上,因此我需要一个自定义的比较器。
我看到sortBy
只接受一个键。 我偶然发现了http://codingjunkie.net/spark-secondary-sort/ ,因此使用repartitionAndSortWithinPartitions
来实现相同的目的。
为什么sortBy
不接受自定义的Comparator进行排序? 为什么只需要重新分区才能使用自定义比较器?
问题1 :这是方法sortBy
的签名 :
/**
* Return this RDD sorted by the given key function.
*/
def sortBy[K](
f: (T) => K,
ascending: Boolean = true,
numPartitions: Int = this.partitions.length)
(implicit ord: Ordering[K], ctag: ClassTag[K]): RDD[T] = withScope {
this.keyBy[K](f)
.sortByKey(ascending, numPartitions)
.values
}
您的RDD数据对象显然是T类型的
请注意,sortBy方法绝对具有单个键参数字段: f: (T) => K
它接受匿名函数 ,因此您可以轻松生成自定义的可比较结构,并充分利用具有自己定义良好的比较器的常见数据类型。
例如,如果您将RDD [Int,Int]称为data ,则可以执行以下操作:
val cmp = (t: (Int, Int)) => (t._1, -t._2)
data.sortBy(cmp)
这样可以实现多字段轻松比较,对吧?
这将获得排序的RDD,其中第一个字段升序,第二个字段降序。
问题2 :repartitionAndSortWithinPartitions 用法
这是一个特定的rdd运算符,旨在比调用分区然后在每个分区内进行排序更有效。
您的程序在排序之前不需要预先分区,只需在此特定通用模式下进行内部优化即可获得高性能。
有关详细信息,请参阅文档 。
- mapPartitions使用例如.sorted对每个分区进行排序
- repartitionAndSortWithinPartitions可以有效地对分区进行排序,同时进行重新分区。
- 排序以生成全局排序的RDD
RDD的sortByKey方法用于总排序
RDD的repartitionAndSortWithinPartitions使用分区内的排序,但不使用交叉分区,但是不幸的是,它添加了一个额外的步骤来进行分区
正如Spark API中所写,repartitionAndSortWithinPartitions比调用repartition效率更高,然后在每个分区内排序其他单词repartitionAndSortWithinPartitions将首先根据提供的分区程序对数据进行重新分区,然后按键进行排序:
因此,首先重新分区,然后再调用sortBy可以使您获得良好的性能,同样可以使用repartitionAndSortWithinPartitions来实现
添加一些排序示例希望对您有所帮助。
例1
val rdd = sc.parallelize(Seq(
| ("math", 55),
| ("math", 56),
| ("english", 57),
| ("english", 58),
| ("science", 59),
| ("science", 54)))
rdd.collect()
//Default Sorting : Ascending order
val sorted1 = rdd.sortByKey()
sorted1.collect()
//Custom Sorting : Descending order (using implicit 'Ordering')
{
| //Let us define an implicit sorting for the method sortByKey()
| //We have used '{' above to limit the scope of the implicit ordering
| implicit val sortIntegersByString = new Ordering[String] {
| override def compare(a: String, b: String) = {
| val result = a.compare(b)
| //We use -ve to sort the key in descending order
| -result
| }
| }
| val sorted2 = rdd.sortByKey()
|
| //Result
| sorted2.collect()
| }
//Default Sorting : Descending order (done using the 'ascending' flag argument)
val sorted3 = rdd.sortByKey(false)
//Result
sorted3.collect()
结果:
rdd: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[101] at parallelize at command-1784487111427703:1
sorted1: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[104] at sortByKey at command-1784487111427703:12
sorted3: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[110] at sortByKey at command-1784487111427703:34
res28: Array[(String, Int)] = Array((science,59), (science,54), (math,55), (math,56), (english,57), (english,58))
例2
case class Row(var firstName: String, var lastName: String, var city: String)
var rows = List(new Row("Oscar", "Wilde", "London"),
new Row("Otto", "Swift", "Berlin"),
new Row("Carl", "Swift", "Paris"),
new Row("Hans", "Swift", "Dublin"),
new Row("Hugo", "Swift", "Sligo"))
//print ("sort by last name")
//rows.sortBy(_.lastName)
print ("sort by last name and first name")
rows.sortBy(r => (r.lastName, r.firstName))
sort by last name and first namedefined class Row
rows: List[Row] = List(Row(Oscar,Wilde,London), Row(Otto,Swift,Berlin), Row(Carl,Swift,Paris), Row(Hans,Swift,Dublin), Row(Hugo,Swift,Sligo))
res26: List[Row] = List(Row(Carl,Swift,Paris), Row(Hans,Swift,Dublin), Row(Hugo,Swift,Sligo), Row(Otto,Swift,Berlin), Row(Oscar,Wilde,London))
RDD与数据集:
val sqlContext = new org.apache.spark.sql.SQLContext(sc)
case class MyRecord(time: Double, id: String)
val rdd = sc.parallelize(1 to 200, 200).flatMap(x =>Seq.fill(10000)(MyRecord(util.Random.nextDouble, "xxx")))
// sort this RDD by time:
val sorted = rdd.sortBy(x => x.time)
result.count
// convert the original RDD to Dataframe and sort again:
val df = sqlContext.createDataFrame(rdd)
df.registerTempTable("data")
val result = sqlContext.sql("select * from data order by time")
result.count
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.