如何使用takeOrdered对多列进行排序?

时间:2017-04-22 08:53:28

标签: scala apache-spark

如何使用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方法进行排序时,它失败了

2 个答案:

答案 0 :(得分:1)

tl; dr 执行类似的操作(但请考虑重写代码以仅调用split一次):

lines.map(x => (x.split(",")(1).toInt, -x.split(",")(4).toInt)).takeOrdered(50)

以下是解释。

当您直接在takeOrdered上致电lines时,生效的implicit OrderingOrdering[String],因为linesRDD[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
  }
})