4

我正在尝试使用 Murmur3 算法生成哈希。哈希是一致的,但它们是 Scala 和 Guava 返回的不同值。

class package$Test extends FunSuite {
  test("Generate hashes") {
    println(s"Seed = ${MurmurHash3.stringSeed}")
    val vs = Set("abc", "test", "bucket", 111.toString)
    vs.foreach { x =>
      println(s"[SCALA] Hash for $x = ${MurmurHash3.stringHash(x).abs % 1000}")
      println(s"[GUAVA] Hash for $x = ${Hashing.murmur3_32().hashString(x).asInt().abs % 1000}")
      println(s"[GUAVA with seed] Hash for $x = ${Hashing.murmur3_32(MurmurHash3.stringSeed).hashString(x).asInt().abs % 1000}")
      println()
    }
  }
}


Seed = -137723950
[SCALA] Hash for abc = 174
[GUAVA] Hash for abc = 419
[GUAVA with seed] Hash for abc = 195

[SCALA] Hash for test = 588
[GUAVA] Hash for test = 292
[GUAVA with seed] Hash for test = 714

[SCALA] Hash for bucket = 413
[GUAVA] Hash for bucket = 22
[GUAVA with seed] Hash for bucket = 414

[SCALA] Hash for 111 = 250
[GUAVA] Hash for 111 = 317
[GUAVA with seed] Hash for 111 = 958

为什么我得到不同的哈希值?

4

2 回答 2

4

在我看来,ScalahashString将一对 UTF-16 chars 转换为ints 与 Guava 的不同hashUnencodedCharshashStringnoCharset被重命名为)。

斯卡拉:

val data = (str.charAt(i) << 16) + str.charAt(i + 1)

番石榴:

int k1 = input.charAt(i - 1) | (input.charAt(i) << 16);

在 Guava 中,char索引的 ati成为 the 的 16 个最低有效位,intcharati + 1成为最高有效 16 位。在 Scala 实现中,情况正好相反:charati重要的,而charati + 1最不重要的。+(我想,Scala 实现使用而不是这一事实|也很重要。)

请注意,Guava 实现相当于使用ByteBuffer.putChar(c)两次将两个字符放入一个 little endianByteBuffer中,然后使用ByteBuffer.getInt()来获取一个 int 值。Guava 实现相当于使用UTF-16LE和散列这些字节将字符编码为字节。Scala 实现不等同于在 JVM 需要支持的任何标准字符集中对字符串进行编码。一般来说,我不确定 Scala 有什么先例(如果有的话)这样做。

编辑:

Scala 实现还做了与 Guava 实现不同的另一件事:它将被散列的字符finalizeHash数传递给方法,而 Guava 的实现将字节数传递给等效fmix方法。

于 2015-05-12T16:43:08.160 回答
-1

我相信hashString(x, StandardCharsets.UTF_16BE)应该符合 Scala 的行为。让我们知道。

(另外,请将您的番石榴升级到更新的版本!)

于 2015-05-12T17:00:52.727 回答