【问题标题】:Java HashMap/List alternative for huge data大数据的 Java HashMap/List 替代方案
【发布时间】:2015-10-29 06:40:05
【问题描述】:

在我的 Java 应用程序中,我必须扫描文件系统并递归存储已创建文件的路径以进行早期搜索。

我尝试使用 List/ArrayList 和 HashMap 作为存储结构,但是当文件系统包含 1.000.000+ 个文件时,内存使用量过多。

如何在不使用一半 RAM (8 GB) 的情况下存储和快速检索这些“字符串”?

【问题讨论】:

  • 我建议将该数据转储到文件或数据库中。一个纯文本文件就足够了
  • 您多久扫描一次文件系统?我们可以说它是恒定的吗?
  • 是的,我已经尝试过 DB,但我失去了“速度”,因为在执行过程中我需要多次搜索单个条目。带有 containsKey 的 HashMap 在 O(1) 时间内给我一个结果,但 DB 没有。
  • 没有 sibnick,这个文件系统可以改变...每次扫描都可以不同
  • @user3357127 - 具有 1.000.000+ 条记录的 hashmap 几乎总是会发生冲突,因此效率不会是 O(1)

标签: java memory hashmap


【解决方案1】:

您正在主内存中存储大量字符串。无论您使用何种数据结构,它都会占用内存。一种方法可能不是一直存储整个路径,而是将它们存储在分层结构中,例如。将目录的名称作为键存储在地图中,并将该目录的所有值作为值递归存储在列表中。

【讨论】:

    【解决方案2】:

    在全局哈希图中,您可以存储指向 Dir-Objects 的指针,而不是将完整路径存储为字符串。

    为您找到的每个目录创建一个 Dir 对象。每个 Dir-object 都有一个指向其父 Dir-object 及其本地名称的指针。

    例子:

    /a/long...path/p/   is a Dir you already found.
    /a/long...path/p/a
    /a/long...path/p/b  are two new Dirs
    

    两个子目录只需要存储对父目录的引用加上它们的本地名称“a”或“b”。

    请注意,您不必首先找到父对象:扫描文件系统时,您应该递归地执行此操作或显式使用堆栈。当您创建一个 Dir 对象(例如此处的 /p)时,您然后将该对象推送到堆栈上,然后您访问(进入)该目录。当您创建 /a 和 /b 子目录时,您只需查看堆栈顶部即可找到它们的父目录。当您处理完 /a/long...path/p/ 的全部内容后,您将代表它的 Dir 对象从堆栈中弹出。

    【讨论】:

    • 如果我存储对象如何快速搜索到我的 hashmap 的路径?循环将非常耗时..
    • 我想我必须更好地解释我的情况:我有一个存储路径的 SQL DB,然后我扫描文件系统,我必须检查我找到的每个文件,如果这个文件(确切路径)是已经在我的数据库中。我正在寻找一种快速且低内存使用的方式...
    • @user3357127 您可以将哈希图中的多个引用存储到 Dir-Object。示例:如果您访问/a/long...path/p/b/x.txt,那么您可以在哈希映射键x.txtb 下存储对它的引用。然后,您需要一个多哈希图或在每个哈希图条目中存储一个向量。
    • 是的,但问题是可以找到许多 x.txt 文件...key 将被覆盖
    • @user3357127 对于这种情况,您需要一个多哈希图或在每个哈希图条目中存储一个向量。然后向量条目引用 Dir-objs。
    【解决方案3】:

    这个问题可以有很多答案。人们可以为您提供广泛的数据结构以供使用,或者可能会要求您增加硬件内存或 JVM 的堆大小。但我认为问题出在其他地方。

    仅使用基本数据结构无法解决此问题。这也可能需要在设计级别进行更改。想想你的需要。您要求的空间如此巨大,而今天的操作系统甚至是存储大量数据的 RDBMS 都不需要。

    数据结构即服务。(DSAS - 它已经存在,例如 redis,但是我可能已经创造了这个术语!)。

    在您的应用程序设计中,尝试引入一个组件或服务,如 redis、memcached 或 couchdb,它们专门用于“存储大量数据”、通过标准套接字或其他高速通信协议(如 DBUS)进行“快速搜索”等.

    不要担心此类协议的内部工作。有足够的库/api 可以为您完成。

    【讨论】:

    • Redis 我认为可能是一个好方法!我看到还有它的java api(jedis),但我不明白它是创建一个永久的'db'还是只是在运行时每个程序运行......
    • redis 也有创建永久数据库的配置。请查看redis.io/topics/persistence 了解更多信息。
    【解决方案4】:

    我可以建议您使用 HashSet 并将 md5 和存储为路径:

    Set<Md5Sum> paths = new HashSet<>();
    //for each path
    String path = ...
    byte[] md5 = messageDigestObject.update(path.getBytes());
    path.add(new Md5Sum(md5));
    

    您不能将byte[] 直接用作哈希集中的键。所以你需要创建简单的帮助类:

    class Md5Sum{
        //it is more memory effiecient than byte[]
        long part1, part2;
        //override equals and hashCode methods
        //..........
    }
    

    关于更新

    您需要重新扫描文件系统并重新创建此哈希集对象,或者您可以订阅文件系统事件(请参阅WatchService)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-31
      • 1970-01-01
      • 2011-04-27
      • 2012-06-06
      • 1970-01-01
      • 2014-12-15
      相关资源
      最近更新 更多