我必须计算Java中不同字符串的重复次数。这些字符串可能很大,来自多个数据源,并且会重复大量字符串。
我需要从每小时频率最高的那些字符串中获得20个。
我考虑计算每个字符串的出现次数,将它们存储在一个巨大的HashMap
中,并使用PriorityQueue
来保持顶部字符串的出现,但这也会占用大量内存。在每小时开始时,将删除旧的哈希映射,将创建新的哈希映射以计算新时间的20个频率最高的字符串。这可能导致JVM花费很长时间来垃圾收集内存。
String#intern
可能会有所帮助,但HashMap
也是内存的问题,将来我也希望将聚合数据存储在堆外,但不确定的不确定数量是字符串使得很难估计堆外内存和存储这些字符串的方法。是否有任何建议可以避免堆外地图?
我也对基数估算感兴趣,但似乎很难用它来计算每个字符串的复制次数。
答案 0 :(得分:4)
HashMap就是答案。它使用的内存比您想象的少,因为映射将引用保存到唯一的字符串,并且每个条目使用O(1)空间。没有必要存储每个字符串的一个副本,因此映射不会比(唯一)字符串本身花费更多的内存。只需累积每个字符串的总出现次数,并使用它来查找前20个字符串。
如果内存不足,则必须在磁盘上实现映射,例如关系数据库或NoSql或其他内容。使用地图(或类似地图的结构)的原则是要走的路。
答案 1 :(得分:2)
我认为来自Guava的SortedMultiset在这种情况下更容易使用。您可以将它传递给自定义Comparator,以便您可以轻松获取前20个条目(最常见的字符串)。它使用与Map实现相同的内存量,并自动为您处理累积。