2

我想存储大约 20 亿个字符串的哈希值。为此,我想使用尽可能少的存储空间。

考虑一个理想的散列算法,它将散列返回为一系列十六进制数字(如 md5 散列)。据我了解这个想法,这意味着我需要哈希不小于且不超过 8 个符号的长度。因为这样的散列能够散列 4+ 十亿(16 * 16 * 16 * 16 * 16 * 16 * 16 * 16)不同的字符串。

所以我想知道将哈希切割到一定长度以节省空间是否安全?(当然,哈希不应该冲突)

是/否/也许-我希望能提供相关研究的解释或链接的答案。

Ps - 我知道我可以测试 8 个字符的哈希是否可以存储 20 亿个字符串。但我需要将 20 亿个哈希值与它们的 20 亿个切割版本进行比较。这对我来说似乎并不重要,所以我最好在这样做之前先问清楚。

4

2 回答 2

0

哈希是一个数字,而不是一串十六进制数字(字符)。在 MD5 的情况下,它是以有效形式保存的 128 位或 16 字节。如果您的问题仍然存在,您当然可以考虑截断数字(通过强制转换为一个单词或第一个位移)。好的散列算法均匀地分配到所有位。

附录:

通常,每当您处理哈希时,您都想检查字符串是否真的匹配。这处理了碰撞哈希的可能性。你削减的哈希越多,你就会得到越多的冲突。但最好为在这个阶段发生的事情做好计划。

于 2013-04-30T13:56:53.440 回答
0

将x值存储在只能表示2x个不同哈希值的哈希域中是否安全完全取决于您是否可以容忍冲突。

哈希函数实际上是随机数生成器,因此您计算的 20 亿个哈希值将平均分布在 40 亿个可能的结果中。这意味着您会遇到生日问题

在您的情况下,如果您仅使用 2^32(40 亿)个可能的哈希值计算 2^31(20 亿)个哈希,则至少两个具有相同哈希(冲突)的机会非常非常接近 100%。(而且三个相同的可能性也非常非常接近 100%。等等。)我找不到根据这些数字计算可能发生碰撞次数的公式,但我怀疑这是一个巨大的数字.

如果在您的情况下哈希冲突不是灾难(例如在 Java 的 HashMap 实现中,它通过将哈希目标转换为共享相同哈希键的对象列表来处理冲突,尽管以降低性能为代价)那么也许您可以肯定会发生大量碰撞。但是,如果您需要唯一性,那么您需要一个大得多的散列域,或者您需要为每条记录分配一个保证唯一的序列号,具体取决于您的目的。

最后,请注意,Keccak 能够生成任何所需的输出长度,因此花费 CPU 资源生成长散列输出只是为了在之后将其缩减是没有意义的。你应该能够告诉你的 Keccak 函数只给出你需要的位数。(另请注意,Keccak 输出长度的更改不会影响初始输出位,因此结果将与您之后进行手动按位修剪完全相同。)

于 2017-05-24T08:40:52.083 回答