0

我有一个非常大的文件(10^8 行),其中事件计数如下,

A 10
B 11
C 23
A 11

我需要累积每个事件的计数,以便我的地图包含

A 21
B 11
C 23

我目前的做法:

读取行数,维护一张地图,并更新地图中的计数如下

updateCount(Map<String, Long> countMap, String key,
            Long c) {
        if (countMap.containsKey(key)) {
            Long val = countMap.get(key);
            countMap.put(key, val + c);
        } else {
            countMap.put(key, c);
        }
    }

目前这是代码中最慢的部分(大约需要 25 毫秒)。请注意,地图基于 MapDB,但我怀疑更新速度会因此而变慢(是吗?)

这是地图的 mapdb 配置,

DBMaker.newFileDB(dbFile).freeSpaceReclaimQ(3)
                .mmapFileEnablePartial()
                .transactionDisable()
                .cacheLRUEnable()
                .closeOnJvmShutdown();

有没有办法加快这个速度?

编辑

唯一键的数量与维基百科中的页面顺序相同。数据实际上是来自这里的页面流量数据。

4

3 回答 3

0

如果您使用的是 TreeMap,则有一些性能调整选项,例如

  1. 每个节点中的条目数。
  2. 您还可以使用特定的键和值序列化程序来加速序列化和反序列化。
  3. 您可以使用 Pump 模式来构建树,速度非常快。但需要注意的是,当您从头开始构建新地图时,这很有用。你可以在这里找到完整的例子

https://github.com/jankotek/MapDB/blob/master/src/test/java/examples/Huge_Insert.java

于 2014-08-22T20:38:23.973 回答
0

作为一个起点,我建议考虑:

  • 您说 25 毫秒实际上对于所涉及的数据量和通用地图实现而言是不合理的时间量是什么标准?如果你量化它,它可能会帮助你解决是否有任何问题。
  • 与其他操作相比,重新散列地图花费了多少时间(例如计算每个 put 的散列码)?
  • 你所说的“事件”是由什么组成的?有多少独特的事件——以及独特的钥匙——有多少?地图的键是如何生成的,有没有更有效的方法呢?(例如,在标准哈希映射中,您为每个关联创建附加对象,并实际存储增加内存占用的关键对象。)
  • 根据前面的答案,您可能会自己推出更有效的地图结构(请参阅这个您可能能够适应的示例)。本质上,您需要专门查看花费时间的内容(例如,每次放置的哈希码计算/重新哈希的成本)并尝试优化该部分。
于 2014-08-19T15:40:42.807 回答
0

你可以试试

class Counter {
    long count;
}

void updateCount(Map<String, Counter> countMap, String key, int c) {
    Counter counter = countMap.get(key);
    if (counter == null) {
        counter = new Counter();
        countMap.put(key, counter);
        counter.count = c;
    } else {
        counter.count += c;
    }
}

这不会创建很多 Long 包装器,而只是为 Counters 分配键的数量。

注意:不要创建 Long 的。上面我做了c一个 int 来不监督 long/Long。

于 2014-08-19T15:23:59.443 回答