【问题标题】:Java: fast disk-based hash setJava:基于磁盘的快速哈希集
【发布时间】:2010-02-27 08:47:59
【问题描述】:

我需要存储一个大哈希集,最多可以包含大约 2 亿个 40 位值。将其存储为 2 亿个 64 位值是可以接受的(尽管有 2 亿个 * 16 位丢失)。

要求是:

  • 很小的内存占用(磁盘空间不是问题,内存是问题)

  • 快速的contains(long l)add(long l) 方法(比SQL 快得多)

  • 嵌入式

  • 免费且没有令人讨厌的许可(没有 Berkeley DB)。 LGPL 很好。

  • 没有误报也没有误报,所以像基于磁盘的布隆过滤器之类的东西不是我所追求的

SQL 不是我在这里所追求的。

因为我真的认为我更喜欢这样的快速(请注意该解决方案比 SQL 解决方案快得多):

Fast disk-based hashtables?

Google 有这样的 Java API 吗?

我只使用“键”的基于磁盘的快速键/值对实现是否可行?

还是别的什么?

我宁愿不重新发明轮毂。

【问题讨论】:

  • 2亿大约是28位。
  • @Thorbjorn:我说的是存储 2 亿个值,每个值都是 40 位。我从来没有谈论过存储可能包含高达 2 亿价值的价值 :)
  • 出于好奇,你用SQLite等试过了吗?在您链接的问题中,我没有看到任何证据表明 OP 关闭了日记功能,甚至创建了索引...
  • @Steven Huwig:不,我指定 SQL 不是我所追求的……当我在谈论某件事时 fast 我想到了更多类似 Peter 的答案Lawrey 提出 :) 您是否真的认为与花时间调整 SQLite 相关的答案会接近已接受的答案,具体说明它正在绕圈运行 SQL?我们不关心关系属性,也不关心 ACID 保证等。对于这样简单的问题,SQL 是一个 massive 过度膨胀。换句话说,是一把金锤。
  • @Steven Huwig:我们正在使用 Java 进行高性能计算(实际上,Java 擅长于此)。游戏的名字是优化。我问了一个非常具体的,不太粗鲁的问题,并明确表示 SQL 不是我所追求的。我不喜欢“SQL”和“XML”类型的答案。我正在寻找像彼得劳里那样的答案。

标签: java hashset disk-based


【解决方案1】:

如果您负担得起 128 GB 的磁盘,您可以每 40 位值存储一位。 然后,您可以使用随机访问文件来检查某个位是否已设置或更改。您不必插入任何值或维护索引。

【讨论】:

  • @Peter Lawrey:有趣...有趣的是,在此之前,我还有另一个问题,我问什么是 Java 中实现大文件随机查找的最快方法 :) 遗憾的是在我的情况下是不可行的:这必须安装在多台计算机上。几 GB 还可以,但 128 太多了 :( 我喜欢上面所说的方法...
  • 您也可以使用布隆过滤器,它大约需要 6 位才能实现 1% 的误报率来检测密钥是否存在。如果这是您正在寻找的操作。如果数据是静态的,那么高扇出的树也是可能的。
【解决方案2】:

尝试 sg-cdb(djb 的 cdb 的奇怪 gizmo 端口),然后将 RandomAccessFile 换成 BufferedRandomAccessFile(在 jai-imageio 代码中有一个很好的)。

我得到了令人兴奋的写入性能。通过屋顶(因为它全部被缓冲然后一举提交)。 不过,缓冲 RAF 的读取性能没有改变。

我可以花时间与 H2 批量导入进行比较,虽然不确定,但可能具有可比性。

数据库很简单:key => value。仅在键上支持查找。 就我而言,密钥是(base32 编码的随机整数 + base32 编码的唯一整数),因此本地化应该不会有太大帮助。这些值是 120 个随机字节的数组。

加载(sql 插入)

h2,带 131MB 缓存(包括刷新,不启动):

2011 年 5 月 4 日晚上 11:45:10 测试。TestH2Simple 主要 :插入执行添加时间:101625 毫秒

数据库大小: 大约 140 MB

批量大小:2000 :插入执行添加时间:116875 毫秒

批量大小:10000 : insertsperformed 添加时间:70234 毫秒

与 cdb 的 sg-cdb(奇怪的 gizmo)端口比较:

使用 RandomAccessFile: 插入不冲洗:21688 毫秒,冲洗:30359 毫秒,总计:52047 毫秒 磁盘上文件的大小: 66.1 MB(69,315,632 字节)

使用 BufferedRandomAccessFile: 大约 6.5 秒

当然,这并不是一个真正公平的比较,因为 H2 在插入过程中不断刷新数据,而 sg-cdb 不是。在进行比较时必须牢记这一点。比较 sg-cdb insert 和 H2 bulk insert 可能比较公平

读取(sql 选择)

sg-cdb

:搜索:490000 完成时间:1304544550439 耗时:17547 毫秒,计数器:0

H2

:选择在:19579 毫秒内执行

关于内存映射文件: 他们似乎不是你要找的。 MMap 文件的出色性能是当您将大约 100MB 或更多的内存映射到内存时(我的经验)。

【讨论】:

    【解决方案3】:

    我相信您将需要使用 B 树而不是哈希表。哈希表没有很好的辅助存储局部性,因此您将在磁盘 I/O 上浪费太多时间。

    大多数数据库(无论是否关系)都将其索引实现为 B 树,因此您所说的相当于存储一个没有附加数据的索引。

    您是否会有多个进程同时更新此数据存储?

    【讨论】:

      猜你喜欢
      • 2010-10-04
      • 2022-10-14
      • 1970-01-01
      • 2017-09-18
      • 2015-01-11
      • 2011-08-26
      • 1970-01-01
      • 2020-07-14
      • 2019-01-15
      相关资源
      最近更新 更多