如何将大HashMap <string,integer =“”>拆分为较小的</string,>

时间:2014-07-16 10:17:24

标签: java algorithm dictionary data-structures

一个HashMap<String, Integer>的大小为50,000;而且,它不能同时适合记忆。我希望将这张大表分成int chunkSize = 1024大小的小表。结果,我试图编写一个方法,但我天真的方法是迭代大表并创建一个小方法。然而,天真的迭代方法是O(n)并且它是开放的bug,因为它没有使用内置的Java方法,只是迭代表。您是否有解决此问题的方法,以便解决方案具有时间效率,并且更依赖于Java内置方法。

更新:我将使用这些较小的hashMap来提供给Pipeline系统。管道系统采用管道设计模式设计。对于每个阶段,将应用一些String操作和Text数据挖掘算法。拆分Big HashMap将为旧应用程序和未来的管道系统增加价值。实际上,分流操作现在是管道系统的一部分;但是,对于旧的应用程序,我已经开始阅读如何微调HashMap内部结构。

3 个答案:

答案 0 :(得分:2)

由于您在评论中提到要存储单词频率/出现次数,我建议使用以下数据结构:

使用树。树中的每个节点都将包含一个字母,并具有频率值。 Root将是空单词的表示,每个节点将表示从根开始的单词。在这个树中,查找/更新频率需要与单词一样多的步骤,与单词的数量无关。

如果这棵树对于内存来说太大了,那么一个简单的分区将是树中的第一个级别,这是每个单词的第一个字母。您可以将其存储在不同的文件中。

如果您需要更精细的粒度,可以使用第一个字母作为文件夹名称,第二个字母作为文件名在这些文件夹中等。

答案 1 :(得分:2)

如果您使用HashMap<String, Integer>来表示单词频率,则代表50,000个条目应该没有问题。如果有,那么显而易见的解决方案是增加Java堆大小。 (使用-Xmx命令行选项执行此操作。)

(如果我的心算是正确的,HashMap的开销类似于每个条目8个单词......加上键和值对象占用的空间。在你的情况下,这可能会增加~25个单词,包括假设典型英语单词的关键和值。在32位JVM中总共大约5Mb。)

但是要回答您的问题,Java标准库中没有用于将HashMap拆分为较小HashMaps的方法或类。

答案 2 :(得分:1)

如果您有单词频率,则值得使用可变长度以避免重复创建新对象。这不会对使用的内存产生太大影响,但会降低GC。

public static void main(String... ignored) {
    StringBuilder sb = new StringBuilder();
    // start with as much free memory as possible.
    System.gc();

    long start = memoryUsed();
    Map<String, long[]> frequencyMap = new HashMap<>();
    int keys = 50 * 1000;
    for (int i = 0; i < keys; i++) {
        sb.setLength(0);
        sb.append("word-").append(i);
        String key = sb.toString();
        long[] count = {i};
        frequencyMap.put(key, count);
    }
    long used = memoryUsed() - start;
    System.out.printf("To create a map with " + frequencyMap.size() + " key/values used %,d KB%n", used / 1024);
}

public static long memoryUsed() {
    return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
}

使用-Xmn1g -XX:-UseTLAB打印

运行
To create a map with 50000 key/values used 6,895 KB

除非你有一个7 MB远远的系统,否则我会把这么小的地图放在一块。