删除多个和大型字典文件中的重复单词

时间:2013-01-31 05:56:30

标签: algorithm sorting memory-management gpu dictionary

这些年来,我已经积累了大约600GB的词典,我决定要清理它们并对它们进行排序

首先,每个文件平均非常大,大小从500MB到9GB不等。我想要做的先决条件是我对每个字典进行排序。我的最终目标是在整个 所有字典文件中完全删除和中的重复字词

这样做的原因是我的大多数词典都按类别排序和组织,但仍然经常存在重复词。

Load file
     Read each line and put into data structure
     Sort and remove any and all duplicate
Load next file and repeat

Once all files are individually unique, compare against eachother and remove duplicates

对于词典D {1}到D {N}:

1)分别通过 D {N} D {1} 进行排序。

2)检查 D {i}

中每个单词的唯一性

3)对于 D {i} 中的每个字,请检查 D {i + 1} D {N} 的所有字词。如果首先在 D {i} 中删除,则删除每个单词。

  • 我正在考虑使用某种“哈希”来改进这种算法。可能只检查前一个或两个字符,因为列表将被排序(例如,以a,b等开头的单词的哈希起始行位置)。

4)保存并退出。

之前的例子(但要小得多):

    Dictionary 1            Dictionary 2            Dictionary 3

    ]a                      0u3TGNdB                2 KLOCK
    all                     avisskriveri            4BZ32nKEMiqEaT7z
    ast                     chorion                 4BZ5
    astn                    chowders                bebotch
    apiala                  chroma                  bebotch
    apiales                 louts                   bebotch
    avisskriveri            lowlander               chorion
    avisskriverier          namely                  PC-Based
    avisskriverierne        silking                 PC-Based
    avisskriving            underwater              PC-Based

因此,它会看到avisskriveri,chorion,bebotch和PC-Based是在三个词典中的每一个内部和之间重复的词。所以我首先在 D {1} 中看到avisskriveri,所以在我看过的所有其他实例中删除它。然后我首先在 D {2} 中看到chorion,并首先在所有其他实例中删除它,依此类推。在 D {3} bebotch和PC-Based被复制,所以我想删除除了一个条目之外的所有条目(除非我以前见过它)。然后保存所有文件并关闭。

之后的例子:

     Dictionary 1           Dictionary 2            Dictionary 3

     ]a                     0u3TGNdB                2 KLOCK
     all                    chorion                 4BZ32nKEMiqEaT7z
     ast                    chowders                4BZ5
     astn                   chroma                  bebotch
     apiala                 louts                   PC-Based
     apiales                lowlander                   
     avisskriveri           namely              
     avisskriverier         silking                 
     avisskriverierne       underwater                          
     avisskriving 

请记住:我不想创建任何新词典,只删除所有词典中的重复词。

选项:

  • “散列”每个文件的唯一单词数量,允许程序估算计算时间。

  • 指定一种方式,以第一个字母开头,以第一个字母开头。这样搜索可以“跳”到一行并跳过不必要的计算时间。

  • 在GPU上运行以实现高性能并行计算。 (这是一个问题,因为从GPU中获取数据很棘手)

目标:减少计算时间和空间消耗,以便在标准机器或能力有限的服务器上实现该方法。或设备一种在GPU集群上远程运行它的方法。

tl; dr - 在数百个文件中对唯一字进行排序,每个文件的大小为1-9GB。

4 个答案:

答案 0 :(得分:1)

我从以下内容开始:

#include <string>
#include <set>

int main()
{
    typedef std::set<string> Words;
    Words words;
    std::string word;
    while (std::cin >> word)
        words.insert(word);  // will only work if not seen before
    for (Words::const_iterator i = words.begin(); i != words.end(); ++i)
        std::cout << *i;
}

然后只是:

cat file1 file2... | ./this_wonderful_program > greatest_dictionary.txt

假设非重复单词的数量适合内存(可能在任何现代PC上,特别是如果你的64位和> 4GB),这应该没问题,这可能是I / O绑定,所以没有点烦恼无序地图vs(二叉树)地图等。您可能希望在插入地图之前转换为小写,剥离虚假字符等。

编辑:

如果唯一的单词不适合内存,或者你只是顽固地决定对每个单独的输入进行排序然后合并它们,你可以在每个文件上使用unix sort命令,然后{{1}有效地合并预先排序的文件。如果你不在UNIX / Linux上,你可能仍然可以找到sort -m的端口(例如来自Cygwin for Windows),你的操作系统可能有一个等效的程序,或者你可以尝试编译sort源代码。请注意,这种方法与tb-要求调用sort对一切进行排序(可能是在内存中)的建议略有不同 - 我不确定它的效果如何,所以最好尝试/比较

答案 1 :(得分:1)

在300GB +的规模上,您可能需要考虑使用Hadoop或其他可扩展存储 - 否则,您将不得不通过自己的编码处理内存问题。您可以尝试其他更直接的方法(UNIX脚本,小型C / C ++程序等),但除非数据中有大量重复的单词,否则可能会耗尽内存。

<强>附录

刚刚遇到memcached这似乎与你想要完成的事情非常接近:但你可能不得不调整而不是来丢弃最旧的值。我现在没时间检查,但您应该在 Distributed Hash Tables 上进行搜索。

答案 2 :(得分:1)

假设词典按字母顺序逐行排列,每行一个单词(和大多数词典一样),你可以这样做:

Open a file stream to each file.
Open a file stream to the compiled list file.
Read 1 entry from each file and put it onto a heap, priority queue, or other sorted data structure.
while you still have entries
    find & remove the first entry, storing the word (it is not necessary to store the file)
    read in the next entry from that file, if one exists
    find & remove any duplicates of the stored entry
    read in the next entry for each of those files, if one exists
    write the stored word to your compiled list file
Close all of the streams

效率类似O(n * m * log(n)),空间效率为O(n),其中n是文件数,m是平均条目数。

请注意,您需要创建一个数据类型,将条目(字符串)与文件指针/引用配对,并按字符串存储进行排序。你还需要一个允许你在弹出之前偷看的数据结构。

如果您对实施有疑问,请问我。

对效率进行更全面的分析:

空间效率非常简单。您填写数据结构,对于您放置的每个项目,您取一个,因此它保持在O(n)。

计算效率更复杂。循环本身是O(n * m),因为您将考虑每个条目,并且有n * m个条目。其中有一部分是有效的,但这是一个常数,所以我们不在乎。

接下来,在优先级队列中添加和删除都是log(n)两种方式,因此要查找&amp;删除是2 * log(n)。

因为我们添加和删除每个条目,我们得到n * m add和remove,所以O(n * m * log(n))。我认为在这种情况下它实际上可能是一个theta,但是meh。

答案 3 :(得分:1)

据我了解,没有一种模式可以巧妙地利用。所以我们想做原始排序。

让我们假设没有可用的集群服务器场(我们可以做其他事情)

然后我会从最简单的方法开始,即命令行工具sort

  

排序-u inp1 inp2 -o sorted

这会将inp1inp2排在输出文件sorted中,而不会重复(u =唯一)。 Sort通常使用自定义的mergesort算法,该算法可以处理有限的内存量。所以你不应该遇到记忆问题 您应该至少有600 gb(两倍大小)的可用磁盘空间 您应该只使用2个输入文件进行测试需要多长时间以及会发生什么。我的测试没有显示任何问题,但他们使用了不同的数据和afs服务器(这是一个相当慢的,但是作为一些HPC文件系统提供商是一个更好的模拟):

$ ll
2147483646 big1
2147483646 big2

$ time sort -u big1 big2 -o bigsorted
1009.674u 6.290s 28:01.63 60.4% 0+0k 0+0io 0pf+0w

$ ll
2147483646 big1
2147483646 big2
 117440512 bigsorted