【问题标题】:Fast disk-based hashtables?基于磁盘的快速哈希表?
【发布时间】:2010-10-04 10:55:29
【问题描述】:

我有一组哈希(MD5 的前 64 位,因此它们的分布非常随机),我希望能够查看一个新的哈希是否在一个集合中,并将其添加到一个集合中。

集合不要太大,最大的有几百万个元素,但是集合有几百个,我记不住。

到目前为止我的一些想法:

  • 我尝试将其全部保存在 sqlite 表中,但一旦无法将所有内容都放入内存中,它就会变得非常慢。
  • 布隆过滤器听起来错误率非常高。我不介意微小的错误率(64 位哈希已经在 4G 元素集上产生了 1 次冲突),但是像 1% 这样的错误率太高了。
  • 在文件中保留有间隙的散列排序列表,并在我没有足够的间隙时调整大小。哈希是均匀分布的,所以即使是这样非常简单的方案也应该可以工作。

我是否遗漏了一些非常明显的东西?任何提示如何实现良好的基于​​磁盘的哈希表?

【问题讨论】:

  • 集合中的数据是否存在某种关联?大多数数据也可以在大多数其他集合中找到,还是恰好在一个集合中?
  • 如果您的未命中率非常高(即大多数查找是否定的),b-tree 或 cdb 前面的布隆过滤器仍然可以帮助您。因为您只需要磁盘查找 1% 的错误。

标签: hashtable


【解决方案1】:

这是我最终使用的解决方案:

  • 每组一个文件
  • 文件包含 2^k 个桶,每个 256 字节或 32 个 8 字节的条目
  • 空条目被清零(000... 是一个有效的散列,但我不关心 2^-64 的碰撞机会,如果所有内容都可以与其他所有内容发生冲突,则根据散列的性质)。
  • 每个哈希都驻留在通过其前 k 位猜测的存储桶中
  • 如果任何存储桶溢出,将文件大小加倍并拆分每个存储桶
  • 所有内容都通过 mmap() 访问,而不是 read()/write()

尽管它是低级 Perl 代码,但它比 sqlite 快得令人难以置信,而且 Perl 真的不适合高性能数据库。它不适用于比 MD5 分布更不均匀的任何东西,它假设一切都非常统一以保持实现简单。

我一开始用seek()/sysread()/syswrite()试了一下,很慢,mmap()版本真的快很多。

【讨论】:

  • >> 如果任何存储桶溢出,将文件大小加倍并拆分每个存储桶我听说过这种技术,但它究竟是如何工作的?
  • Nick:最简单的方法是创建一个新的空文件,遍历旧文件中的每个哈希并逐个添加它们。
  • 你是如何在文件中间填充桶的?插入后是否重新创建了新文件?
  • user12384512:你什么意思?它在初始化时用零填充整个文件,因此中间的存储桶是空的。
  • 对于大文件,mmap 会占用这么多内存来将整个文件加载到 ram 中?
【解决方案2】:

我在描绘您的确切问题/需求时遇到了一些麻烦,但它仍然让我想到了 Git 以及它如何在磁盘上存储 SHA1 引用:

采用给定哈希的十六进制字符串表示形式,例如“abfab0da6f4ebc23cb15e04ff500ed54”。将散列中的前两个字符(在我们的例子中为“ab”)切掉,并将其放入一个目录中。然后,使用其余的(“fab0da6f4ebc23cb15e04ff500ed54”),创建文件,然后将内容放入其中。

通过这种方式,您可以通过自动索引获得相当不错的磁盘性能(自然取决于您的 FS)。此外,您可以直接访问任何已知的哈希,只需在前两个字符 ("./ab/fab0da[..]") 后加入目录分隔符即可

如果我完全错过了球,我很抱歉,但如果运气好的话,这可能会给你一个想法。

【讨论】:

    【解决方案3】:

    听起来像是Berkeley DB 的工作。

    【讨论】:

    • 是的,我想过。它有令人讨厌的许可,但首先我想知道一旦超过可用内存,它是否真的会比 sqlite 更快。
    • BDB 提供了比 sqlite 更多的旋钮。由于您非常了解自己的数据,这可以为您提供所需的优势。最后,内存不足一个硬障碍,只有尝试一下才能回答你的问题。
    【解决方案4】:

    其他基于磁盘的散列算法/数据结构包括线性散列和可扩展散列。

    【讨论】:

      【解决方案5】:

      我首先想到了两种算法:

      • 使用b-tree
      • 通过使用散列的前 10 位索引到 1024 个单独文件中的一个来分离散列本身,每个文件都包含从这 10 位开始的所有散列的排序列表。这使您可以恒定时间跳转到应该适合内存的块,并在加载该块后进行 log(n) 搜索。 (或者您可以使用 8 位散列成 256 个文件等)

      【讨论】:

        【解决方案6】:

        由于您必须使用随机访问的哈希值,我怀疑任何数据库都会为您提供不错的性能。您最好的选择可能是增加磁盘缓存(更多 RAM),并获得具有非常高随机访问速度的硬盘(可能是固态磁盘)。

        【讨论】:

        • 我用一个非常简单的哈希表存储在磁盘上并通过 mmap() 访问 - 每个存储桶 32 个条目,任何存储桶溢出时文件大小加倍 - 它比 sqlite 快得令人难以置信,尽管我在 Perl 中实现它,它真的不适合这样的东西。
        猜你喜欢
        • 1970-01-01
        • 2022-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-08
        • 2020-07-14
        • 2017-09-18
        • 2013-09-12
        相关资源
        最近更新 更多