从列表中删除重复项而不将列表存储在内存中

时间:2015-08-02 06:03:53

标签: java performance scala out-of-memory

我试图找到一种有效的方法来从文件中删除重复行而不将文件的全部内容读入内存。该文件是随机排序的。我试图不把它读入内存因为文件太大(20GB +)。任何人都可以建议一种方法来修复我的代码,以便它不会将整个文件读取到内存中吗?

val oldFile="steam_out_scala.txt"
val noDupFile="nodup_steam_out.txt"

import scala.io.Source
import java.io.{FileReader, FileNotFoundException, IOException}
import java.io.FileWriter;
import scala.collection.mutable.ListBuffer

var numbers = new ListBuffer[String]()
val fw = new FileWriter(noDupFile, true) 

for (line <- Source.fromFile(oldFile).getLines()) {
    numbers+=line

}

numbers.distinct.foreach((x)=>{
    //println(x)
    fw.write(x)
})
fw.close()    

我对数据的了解:

  • 每一行都是Long ex:76561193756669631
  • 它没有订购,最终结果不需要以任何方式订购
  • 该列表是使用其他程序生成的。可以重复一个数字(0,4百万)

  • 2 个答案:

    答案 0 :(得分:1)

    有几种方法可以解决这个问题:

    1)逐行读取原始文件,然后将其添加到仅包含唯一行的新文件中,如果已存在此行,则检入该文件。这会非常慢,因为O(n^2)

    代码看起来像这样:

    val oldFile="steam_out_scala.txt"
    val noDupFile="nodup_steam_out.txt"
    
    import scala.io.Source
    import java.io.{FileReader, FileNotFoundException, IOException}
    import java.io.FileWriter;
    import scala.collection.mutable.ListBuffer
    
    var numbers = new ListBuffer[String]()
    val fw = new FileWriter(noDupFile, true) 
    
    for (line <- Source.fromFile(oldFile).getLines()) {
        if(Source.fromFile(noDupFile).getLines().forall(!_.equals(line))) {
            fw.write(line)
        }
    }
    
    fw.close()
    

    2)你可以执行一个所谓的external sort,它是为了排序大量不适合内存的数据而发明的,比上述方法更快。它对整个数据集的小块进行排序(可以放入内存中),将它们存储到临时文件中,然后将它们合并在一起。有趣的是,如果您的操作系统具有虚拟内存选项,那么操作系统将为您执行类似的操作,无论如何都要将不适合内存的数据交换到硬盘驱动器。

    这些是适用于任何类型数据的通用解决方案。如果您可以提供有关文件内容的更多信息,我们可能会提供更聪明的内容。

    答案 1 :(得分:0)

    您可以使用bloom过滤器(https://en.m.wikipedia.org/wiki/Bloom_filter)删除文件中的重复内容