在for-each循环/字符串被截断后,Scala变量重置

时间:2015-01-16 03:00:00

标签: string scala apache-spark

我正在做一个Spark项目。在下面的代码中,我有一个字符串,我用它来收集我的结果,以便稍后写入文件(我知道这不是正确的方法,我只是检查返回的Tuple3内的内容是什么一个方法)。每个循环后,字符串被截断。这是我的代码的相关部分:

val newLine = sys.props("line.separator") // also tried "\n". I am using OS X.

var str = s"*** ${newLine}"

for (tuple3 <- ArrayOfTuple3s) {
  for (list <- tuple3._3) {
    for (strItem <- list) {
      str += s"${strItem}, "
    }
    str += s"${newLine}"
  }
  str += s"${newLine}"
  println(tempStr)
}

print("str=" + str)

第一个println方法调用打印字符串的正确值(连接结果),但是当循环结束时,str的值为***(分配的值相同)在第一个循环之前到它。

修改:我将str不可变String对象替换为StringBuilder,但结果没有变化:

val newLine: String = sys.props("line.separator")

var str1: StringBuilder = new StringBuilder(15000)

for (tuple3 <- ArrayOfTuple3s) {
  for (list <- tuple3._3) {
    for (str <- list) {
      str1.append(s"${str}, ")
    }
    str1.append(s"${newLine}")
  }
  str1.append(s"${newLine}")
  println(str1.toString())
}

print("resulting str1=" + str1.toString())

编辑2:我映射了RDD以直接获取Tuple3的第三个字段。该字段本身是列表数组的RDD。我相应地更改了代码,但是我仍然得到相同的结果(结果字符串是空的,尽管在for循环中它不是)。

val rddOfArraysOfLists = getArrayOfTuple3s(mainRdd).map(_._3)

for (arrayOfLists <- rddOfArraysOfLists) {
  for (list <- arrayOfLists) {
    for (field <- list) {
      str1.append(s"${field}, ")
    }
    str1.append(" -- ")
  }
  str1.append(s"${newLine}")
  println(str1.toString())
}

编辑4:我认为问题不在于字符串。所有类型的变量似乎都存在问题。

var count = 0

for (arrayOfLists <- myArray) {
  count = arrayOfLists.last(3).toInt
  println(s"count=$count")
}

println(s"count=$count")

循环内的值为非零,但在循环外它为0。有什么想法吗?

编辑5:我无法发布整个代码(由于机密性限制),但这是其中的主要部分。如果重要的话,我在Intellij Idea的本地机器上运行Spark(用于调试)。

System.setProperty("spark.cores.max", "8")
System.setProperty("spark.executor.memory", "15g")    
val sc = new SparkContext("local", getClass.getName)            
val samReg = sc.objectFile[Sample](sampleLocation, 200).distinct

val samples = samReg.filter(f => f.uuid == "dce03545e8034242").sortBy(_.time).cache()

val top3Samples = samples.take(3)
for (sample <- top3Samples) {
  print("sample: ")
  println(s"uuid=${sample.uuid}, time=${sample.time}, model=${sample.model}")
}

val firstTimeStamp = samples.first.time
val targetTime = firstTimeStamp + 2592000 // + 1 month in seconds (samples during the first month)

val rddOfArrayOfSamples = getCountsRdd(samples.filter(_.time <= targetTime)).map(_._1).cache()
// Due to confidentiality matters, I cannot reveal the code, 
// but here is a description:
// I have an array of samples. Each sample has a few String fields 
// and is represented by a List[String]
// The above RDD is of the type RDD[Array[List[String]]]. 
// It contains only a single array of samples
// (because I passed a filtered set of samples to the function), 
// but it may contain more.
// The fourth field of each sample (list) is an increasing number (count)

println(s"number of arrays in the RDD: ${rddOfArrayOfSamples.count()}")

var maxCount = 0
for (arrayOfLists <- rddOfArrayOfSamples) {
  println(s"Last item of the array (a list)=${arrayOfLists.last}")
  maxCount = arrayOfLists.last(3).toInt
  println(s"maxCount=${maxCount}")
}
println(s"maxCount=${maxCount}")

输出:

示例:uuid = dce03545e8034242,时间= 1360037324,型号= Nexus 4

示例:uuid = dce03545e8034242,时间= 1360037424,型号= Nexus 4

示例:uuid = dce03545e8034242,时间= 1360037544,型号= Nexus 4

RDD中的数组数量:1

数组的最后一项(列表)=列表(dce03545e8034242,Nexus 4,1362628767,32,2089,0.97,0.15999999999999992,0)

MAXCOUNT = 32

MAXCOUNT = 0

2 个答案:

答案 0 :(得分:1)

在评论中将我的解释提升为答案:

请参阅this answer与某个相关的问题:

  

不要涉及太多细节,但是当你运行不同时   转换RDD(map,flatMap,filter等),你的   转换代码(闭包)是:

     

在驱动程序节点上序列化,
  运送到集群中的相应节点,
  反序列化,
  最后在节点上执行

代码中的for只是map的语法糖。

因此,每个执行更新的maxCount与调用程序中的maxCount不同。那个永远不会改变。

这里的教训是不要使用更新块外的变量的闭包(块)

答案 1 :(得分:0)

由于您没有发布完整的示例,我不得不对部分代码进行仲裁。

我做了第4次编辑:

val myArray = Array(
  List(List(0, 0, 0, 0), List(0, 0, 0, 0), List(0, 0, 0, 0)),
  List(List(1, 1, 1, 1), List(1, 1, 1, 1), List(1, 1, 1, 1)),
  List(List(2, 2, 2, 2), List(2, 2, 2, 2), List(2, 2, 2, 2))
)

在REPL中运行:

var count = 0

for (arrayOfLists <- myArray) {
  count = arrayOfLists.last(3).toInt
  println(s"count=$count")
}

println(s"count=$count")

我明白了:

scala> for (arrayOfLists <- myArray) {
     |   count = arrayOfLists.last(3).toInt
     |   println(s"count=$count")
     | }
count=0
count=1
count=2

scala> println(s"count=$count")
count=2

循环中的值非零是非零。

如果您发布完整的示例,也许我们可以为您提供更多帮助。