Spark:在mapPartitionsWithIndex中调用一个函数

时间:2018-06-07 00:23:28

标签: scala apache-spark

使用以下代码我得到了非常奇怪的结果。 我只想获取分区数据并迭代每个数据X次。

我在这里为每个分区调用我的函数:

val myRDDResult = myRDD.mapPartitionsWithIndex( myFunction(_, _, limit), preservesPartitioning = true)

功能是:

private def myFunction (partitionIndex: Long,
                          partitionData: Iterator[Array[(LabeledPoint,Int,Int)]]), limit: Int): Iterator[String] = {

    var newData = ArrayBuffer[String]()
    if (partitionData.nonEmpty){
        val partDataMap = partitionData.next.map{ case (lp, _, neighId) => (lp, neighId) }.toMap
        var newString:String = ""
        for {
            (k1,_) <- partDataMap
            i  <- 0 to limit
            _ = {
             // ... some code to generate the content for `newString`
            newData.+=(newString)
           }
        }yield ()
    } 
    newData.iterator
}

以下是获得的一些值:

partitionData   limit   newData   newData_expected
1640            250     411138   410000 (1640*250)
16256           27      288820   438912

我不知道我是否误解了我的代码的一些概念。

我也尝试更改for这个想法的部分:partDataMap.map{elem=> for (i <- 0 to limit){....}}

有什么建议吗?

1 个答案:

答案 0 :(得分:2)

首先,抱歉,因为我对你的问题进行了投票/上调(点击错误),因为我没有在10分钟内取消它,所以保持了它的投票。

关于你的代码,我认为你的预期结果很糟糕,因为我使用了与你相同的代码,简化了一点,而不是接收 410000 元素,我得到 411640 < / em>的。也许我复制了一些不正确的东西或忽略了一些东西,但给出411640的代码看起来像:

val limit = 250
val partitionData: Iterator[Array[Int]] = Seq((1 to 1640).toArray).toIterator
var newData = ArrayBuffer[String]()
if (partitionData.nonEmpty){
  val partDataMap = partitionData.next.map{ nr => nr.toString }

  for {
    value <- partDataMap
    i  <- 0 to limit
    _ = {
      newData.+=(s"${value}_${i}")
    }
  } yield ()
}
println(s"new buffer=${newData}")
println(s"Buffer size =  ${newData.size}")

现在回答您关于为什么mapWithPartitions结果与您的期望不同的问题。 IMO,因为您从Array转换为Map。如果在您的阵列中有重复键,它将只计数一次。它可以解释为什么在这两种情况下(如果我们将411640视为正确的预期数字),您会得到低于预期的结果。为确保您可以将partDataMap.sizepartitionData.next.size进行比较。