Scala迭代器/循环技术-大型集合

Scala迭代器/循环技术-大型集合,scala,iterator,Scala,Iterator,我有很大的制表符分隔文件10GB-70GB,需要对一个单独的文件进行读、数据操作和写操作。文件的范围从100到10K列,有200万到500万行 前x列是静态的,需要参考。示例文件格式: #ProductName Brand Customer1 Customer2 Customer3 Corolla Toyota Y N Y Accord Honda Y Y N Civic

我有很大的制表符分隔文件10GB-70GB,需要对一个单独的文件进行读、数据操作和写操作。文件的范围从100到10K列,有200万到500万行

前x列是静态的,需要参考。示例文件格式:

#ProductName  Brand    Customer1  Customer2  Customer3
Corolla       Toyota   Y          N          Y
Accord        Honda    Y          Y          N
Civic         Honda    0          1          1
我需要使用前两列获取产品id,然后生成类似以下内容的输出文件:

ProductID1 Customer1 Y
ProductID1 Customer2 N
ProductID1 Customer3 Y
ProductID2 Customer1 Y
ProductID2 Customer2 Y
ProductID2 Customer3 N
ProductID3 Customer1 N
ProductID3 Customer2 Y
ProductID3 Customer3 Y
当前示例代码:

val fileNameAbsPath = filePath + fileName
val outputFile = new PrintWriter(filePath+outputFileName)
var customerList = Array[String]()

for(line <- scala.io.Source.fromFile(fileNameAbsPath).getLines()) {
    if(line.startsWith("#")) {
        customerList = line.split("\t")
    }
    else {
        val cols = line.split("\t")

        val productid = getProductID(cols(0), cols(1))
        for (i <- (2 until cols.length)) {
            val rowOutput = productid + "\t" + customerList(i) + "\t" + parser(cols(i))

            outputFile.println(rowOutput)
            outputFile.flush()
        }
    }
}
outputFile.close()
我运行的其中一个测试花费了大约12个小时来读取一个70GB的文件,该文件有300万行和2500列。最终的输出文件生成了250GB,大约有8亿多行

我的问题是:在Scala中,除了我正在做的工作之外,还有什么可以提供更快性能的吗?

好的,一些想法

正如评论中提到的,您不希望在每行之后都刷新。所以,是的,摆脱它。 此外,默认情况下,PrintWriter会在每行换行后刷新,因此,当前,您实际上刷新了两次:。创建PrintWriter时,请使用双参数构造函数,并确保第二个参数为false 您不需要显式创建BufferedWriter,默认情况下PrintWriter已经在缓冲。默认缓冲区大小是8K,您可能想尝试使用它,但它可能不会有任何区别,因为我上次检查时,底层FileOutputStream会忽略所有这些,并以任何方式刷新KB大小的块。 不要将行粘在一个变量中,只需将每个字段直接写入输出即可。 如果您不关心行在输出中的显示顺序,那么您可以简单地并行处理如果您确实关心顺序,您仍然可以(稍微不那么简单)一次编写多个文件。如果您将输出块放在不同的磁盘上和/或如果您有多个内核来运行此代码,这将非常有帮助。您需要在真正的scala中重写代码以使其线程安全,但这应该足够简单。 在写入数据时压缩数据。例如,使用GZipOutputStream。这不仅可以减少实际命中磁盘的数据量,还可以提供更大的缓冲区 看看你的解析器在做什么。您没有显示实现,但有消息告诉我它可能不是免费的。 在巨大的字符串上,split可能会非常昂贵。人们常常忘记,它的参数实际上是一个正则表达式。您最好编写一个自定义迭代器,或者只使用好的旧StringTokenizer在运行时解析字段,而不是在前面拆分字段。至少,每行可以为您节省一次额外扫描。
最后,最后,但决不是最不重要的。考虑使用火花和HDFS。这类问题正是这些工具真正擅长的领域。

这看起来很像一项任务,它不适合作为一个问题。如果我误解了,我很抱歉,但我只是在寻找想法,而不是有人帮助我编写代码。。我是scala的新手,我想知道它是否能提供更好的性能。我个人会将处理头行的if子句移出for循环。如果知道标题行只出现一次,则无需对每一行执行检查。第二,除非你真的想确保你不想错过任何写入,否则每次写入刷新都会降低性能,我会先使用BufferedWriter和PrintWriter,让他们负责刷新脏位。根据,在单个字符上拆分是相当快的。@OlegPyzhcov是的。。。但仍然需要创建一个包含2500列的数组,并在前面填充它。如果这就是你否决我答案的原因,那么。。。你是个混蛋:不,只是指出了一件奇怪的、不太广为人知的事情,你的回答很好,我支持投票人:@OlegPyzhcov好吧,很抱歉怀疑你: