HashSet of Strings占用了太多内存,建议......?

时间:2010-07-12 11:31:43

标签: java memory

我目前正在HashSet中存储一个单词列表(大约120,000个),目的是使用列表来检查被激活的单词,以查看它们是否拼写正确,只返回是或否。

我想知道是否有办法做到这一点,占用更少的内存。目前120,000个单词约为12meg,单词读取的实际文件大约为900kb。

有什么建议吗?

提前致谢

8 个答案:

答案 0 :(得分:10)

您可以使用前缀树或特里:http://en.wikipedia.org/wiki/Trie

答案 1 :(得分:6)

查看布隆过滤器或布谷鸟哈希。 Bloom filter or cuckoo hashing?

我不确定这是否是您问题的答案,但值得研究这些替代方案。布隆过滤器主要用于拼写检查器的用例。

答案 2 :(得分:4)

HashSet可能不是正确的结构。请改用Trie

答案 3 :(得分:2)

这可能有点晚了但是使用谷歌你可以很容易地找到我刚刚发布的DAWG调查和C代码。

http://www.pathcom.com/~vadco/dawg.html

TWL06 - 178,691字 - 符合494,676字节

压缩共享节点结构的缺点是它不能作为列表中单词的哈希函数。也就是说,它会告诉你一个单词是否存在,但它不会返回一个确实存在的单词的相关数据的索引。

如果您想要完美和完整的哈希功能,在处理器缓存大小的结构中,您将不得不阅读,理解和修改名为ADTDAWG的数据结构。它会比传统的DAWG略大,但它更快,更实用。

http://www.pathcom.com/~vadco/adtdawg.html

一切都很好,

JohnPaul Adamovsky

答案 4 :(得分:2)

12MB来存储120,000个字,每个字大约100个字节。可能至少32个字节是字符串开销。如果单词平均为10个字母并且它们存储为2字节字符,则会占另外20个字节。然后是对HashSet中每个String的引用,这可能是另外4个字节。剩下的44个字节可能是HashSet条目和索引开销,或者我上面没有考虑过的。

最简单的事情是String对象本身的开销,它可以占用比存储实际字符数据所需的内存更多的内存。因此,您的主要方法是开发一个自定义表示,避免为每个字符串存储单独的对象。在执行此操作的过程中,您还可以摆脱HashSet开销,因为您真正需要的只是一个简单的单词查找,这可以通过对将成为自定义实现的一部分的数组进行简单的二进制搜索来完成。 / p>

您可以将自定义实现创建为int类型的数组,每个单词都有一个元素。这些int元素中的每一个都将被分成子字段,这些子字段包含长度和指向char类型的单独支持数组的偏移量。将这两者放入管理它们的类中,并支持公共方法,允许您在给定字符串索引和可选字符索引的情况下检索和/或转换数据和单个字符,并在单词列表上执行简单搜索这是您的拼写检查功能所需要的。

如果您的基础字符串数据不超过16777216个字符(例如,120,000个字符串乘以10个字符的平均长度= 120万个字符),您可以获取每个int的低位24位并存储起始偏移量将每个字符串放入char数据的后备数组中,并取每个int的高位8位并存储相应字符串的大小。

你的char数据会把你以前的字符串塞进去而没有任何分隔符,完全依赖于int数组来知道每个字符串的开始和结束位置。

采用上述方法,您的120,000个单词(平均每个10个字母)将需要大约2,400,000个字节的后备阵列数据和480,000个字节的整数索引数据(120,000 x 4个字节),总计2,880,000个字节,这比你上面报告的目前的12MB金额节省了大约75%。

数组中的单词将按字母顺序排序,您的查找过程可以是int数组上的简单二进制搜索(从每个测试的char数组中检索相应的单词),这应该非常有效。

如果您的单词恰好是完全ASCII数据,则可以通过将后备数据存储为字节而不是字符来节省额外的1,200,000个字节。

如果您需要更改这些字符串,这可能会变得更加困难。显然,在你的情况下(拼写检查),你不需要(除非你想支持用户添加到列表中,无论如何都不常见,因此重写char数据和索引以添加或删除单词可能是可以接受的)。

答案 5 :(得分:1)

节省内存以节省内存的一种方法是使用radix tree。这比trie好,因为前缀不会冗余存储。

当你的字典被修复时,另一种方法是为它构建一个完美的哈希函数。您的哈希集不需要桶(以及相关的开销),因为不会发生冲突。使用open addressing的哈希表/哈希集的每个实现都可以用于此(如谷歌集合的ImmutableSet)。

答案 6 :(得分:0)

问题在于设计:出于拼写检查原因在HashSet中存储如此大量的单词并不是一个好主意:

您可以使用拼写检查程序(例如:http://softcorporation.com/products/spellcheck/),也可以使用前缀树(说明:http://en.wikipedia.org/wiki/Trie)构建“auto-wordcompletion”。

在此设计中无法减少内存使用量。

答案 7 :(得分:0)

您还可以尝试Radix TreeWikiImplementation)。这有些像trie,但内存效率更高。