如何使用Spark-Scala中的takeOrdered(4)(Ordering[Int])
方法按2列或多列进行排序。
我可以使用sortBy实现这一点:
lines.sortBy(x => (x.split(",")(1).toInt, -x.split(",")(4).toInt)).map(p => println(p)).take(50)
但是当我尝试使用takeOrdered方法进行排序时,它失败了
答案 0 :(得分:1)
tl; dr 执行类似的操作(但请考虑重写代码以仅调用split
一次):
lines.map(x => (x.split(",")(1).toInt, -x.split(",")(4).toInt)).takeOrdered(50)
以下是解释。
当您直接在takeOrdered
上致电lines
时,生效的implicit Ordering
为Ordering[String]
,因为lines
为RDD[String]
。您需要将lines
转换为新 RDD[(Int, Int)]
。由于可以使用implicit Ordering[(Int, Int)]
,因此它会对您已转换的RDD
生效。
与此同时,sortBy
的工作方式略有不同。这是签名:
sortBy[K](f: (T) ⇒ K, ascending: Boolean = true, numPartitions: Int = this.partitions.length)(implicit ord: Ordering[K], ctag: ClassTag[K]): RDD[T]
我知道这是一个令人生畏的签名,但是如果你消除了噪音,你可以看到sortBy
采用的函数将原始类型映射到新类型仅用于排序目的如果一个人在Ordering
范围内,则对该返回类型应用implicit
。
在您的情况下,您正在将一项功能应用于String
中的RDD
,以将其转换为"视图" Spark如何仅仅为了排序目的而将它们视为即作为(Int, Int)
,然后依赖implicit Ordering[(Int, Int)]
如上所述的事实。
sortBy
方法可让您将lines
保持为RDD[String]
,并使用映射进行排序,同时takeOrdered
方法对全新进行操作 RDD
包含(Int, Int)
来自原始lines
的内容。无论哪种方法更适合您的需求取决于您希望实现的目标。
另外请注意,您可能只想将代码重写为split
一次。
答案 1 :(得分:0)
您可以实施自定义订购:
lines.takeOrdered(4)(new Ordering[String] {
override def compare(x: String, y: String): Int = {
val xs=x.split(",")
val ys=y.split(",")
val d1 = xs(1).toInt - ys(1).toInt
if (d1 != 0) d1 else ys(4).toInt - xs(4).toInt
}
})