有哪些有效的方法可以消除一组 100 万个字符串>重复数据?

What are some efficient ways to de-dupe a set of > 1 million strings?

本文关键字:字符串 万个 gt 数据 一组 方法 有效      更新时间:2023-10-16

对于我的项目,我需要非常有效地对非常大的字符串集进行重复数据消除。 即,给定一个可能包含重复项的字符串列表,我想生成该列表中所有字符串的列表,但没有任何重复项。

下面是简化的伪代码:

set = # empty set
deduped = []
for string in strings:
if !set.contains(string):
set.add(string)
deduped.add(string)

这是它的简化C++(大致(:

std::unordered_set <const char *>set;
for (auto &string : strings) {
// do some non-trivial work here that is difficult to parallelize
auto result = set.try_emplace(string);
}
// afterwards, iterate over set and dump strings into vector

但是,这对于我的需求来说还不够快(我已经仔细地对其进行了基准测试(。以下是一些使其更快的想法:

  • 使用不同的C++集实现(例如,绳降的(
  • 并发插入到集合中(但是,根据C++实现中的注释,这很难。此外,并行化会有性能开销(
  • 由于字符串集在运行中变化很小,因此无论哈希函数是否不生成冲突,都可以缓存。如果它没有生成任何内容(在考虑更改时(,则可以在查找期间通过其哈希值来比较字符串,而不是实际的字符串相等性(strcmp(。
  • 在运行过程中将去重复的字符串存储在文件中(但是,尽管这看起来很简单,但这里有很多复杂性(

我发现,所有这些解决方案要么非常棘手,要么没有提供那么大的加速。快速重复数据删除有什么想法吗?理想情况下,不需要并行化或文件缓存的东西。

您可以尝试各种算法和数据结构来解决问题:

  1. 尝试使用前缀树(trie(,后缀机器,哈希表。哈希表是查找重复项的最快方法之一。尝试不同的哈希表。
  2. 使用各种数据属性来减少不必要的计算。例如,只能处理具有相同长度的字符串子集。
  3. 尝试实现"分而治之"方法来并行计算。例如,将字符串集除以等于硬件线程的子集数。然后将这些子集合并为一个。由于子集的大小将在此过程中减小(如果重复项的数量足够大(,因此组合这些子集应该不会太昂贵。

不幸的是,这个问题没有通用的方法。在很大程度上,决策取决于所处理数据的性质。在我看来,我清单上的第二项是最有希望的。始终尝试减少计算以使用较小的数据集。

您可以通过手动实现简化版本的std::unordered_set来显著并行化您的任务:

  1. 创建任意数量的存储桶(可能应与线程池中的线程数成比例或等于(。
  2. 使用线程池并行计算字符串的哈希值,并用它们的哈希值拆分字符串。添加字符串时,您可能需要锁定单个存储桶,但操作应简短和/或您可以使用无锁结构。
  3. 使用线程池单独处理每个存储桶 - 比较哈希值,如果它们相等,则比较字符串本身。

您可能需要试验存储桶大小并检查它会如何影响性能。从逻辑上讲,它不应该在一侧太大,但在另一侧不应该太小 - 以防止拥堵。

顺便说一句,从您的描述中可以看出,您将所有字符串加载到内存中,然后消除重复项。您可以尝试将数据直接读取到std::unordered_set,这样您就可以节省内存并提高速度。