基于按位与的 就散策略
总览
编年史有很多用于哈希的实现,包括City和Murmur。 它也有自己的香草哈希,但是如何测试呢?
什么是香草哈希?
Vanilla Hash设计得尽可能简单,并且针对Orthogonal Bits测试进行了优化(请参见下文),并与City 1.1和Murmur 3哈希策略进行了比较。
这是用新数据填充64字节/ 256字节缓冲区并生成64位哈希值的99%延迟。 JMH用于执行测量。 请参阅Main64bytes和Main256bytes
散列策略 | 64字节99%瓦片 | 256字节99%瓦片 |
---|---|---|
香草 | 67 ns | 112毫微秒 |
城市1.1 | 90纳秒 | 182 ns |
杂音3 | 104毫微秒 | 211 ns |
- 完整的测试结果在这里。
您可以执行哪些测试来检查哈希策略是否良好?
您可以执行许多简单的测试。 测试无法识别出良好的哈希,但可以将哈希显示为不良哈希。 通过一项测试可能意味着它将通过另一项测试。
在每种情况下,都使用不同的随机起点运行多个测试。 分数为第99%,即最差的1%。 这是因为您不需要在某些时间或平均情况下有效的哈希。 您需要一种大多数情况下都可以使用的产品。 (在所有情况下,您都可以发明任何特定散列都将分解的病理情况)
为了保持一致性,分数越低越好。 测试的构造应使得分为0表示测试已损坏。
在每个测试中,使用8,192位或1024 KB的输入,一次切换一位。 根据这些输入,将生成8,192 x 64位哈希。
但是,对于随机测试,采用了一系列随机的64位值。 这些对于了解所测试的散列策略有多少是有用的。
哈希表掩码
在此测试中,每个哈希为模数乘以16,384(哈希数的两倍),并报告了冲突数。 大多数哈希策略在此测试中效果很好。
雪崩分数
在此测试中,将每个散列与前一个散列(前一位进行切换)进行比较,以查看任何给定位被翻转的可能性。 理想值为50%,得出的差值与50%的总和为最差的1%。
延迟速度
在此测试中,记录了执行哈希所需的时间,并报告了最差的1%延迟。
正交钻头
该测试的目的是确保所有散列的位与所产生的其他所有散列都尽可能不同。 除了64位数字外,请考虑8个皇后问题。 理想的情况是每个数字都具有与其他每个数字不同的相同位数,并且位数应尽可能高。
在此测试中,将每个哈希与其他每个哈希进行比较。 对不同的位数进行计数。 如果不同位数小于18,则给出2 ^(17-n)的惩罚分数。 位数越少,指数级的惩罚越大。 如果映射到其他8K哈希值的任何8K哈希值的差异小于5位,那么即使所有其他对都很好,这也是失败的。
我称其为正交位测试,因为您可以将64位数字建模为64位的位向量。 理想情况下,您希望产生的所有散列之间的角度尽可能大。
在所有测试中,此测试显示具有HashMap.hash(int)的String.hashCode()与其他哈希策略之间的最大差异。
测试String.hashCode()
String.hashCode()是一个非常差的哈希,尤其是对于低位 。 它是标准的,不能更改或破坏向后兼容性。 但是,这不一定是问题,因为HashMap使用agitate函数,该函数会降低一些较高的位以将较低的位随机化。
int hash(int h) {// This function ensures that hashCodes that differ only by// constant multiples at each bit position have a bounded// number of collisions (approximately 8 at default load factor).h ^= (h >>> 20) ^ (h >>> 12);return h ^ (h >>> 7) ^ (h >>> 4);
}
结果
CheckMain类对每种哈希策略运行一套测试。
VANILLA
Orthogonal bits: 99%tile score: 6066
Speed: The 99%tile for latency was 0.223 us
Avalanche: The 99%tile of the drift from 50% was 0.55%
Mask of Hash: 99%tile collisions: 1815CITY_1_1
Orthogonal bits: 99%tile score: 7395
Speed: The 99%tile for latency was 0.267 us
Avalanche: The 99%tile of the drift from 50% was 0.55%
Mask of Hash: 99%tile collisions: 1817MURMUR_3
Orthogonal bits: 99%tile score: 7524
Speed: The 99%tile for latency was 0.378 us
Avalanche: The 99%tile of the drift from 50% was 0.54%
Mask of Hash: 99%tile collisions: 1815STRING32
Orthogonal bits: 99%tile score: 295906433
Speed: The 99%tile for latency was 1.580 us
Avalanche: The 99%tile of the drift from 50% was 1.02%
Mask of Hash: 99%tile collisions: 1814STRING64
Orthogonal bits: 99%tile score: 1939167
Speed: The 99%tile for latency was 1.520 us
Avalanche: The 99%tile of the drift from 50% was 0.61%
Mask of Hash: 99%tile collisions: 1816STRING32_WITHOUT_AGITATE
Orthogonal bits: 99%tile score: 879390386
Speed: The 99%tile for latency was 1.573 us
Avalanche: The 99%tile of the drift from 50% was 3.53%
Mask of Hash: 99%tile collisions: 6593RANDOM
Orthogonal bits: 99%tile score: 7444
Speed: The 99%tile for latency was 0.058 us
Avalanche: The 99%tile of the drift from 50% was 0.53%
Mask of Hash: 99%tile collisions: 1817SECURE_RANDOM
Orthogonal bits: 99%tile score: 7449
Speed: The 99%tile for latency was 0.861 us
Avalanche: The 99%tile of the drift from 50% was 0.54%
Mask of Hash: 99%tile collisions: 1816SEEDED_VANILLA
Orthogonal bits: 99%tile score: 6000
Speed: The 99%tile for latency was 0.219 us
Avalanche: The 99%tile of the drift from 50% was 0.55%
Mask of Hash: 99%tile collisions: 1814SEEDED_CITY_1_1
Orthogonal bits: 99%tile score: 7313
Speed: The 99%tile for latency was 0.270 us
Avalanche: The 99%tile of the drift from 50% was 0.54%
Mask of Hash: 99%tile collisions: 1813SEEDED_MURMUR_3
Orthogonal bits: 99%tile score: 7404
Speed: The 99%tile for latency was 0.359 us
Avalanche: The 99%tile of the drift from 50% was 0.53%
Mask of Hash: 99%tile collisions: 1810
注意: Vanilla Hash种子是Chronicle Enterprise的一部分
结论
Vanilla,City和Murmur哈希是最快的。
尽管String.hashCode()很简单,但每个字符的乘法运算却很昂贵。 相比之下,所有其他字节使用long一次处理8个字节。 与STRING32相比,请参阅STRINGS32_WITHOUT_AGITATE。 HashMap使用更高版本。
即使在avalanche测试中,带有搅动的32位String hashCode()也表现不佳。 在SMHasher中,该测试的得分超过1%,被视为失败。
哈希掩码测试虽然简单,但在所有情况下都表现良好。 例外是String.hashCode(),如上所述,它没有非常随机的低位。
我发现有趣的是,正交测试得分有何不同。 前三个哈希策略再次始终保持较低水平。 甚至String.hashCode()的64位版本在产生散列方面也有很大的变化,只有不到18位的不同,实际上很多位是相同的。
免责声明
香草哈希已针对正交钻头测试进行了优化。 因此,获得更好的结果也就不足为奇了。 这并不意味着Vanilla Hash优于City或Murmur。 这可能仅表示对“正交位”测试最好。
翻译自: https://www.javacodegeeks.com/2015/08/comparing-hashing-strategies.html
基于按位与的 就散策略