针对集合中的每个项目运行函数

时间:2014-05-09 21:38:17

标签: scala apache-spark

我有数据类型:

counted: org.apache.spark.rdd.RDD[(String, Seq[(String, Int)])] = MapPartitionsRDD[24] at groupByKey at <console>:28

我正在尝试将以下内容应用于此类型:

def func = 2

counted.flatMap { x => counted.map { y => ((x._1+","+y._1),func) } }

因此,将每个序列相互比较并应用函数。为简单起见,函数只返回2.当我尝试上面的函数时,我收到这个错误:

scala> counted.flatMap { x => counted.map { y => ((x._1+","+y._1),func) } }
<console>:33: error: type mismatch;
 found   : org.apache.spark.rdd.RDD[(String, Int)]
 required: TraversableOnce[?]
              counted.flatMap { x => counted.map { y => ((x._1+","+y._1),func) } }

如何使用Spark?

应用此功能

我试过了

val dataArray = counted.collect
dataArray.flatMap { x => dataArray.map { y => ((x._1+","+y._1),func) } }

将集合转换为Array类型并应用相同的函数。但是当我尝试这种方法时,我的内存耗尽了。我认为使用RDD比使用数组效率更高?我可以分配的最大内存量是7g,是否有一种火花机制我可以使用硬盘内存来增加可用的RAM内存?

我正在运行此功能的集合包含20'000个条目,因此20'000 ^ 2比较(400'000'000)但是在Spark方面这个很小?

2 个答案:

答案 0 :(得分:2)

简短回答:

counted.cartesian(counted).map {
  case ((x, _), (y, _)) => (x + "," + y, func)
}

请使用模式匹配来提取嵌套元组的元组元素,以避免不可读的链式下划线表示法。使用_作为第二个元素会向读者显示这些值被忽略。

如果func没有使用第二个元素,那么更具可读性(也许更有效)的是:

val projected = counted.map(_._1)
projected.cartesian(projected).map(x => (x._1 + "," + x._2, func))

请注意,如果你的lambda适合单个语义行,那么你不需要大括号,这在Scala中是一个非常常见的错误

我想知道为什么你希望拥有这种笛卡尔产品,通常有办法避免这样做,这些产品具有更高的可扩展性。请说明您将如何处理这款笛卡尔产品,我将尝试找到一种可扩展的方式来做您想做的事。

最后一点; 请在运营商之间添加空格

答案 1 :(得分:1)

@RexKerr指出我在评论部分有点不正确,所以我删除了我的评论。但是在这样做的时候,我又有机会再次阅读这篇文章,并提出了可能对你有用的想法。

由于您尝试实现的实际上是对笛卡尔积的某些操作,您可能只想尝试调用RDD#cartesian。这是一个愚蠢的例子,但如果你能提供一些真实的代码,也许我也可以在这种情况下做这样的事情:

// get collection with the type corresponding to the type in question:
val v1 = sc.parallelize(List("q"-> (".", 0), "s"->(".", 1), "f" -> (".", 2))).groupByKey
// try doing something
v1.cartesian(v1).map{x => (x._1._1+","+x._1._1, 2)}.foreach(println)