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

hashStringScalaが UTF-16charのペアをintGuava のものとは異なる方法で変換するように私には見えますhashUnencodedChars( hashStringnoはそれCharsetに名前が変更されました)。

スカラ:

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

グアバ:

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

Guava では、charインデックスの at は のi最下位16 ビットになりintcharati + 1は最上位 16 ビットになります。Scala 実装では、これが逆になります。atが最も重要であり、 charati最も重要chari + 1はありません。(Scala の実装では+なくを使用しているという事実|も重要だと思います。)

Guava の実装は、ByteBuffer.putChar(c)2 回使用して 2 つの文字をリトルエンディアンに入れByteBuffer、次に使用ByteBuffer.getInt()して int 値を取得することと同等であることに注意してください。Guava 実装は、文字をバイトにエンコードし、それらのバイトをハッシュすることに相当します。UTF-16LEScala の実装は、JVM がサポートする必要がある標準の文字セットで文字列をエンコードすることと同等ではありません。一般に、Scala がその方法でそれを行うための前例 (もしあれば) があるかどうかはわかりません。

編集:

Scala の実装は、Guava の実装とは別のことも行います。ハッシュされる文字数をメソッドに渡します。GuavafinalizeHashの実装は、バイト数を同等のfmixメソッドに渡します。

于 2015-05-12T16:43:08.160 に答える
-1

hashString(x, StandardCharsets.UTF_16BE)Scala の動作と一致するはずだと思います。我々に教えてください。

(また、Guava を新しいものにアップグレードしてください!)

于 2015-05-12T17:00:52.727 に答える