【问题标题】:finding items to de-duplicate查找要重复数据删除的项目
【发布时间】:2013-07-22 14:59:46
【问题描述】:

我有一个数据池 (X1..XN),我想为其找到相等值的组。比较非常昂贵,我无法将所有数据都保存在内存中。

我需要的结果是,例如:

X1 等于 X3 和 X6
X2 是唯一的
X4 等于 X5

(行的顺序或行内的顺序无关紧要)。

如何通过成对比较来实现它?


这是我目前所拥有的:

比较所有对 (Xi, Xk) 与 i and 利用传递性:如果我已经找到 X1==X3 和 X1==X6,我不需要比较 X 3 和 X6

所以我可以使用以下数据结构:

  map: index --> group
  multimap: group --> indices

其中组是任意分配的(例如输出中的“行号”)。

对于具有 i i, Xk) 对:

  • 如果 i 和 k 都已经分配了一个组,则跳过

  • 如果它们比较相等:

    • 如果我已经分配了一个组,请将 k 放入该组
    • 否则,为 i 创建一个新组并将 k 放入其中
  • 如果它们不相等:

    • 如果我还没有分配组,请为 i 分配一个新组
    • k 也一样

如果我对项目的顺序很小心,那 应该 工作,但我想知道这是否是解决这个问题的最佳/最不令人惊讶的方法,因为这个问题似乎有些普遍。


背景/更多信息:目的是对项目的存储进行重复数据删除。他们已经有一个哈希值,如果发生冲突,我们希望保证完全比较。相关数据的大小具有非常尖锐的长尾分布。

迭代算法(找到任意两个重复项,共享它们,重复直到没有重复项)可能更容易,但我们需要非修改诊断。 代码库是 C++,与 STL / boost 容器或算法一起工作的东西会很好。

[edit] 关于散列:为了这个问题,请假设一个无法替换的弱散列函数。

这是对现有数据进行一次性重复数据删除所必需的,并且需要处理哈希冲突。最初的选择是“快速散列,并在碰撞时比较”,选择的散列有点弱,但改变它会破坏向后兼容性。即便如此,我还是用一个简单的语句睡得更好:如果发生碰撞,您不会得到错误的数据。 而不是写关于 wolf attacks 的博客。

【问题讨论】:

  • 使用一个好的散列函数,碰撞的概率大约为零,所以你应该只担心所有项目相等的常见情况。
  • “一次性...向后兼容”这没有意义。
  • @DavidEisenstat:这是一个信任问题,而不是概率问题。万亿分之一的碰撞造成的直接损害可能可以忽略不计,让客户相信这是完全不同的事情。
  • @DavidEisenstat:当前的格式已经允许重复数据删除,但仅在少数“简单”的情况下才可以。对于大多数用户来说,这将是一次透明的维护操作——除非他们经常在新旧版本之间切换。
  • 我并不是建议您可以省略昂贵的检查,只是在加密哈希比较相等之后对其进行优化可能是浪费时间,除了非“狼攻击”情况。

标签: c++ algorithm language-agnostic deduplication


【解决方案1】:

这是另一种可能更简单的利用传递性的数据结构。做一个你需要做的比较队列。例如,如果有 4 个项目,它将是 [ (1,2), (1,3), (1,4), (2,3), (2,4), (3,4) ] .还有一个数组用于您已经完成的比较。在每次比较之前,检查之前是否进行过比较,每次找到匹配项时,通过队列并将匹配项的索引替换为其较低的索引等效项。

例如,假设我们弹出 (1,2),比较,它们不相等,将 (1,2) 推入 already_visited 的数组并继续。接下来,pop (1,3) 并发现它们相等。此时,通过队列并将所有 3 替换为 1。队列将是 [(1,4), (2,1), (2,4), (1,4)] 等等。当我们到达(2,1)时,它已经被访问过,所以我们跳过它,和(1,4)一样。

但我确实同意前面的答案。由于比较的计算量很大,您可能希望首先计算一个快速、可靠的哈希表,然后才将此方法应用于冲突。

【讨论】:

  • 我没有最终使用它 - 但接受了,因为你把我推向了正确的方向 :) map<id, shared_ptr< set<id> > > 对于每个出现多次的哈希,在所有人之间共享 set<id>instances数据。 --- 因为“主”应用程序保证在哈希冲突的情况下进行比较,这个维护操作也可以;如前所述,这不是概率,而是信任问题。
【解决方案2】:

所以...你已经有了一个哈希?这个怎么样:

  • 按哈希排序和分组
  • 将大小为 1 的所有组打印为唯一组
  • 比较碰撞

比较 colisions 的提示:为什么不使用不同的算法重新哈希它们?冲洗,重复。

(我假设您在此处存储文件/blob/图像并具有它们的哈希值,并且您可以将哈希值放入内存中,而且哈希值类似于 sha1/md5 等,因此不太可能发生冲突)

(另外,我假设两种不同的哈希算法不会在不同的数据上发生冲突,但这可能是安全的假设......)

【讨论】:

    【解决方案3】:

    对每个项目进行哈希处理。列出pair<hash,item_index>。您可以通过按哈希排序此列表或将其放入std::multimap 来查找组。

    当您输出组列表时,您需要比较哈希冲突的项目。 因此,对于每个项目,您将进行一次哈希计算和一次比较。和哈希列表的排序。

    【讨论】:

    • 但是,如果您有超过 2 个具有相同哈希的项目,我们又回到了最初的问题,在这种情况下,您需要对每个项目进行多个比较。
    • 散列冲突在散列良好的情况下很少见,因此每个项目将大约进行一次比较。我已将about 添加到我的答案中。
    【解决方案4】:

    我同意使用第二个(希望是改进的)哈希函数的想法,这样您就可以解决一些弱哈希的冲突,而无需进行昂贵的成对比较。既然您说您遇到内存限制问题,希望您可以将整个哈希表(带有辅助键)放入内存中,对于表中的每个条目,您存储磁盘上与该键对应的记录的记录索引列表一对。那么问题是对于每个密钥对,是否可以将所有记录加载到具有该密钥对的内存中。如果是这样,那么您可以迭代密钥对;对于每个密钥对,释放内存中前一个密钥对的所有记录,并为当前密钥对加载内存中的记录,然后像您已经概述的那样在这些记录之间进行比较。如果您有一个无法将所有记录都放入内存的密钥对,那么您将不得不加载部分子集,但您绝对应该能够在内存中维护所有组(每个组都有一个唯一的记录代表)您已经找到了密钥对,因为如果您有一个良好的二级哈希,那么唯一记录的数量将会很少。

    【讨论】:

      猜你喜欢
      • 2014-11-02
      • 1970-01-01
      • 1970-01-01
      • 2012-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-23
      • 1970-01-01
      相关资源
      最近更新 更多