来自Scala和Guava的Murmur3的不同结果

时间:2015-05-12 16:13:21

标签: scala guava consistent-hashing murmurhash

我正在尝试使用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

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

2 个答案:

答案 0 :(得分:4)

在我看来,Scala的hashString将UTF-16 char对转换为int的方式与Guava的hashUnencodedCharshashString不同Charset不同{1}}已重命名为。)

Scala的:

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

番石榴:

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

在Guava中,索引char的{​​{1}}成为i的16个最低有效位,int的{​​{1}}成为最高位有效16位。在Scala实现中,情况正好相反:char位于i + 1 重要而char位于i 意义重大。 (Scala实现使用char而不是i + 1的事实也可能是我想象的重要。)

请注意,Guava实现相当于使用+两次将两个字符放入一个小端|,然后使用ByteBuffer.putChar(c)来取回一个int值。 Guava实现等效于使用ByteBuffer将字符编码为字节并散列这些字节。 Scala实现不等同于在JVM需要支持的任何标准字符集中编码字符串。一般来说,我不确定Scala的做法是什么先例(如果有的话)。

修改

Scala实现还做了另一件与Guava实现不同的事情:它将被散列的 chars 的数量传递给ByteBuffer.getInt()方法,其中Guava的实现传递了的数量字节到等效的UTF-16LE方法。

答案 1 :(得分:-1)

我相信hashString(x, StandardCharsets.UTF_16BE)应符合Scala的行为。请告诉我们。

(另外,请将你的番石榴升级到更新的东西!)