【问题标题】:Scala - ListBuffer emptying itself after every add in loopScala - ListBuffer 在每次添加循环后清空自身
【发布时间】:2016-03-25 05:41:25
【问题描述】:

我试图在循环中向 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,但它正在被清除。与垃圾收集有关吗?

【问题讨论】:

  • 你确定你只给generateStatistics打电话一次吗?
  • @JeanLogeart 是的,当然。
  • 附带说明,请使用 ListBuffer 作为 val 并使用 += (see here) 附加到它。这很奇怪,而且很难推理,因为您正在修改对象引用。

标签: scala apache-spark


【解决方案1】:

尝试将for (row &lt;- statsDf) 更改为for (row &lt;- statsDf.collect())

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

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

【讨论】:

    【解决方案2】:

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

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

    请参阅 the documentation 进行讨论。

    【讨论】:

      【解决方案3】:

      集合是可变的吗?

      另外,在使用 Scala 时,应该努力进行 FP。

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

      可能会完成您需要的工作。既然你有一个if,也许collect 会更合适

      【讨论】:

        猜你喜欢
        • 2014-04-11
        • 2014-10-31
        • 1970-01-01
        • 2015-03-19
        • 2017-09-05
        • 1970-01-01
        • 1970-01-01
        • 2017-10-29
        • 1970-01-01
        相关资源
        最近更新 更多