Scala - ListBuffer在每次添加循环后清空自身

时间:2016-03-24 14:59:45

标签: scala apache-spark

我正在尝试在循环中向Scala ListBuffer添加一些对象,但每次添加一个它都会在循环的下一次迭代中消失。

当我在添加新条目之前和之后打印ListBuffer的内容时,我得到以下输出:

  

添加前:ListBuffer()

     

添加后:ListBuffer(com.me.FeatureV2@20d953ba)

     

添加前:ListBuffer()

     

添加后:ListBuffer(com.me.FeatureV2@6b768ce7)

     

添加前:ListBuffer()

     

添加后:ListBuffer(com.me.FeatureV2@123f42d5)

代码:

def generateStatistics(df: DataFrame): List[FeatureV2] = {
    var features = ListBuffer[FeatureV2]()
    val dataColumn = "data"
    for (field <- df.schema.fieldNames){
      val columnType: String = df.select(field).dtypes(0)._2

      if (columnType == StringType.toString){
        val statsDf: DataFrame = getStats(df, field, dataColumn)
        for (row <- statsDf){
          println("Before add: " + features)
          val feature = new FeatureV2()
          feature.element = row.getString(0)
          feature.count = row.getLong(1)
          feature.sum = row.getDouble(2)
          feature.max = row.getDouble(3)
          feature.min = row.getDouble(4)
          feature.feature = field
          features += feature
          println("After add: " + features)
        }
      }
    }
    features.toList
  }

但有时,我得到以下内容:

  

添加前:ListBuffer()

     

添加后:ListBuffer(com.me.FeatureV2@1433183c)

     

之前添加:ListBuffer(com.me.FeatureV2@1433183c)

     

添加:ListBuffer(com.me.FeatureV2@1433183c,   com.me.FeatureV2@4b0df9e5)

     

添加前:ListBuffer()

     

添加后:ListBuffer(com.me.FeatureV2@1e201b19)

这看起来实际上正在填充ListBuffer,但它已被清除。与垃圾收集有关吗?

3 个答案:

答案 0 :(得分:3)

尝试将for (row <- statsDf)更改为for (row <- statsDf.collect())

如果这可以解决您的问题,那么您的问题可能是由foreach在一个或多个线程中运行的事实引起的。

for (row <- stadsDf)实际上是DataFrame.foreach(f: Row => Unit),它是一个分布式foreach,其中f可以在任意数量的线程或机器上运行,具体取决于您的Spark母版。

答案 1 :(得分:2)

Spark应用程序由驱动程序和执行程序组成。您可以从驱动程序控制和创建内容 - 执行程序获取范围内变量的副本。因此,执行者获得ListBuffer的副本。它们会附加到副本中,这些副本在任务完成时会丢失。

您可以使用collect()将数据拉入驱动程序以附加到ListBuffer,或使用广播变量。

请参阅 enter image description here 进行讨论。

答案 2 :(得分:0)

该集合是否可变?

另外,当使用Scala时,应该努力做FP。

df.schema.fieldNames.map {...}

可能会做你需要的工作。因为你有一个if,所以collect可能会更加适合