我正在尝试在循环中向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,但它已被清除。与垃圾收集有关吗?
答案 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
,或使用广播变量。
答案 2 :(得分:0)
该集合是否可变?
另外,当使用Scala时,应该努力做FP。
df.schema.fieldNames.map {...}
可能会做你需要的工作。因为你有一个if
,所以collect
可能会更加适合