【问题标题】:Checking if a 800million entry hashmap contains an element检查一个 8 亿条目的 hashmap 是否包含一个元素
【发布时间】:2013-03-20 03:57:04
【问题描述】:

我有一个哈希图,其中包含约 8 亿个条目(字符串)。它实际上被序列化成一个我已经进入 hashmap 的文件。

现在我有另一个巨大的字符串列表,大小约为 3500 万。我需要一个一个地读取这 3500 万个字符串,并以一种特定的方式对它们进行格式化,这种方式本身就是一个单独的方法(这是一个非常轻量级的处理)。

然后我需要检查对列表中的一个字符串进行格式化的结果是否已经存在于 hashMap 中。

在 Java 中最有效的方法是什么?

【问题讨论】:

  • 这不是 Java,但我会将它们推送到数据库中,并会在其上进行 JOIN... 8000 万行现在对于任何严重的 RDBMS 来说都几乎是不可能的。我建议使用 Postgres。
  • 标题说8亿,正文却说8000万。哪个是正确的?
  • 还有,元素是什么? ints? longs?还有什么?
  • 在 java 中最有效的方法是将数据放入数据库(可能是 MySQL)并使用 JDBC 访问它。
  • 我对所有这些对数据库的建议感到惊讶。由于数据已经存储在哈希图中,数据库(带有索引)不会提供太多好处(特别是如果这是一项一次性任务)。 3500万不是很多。您应该能够将所有哈希值存储在内存中。现在,对于第一组中的每个元素,检查它是否在第二组中。如果你能在内存中容纳 8000 万个哈希值,那就更好了。

标签: java algorithm data-structures


【解决方案1】:

您可以尝试使用布隆过滤器

一种节省空间的概率数据结构,用于测试元素是否是集合的成员。假阳性检索结果是可能的,但假阴性是不可能的;即查询返回“在集合内(可能是错误的)”或“绝对不在集合内”。

(引用自wikipedia

Google Guava 提供an implementation in java

【讨论】:

  • 我认为布隆过滤器不适用于这种情况。首先,布隆过滤器没有提供确切的答案。第二个 80/35 百万在布隆过滤器中编码很多(过滤器大小也需要以百万为单位才能获得任何实际优势。
  • @ElKamina:我猜 OP 将能够决定他是否可以处理一小部分误报,这只是一个想法。我没有对 Guava 实现的性能进行很多实验,但似乎人们确实使用它进行了数百万次插入,并且该类在早期版本中得到了很大改进,请参阅code.google.com/p/guava-libraries/issues/detail?id=892
【解决方案2】:

如果您必须将哈希函数保存在内存中,我将从改进哈希函数的开发方式开始。可以在 dzone 的 article 中找到很好的帮助资源

如果您不关心维护排序结构时可能引入的延迟,更进一步的方法是使用 Map 接口的另一个 implementation

【讨论】:

    【解决方案3】:

    如果您的大型数据集已经在您正在从磁盘反序列化的哈希表中并且您无法更改它,那么我怀疑您是否会比只做显而易见的事情并检查哈希做得更好直接表。任何将大型哈希表转换为另一种格式的方法都可能比按原样一次在表上进行所有查找更昂贵。 (约 3500 万次恒定时间操作,而至少 8 亿 + 3500 万次恒定时间操作和另一个可能不会好多少的常数,可能更多取决于您要使用的新格式。)

    如果存储大型数据集的表已经是线程安全的,并且运行程序的计算机有多个内核,则可以通过为每个内核运行一个查找线程来获得加速,但即使这样也可能由于协调开销以及每个单独的操作都非常便宜这一事实,因此不会加快速度(或者实际上可能会减慢速度)。

    您是否有能力改变大型数据集的准备方式?例如,与其把它写成一个散列集,你能把它写成别的东西吗?你能改变默认的散列函数吗?你知道你正在散列的字符串的属性,这些属性可以用来构建一个更便宜的散列函数吗?它们会在输入文件中以特定顺序出现吗?这类事情可能会被用来进行更快的查找,但相对于简单方法的显着加速可能将依赖于更多地了解您的问题的具体细节。

    【讨论】:

      猜你喜欢
      • 2017-08-04
      • 1970-01-01
      • 2010-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多