有没有一种有效的方法来统计Java中大量字符串的出现?

有没有一种有效的方法来统计Java中大量字符串的出现?,java,string,algorithm,memory,Java,String,Algorithm,Memory,我必须计算Java中不同字符串的重复次数。这些字符串可能是巨大的,来自多个数据源,并且大量的字符串是重复的 我只需要从那些每小时频率最高的字符串中得到20个 我考虑过计算每个字符串的出现次数,将它们存储在一个巨大的HashMap中,并使用优先级队列来保留最前面的字符串出现次数,但这也会消耗大量内存。在每小时开始时,旧的哈希映射将被删除,新的哈希映射将被创建以计算新小时的20个最频繁字符串。这可能会导致JVM花费很长时间对该内存进行垃圾收集 String#intern可能会有所帮助,但是HashM

我必须计算Java中不同字符串的重复次数。这些字符串可能是巨大的,来自多个数据源,并且大量的字符串是重复的

我只需要从那些每小时频率最高的字符串中得到20个

我考虑过计算每个字符串的出现次数,将它们存储在一个巨大的
HashMap
中,并使用
优先级队列
来保留最前面的字符串出现次数,但这也会消耗大量内存。在每小时开始时,旧的哈希映射将被删除,新的哈希映射将被创建以计算新小时的20个最频繁字符串。这可能会导致JVM花费很长时间对该内存进行垃圾收集

String#intern
可能会有所帮助,但是
HashMap
也是内存的一个问题,将来我也希望将聚合数据存储在堆外,但是字符串的不确定数量使得很难估计堆外内存以及存储这些字符串的方式。有什么建议可以避免堆外映射吗


我也对基数估计感兴趣,但似乎很难用它来计算每个字符串的复制次数。

答案是HashMap。它使用的内存比您想象的要少,因为映射包含对唯一字符串的引用,并且每个条目使用O(1)个空间。不必为每个字符串存储一个副本,因此映射不会比(唯一)字符串本身花费更多内存。只需累积每个字符串的总出现次数,并使用它来查找前20个


如果内存不足,则必须在磁盘上实现映射,例如关系数据库、NoSql或其他。使用映射(或类似于映射的结构)的原则是解决方法。

哈希映射就是答案。它使用的内存比您想象的要少,因为映射包含对唯一字符串的引用,并且每个条目使用O(1)个空间。不必为每个字符串存储一个副本,因此映射不会比(唯一)字符串本身花费更多内存。只需累积每个字符串的总出现次数,并使用它来查找前20个



如果内存不足,则必须在磁盘上实现映射,例如关系数据库、NoSql或其他。使用地图(或类似地图的结构)的原则是一条可行之路。

我认为,在这种情况下,使用番石榴的分类多重集更容易。您可以向它传递一个自定义比较器,以便轻松获取前20个条目(最频繁的字符串)。它使用与Map实现相同的内存量,并自动为您处理累积。

我认为,在这种情况下,使用Guava的SortedMultiset更容易。您可以向它传递一个自定义比较器,以便轻松获取前20个条目(最频繁的字符串)。它使用与映射实现相同的内存量,并自动为您处理累积。

您是否研究过使用
LinkedHashMap
?我正在尝试避免hashmap,LinkedHashMap可能会导致更多内存碎片,如果我想使用堆外数组,则更喜欢数组,就像count只是一个4字节数组一样,但是我怎样才能使用可估计内存来获得计数的顶端呢?从你的描述中还不清楚为什么你的哈希映射会占用大量内存。您将在其中存储多少不同的字符串,这些独特字符串的估计总长度是多少?请查看番石榴的SortedMultiset。您可以通过一个自定义比较器,这样您就可以轻松地找到前20个最常见的字符串。在任何情况下,都可以考虑一些类似ReDIS或基于磁盘的等价物。然后,您将不受VM堆大小的限制(如果使用基于磁盘的存储,则不受RAM/页面文件大小的限制)。但首先,请实际测试您的算法,看看它实际使用了多少内存,并在需要时增加堆大小。您是否研究过使用
LinkedHashMap
?我正在尝试避免hashmap,LinkedHashMap可能会导致更多内存碎片,如果我想使用堆外数组,则更喜欢数组,就像count只是一个4字节数组一样,但是我怎样才能使用可估计内存来获得计数的顶端呢?从你的描述中还不清楚为什么你的哈希映射会占用大量内存。您将在其中存储多少不同的字符串,这些独特字符串的估计总长度是多少?请查看番石榴的SortedMultiset。您可以通过一个自定义比较器,这样您就可以轻松地找到前20个最常见的字符串。在任何情况下,都可以考虑一些类似ReDIS或基于磁盘的等价物。然后,您将不受VM堆大小的限制(如果使用基于磁盘的存储,则不受RAM/页面文件大小的限制)。但首先实际测试您的算法,看看它实际使用了多少内存,并在需要时增加堆大小。在我以前的实现中,我使用哈希映射聚合用户的所有ip访问计数,按maxpriorityqueue排序,但这将消耗大量内存并导致内存碎片,因为在我的例子中,可能有这么多用户,所以每小时都会创建这么多子映射来存储ip访问信息。如果您正在寻找连续内存分配,Java不是适合您的语言。@daisydanngo您还没有告诉我们您需要多少搜索字符串。例如,10000个唯一的搜索字符串,如果你只使用一个普通的
HashMap
或任何东西,你将值集抓取到一个数组中,然后进行排序,它仍然不会在内存中留下任何凹痕,也不会花费超过几毫秒的时间。我们需要计算一个用户的顶级ip,ip的顶级用户也会分布到更多节点,但低缓存仍然存在在我以前的实现中,我使用哈希映射来聚合用户的所有ip访问计数,按maxpriorityqueue排序,但这将消耗大量内存并导致内存碎片,因为在我的情况下,可能会有这么多用户,所以每小时都会发生