我试图找出Scala的哈希函数在大型哈希表中的扩展程度(数十亿条目,例如存储特定DNA出现的频率)。
然而,有趣的是,HashMap和OpenHashMap似乎都忽略了指定初始大小的参数(2.9.2。和2.10.0,最新版本)。
我认为这是因为在第一次800.000之后添加新元素变得慢得多。
我试过增加要插入的字符串中的熵(下面代码中只有字符ACGT),没有效果。
有关此特定问题的任何建议吗?我也很高兴听到您对使用Scala的内置类型是否适合具有数十亿条目的哈希表的看法。
import scala.collection.mutable.{ HashMap, OpenHashMap }
import scala.util.Random
object HelloWorld {
def main(args: Array[String]) {
val h = new collection.mutable.HashMap[String, Int] {
override def initialSize = 8388608
}
// val h = new scala.collection.mutable.OpenHashMap[Int,Int](8388608);
for (i <- 0 until 10000000) {
val kMer = genkMer()
if(! h.contains(kMer))
{
h(kMer) = 0;
}
h(kMer) = h(kMer) + 1;
if(i % 100000 == 0)
{
println(h.size);
}
}
println("Exit. Hashmap size:\n");
println(h.size);
}
def genkMer() : String =
{
val nucs = "A" :: "C" :: "G" :: "T" :: Nil
var s:String = "";
val r = new scala.util.Random
val nums = for(i <- 1 to 55 toList) yield r.nextInt(4)
for (i <- 0 until 55) {
s = s + nucs(nums(i))
}
s
}
}
答案 0 :(得分:3)
我不会使用Java数据结构来管理数十亿条目的地图。原因:
如果是我,我会看一个堆外解决方案:某种数据库。如果您只是存储(哈希码,计数),那么可能有效的许多键值存储之一。最大的障碍是找到一个可以支持数十亿条记录的记录(最多可以支持2 ^ 32)。
如果你能接受一些错误,概率方法可能值得一看。我在这里不是专家,但列出here的内容听起来很相关。
答案 1 :(得分:2)
这些是错误的数据结构。你会很快达到一个ram限制(除非你有100 + gb,即便如此,你仍然会很快达到限制)。
我不知道scala是否存在合适的数据结构,尽管有人可能会使用Java做一些事情。
答案 2 :(得分:2)
首先,你不能覆盖initialSize,我认为scala让你,因为它在HashTable中是私有的包:
private[collection] final def initialSize: Int = 16
其次,如果要设置初始大小,则必须为其提供所需初始大小的HashTable。因此,如果没有从16开始构建这个地图真的没有好办法,但它确实以2的幂增长,所以每次调整大小都会变得更好。
第三,scala集合相对较慢,我建议使用java / guava / etc集合。
最后,数十亿条目对于大多数硬件来说有点多,你可能会耗尽内存。你很可能需要使用内存映射文件,这是一个很好的例子(尽管没有散列):
https://github.com/peter-lawrey/Java-Chronicle
更新1 这里有一个很好的替代java集合:
https://github.com/boundary/high-scale-lib
更新2 我运行你的代码,它确实减慢了大约800,000个条目,但后来我提高了Java堆大小,它运行良好。尝试使用类似于jvm的东西:
-Xmx2G
或者,如果你想使用你记忆的最后一点:
-Xmx256G