在Scala中对RDD中的值进行排序

时间:2019-05-21 01:37:16

标签: scala apache-spark rdd

我有一个RDD,其中的键是一个ID,值包括ID列表。我想按升序对值列表进行排序 例如

1, list(12,3,8,10)
2, list(42,3,65,33)
3, list(6,2,4,1)

输出

1, list(3,8,10,12)
2, list(3,33,42,65)
3, list(1,2,4,6)

RDD创建 因此,我在加入两个不同的RDD之后创建了RDD,然后使用它productIterator创建了list of values,这给了我RDD(Int, List[Any])类型的RDD。

我尝试过 rdd.mapValues(x=> _.2.sorted)不同的排序方法,但没有运气

1 个答案:

答案 0 :(得分:2)

您快到了。

顾名思义,

mapValues仅将映射功能应用于值。您的代码看起来像您正在尝试从键/值元组中提取第二个元素,我想这会引发错误。

您可以使用mapmapValues。如果您希望保留密钥,map需要返回一个元组,因此mapValues比较简单,但是我将向您展示两种方式。因此,我们从已经构建的RDD[(Int, List[Int])]开始,然后使用collect()进行查看。

scala> start
res17: org.apache.spark.rdd.RDD[(Int, List[Int])] = MapPartitionsRDD[6] at map at <console>:37

scala> start.collect()
res18: Array[(Int, List[Int])] = Array((1,List(12, 3, 8, 10)), (2,List(42, 3, 65, 33)))

首先,让我们做最简单的事情:

scala> start.mapValues(x => x.sorted).collect()
res19: Array[(Int, List[Int])] = Array((1,List(3, 8, 10, 12)), (2,List(3, 33, 42, 65)))

如您所见,它将返回您期望的顺序。

使用地图修改键/值元组非常简单,只要您保留键即可。我建议使用Scala的case函数语法将元组分解为命名参数,而不必引用tuple._1 / tuple._2

scala> start.map({ case (k, v) => (k, v.sorted) }).collect()
res21: Array[(Int, List[Int])] = Array((1,List(3, 8, 10, 12)), (2,List(3, 33, 42, 65)))

但是使用您熟悉的元组语法:

scala> start.map(x => (x._1, x._2.sorted)).collect()
res22: Array[(Int, List[Int])] = Array((1,List(3, 8, 10, 12)), (2,List(3, 33, 42, 65)))

我希望这会有所帮助。 编辑,因为您的问题似乎是由于缺少类型信息所致,所以我添加了如何创建用于场景运行的RDD。

val input: Array[Array[Int]] = Array(Array(1, 12, 3, 8, 10), Array(2, 42, 3, 65, 33))

val start: RDD[(Int, List(Int)] = sc.parallelize(input).map({ 
  case Array(key, value @ _*) => (key, value.toList)
})

如果查看List.sorted的方法签名,则会看到它具有一个隐式参数,该参数告诉Scala如何对列表进行排序。

Scala为数字和字符串之类的东西提供默认实现,但是它根据List的类型查找隐式实现。它没有默认的Any列表,这与Java中的Object列表等效。因此,如果您可以修改问题以包含更多代码,则将有助于确定丢失该类型信息的位置。