2013-02-10 8 views
7

In Scala 2.10, MurmurHash ist aus irgendeinem Grund veraltet, ich sollte jetzt MurmurHash3 verwenden. Aber die API ist anders und es gibt keine brauchbaren scaladocs für MurmurHash3 -> fail.Von MurmurHash zu MurmurHash3 migrieren

Zum Beispiel aktuelle Code:

trait Foo { 
    type Bar 
    def id: Int 
    def path: Bar 

    override def hashCode = { 
    import util.MurmurHash._ 
    var h = startHash(2) 
    val c = startMagicA 
    val k = startMagicB 
    h = extendHash(h, id, c, k) 
    h = extendHash(h, path.##, nextMagicA(c), nextMagicB(k)) 
    finalizeHash(h) 
    } 
} 

Wie würde ich dies mit MurmurHash3 stattdessen tun? Dies muss eine schnelle Operation sein, vorzugsweise ohne Zuweisungen, so dass ich keine Product, Seq, Array[Byte] oder was auch immer MurmurHash3 scheint mir anbieten will.

Antwort

7

Die MurmurHash3 algorithm geändert wurde, von einem Algorithmus zum Verwechseln, die gemischt in seinem eigenen Salz, im Wesentlichen (c und k), zu einem, das nur mehr Bit-Mischen tut. Die grundlegende Operation ist jetzt mix, die Sie über alle Ihre Werte falten sollten, nach denen Sie sollten finalizeHash (das Int Argument für die Länge ist für die Bequemlichkeit auch, um mit der Unterscheidung von Sammlungen unterschiedlicher Länge zu helfen). Wenn Sie Ihre letzte mix durch mixLast ersetzen möchten, ist es ein wenig schneller und entfernt Redundanz mit finalizeHash. Wenn Sie zu lange brauchen, um den letzten Mix zu erkennen, einfach mix.

Normalerweise möchten Sie für eine Sammlung einen zusätzlichen Wert mischen, um anzugeben, um welche Art von Sammlung es sich handelt.

So minimal würden Sie

override def hashCode = finalizeHash(mixLast(id, path.##), 0) 

haben und „typisch“ Sie

// Pick any string or number that suits you, put in companion object 
val fooSeed = MurmurHash3.stringHash("classOf[Foo]") 

// I guess "id" plus "path" is two things? 
override def hashCode = finalizeHash(mixLast(mix(fooSeed,id), path.##), 2) 

Hinweis würde, dass das Längenfeld nicht da ist ein qualitativ hochwertiges Hash zu geben, dass mischt Nummer. Das Mischen von wichtigen Hash-Werten sollte mit mix erfolgen.

+0

Danke, Rex. Die Samengeneration macht Sinn. Für so 'Produkt' wäre das wahrscheinlich' stringHash (productPrefix) '. –

+0

@ 0__ - Das wäre ein vernünftiger Wert. Es läuft wirklich darauf hinaus, was mit dem gleichen Inhalt, aber mit einer anderen Identität möglich ist; wenn es so etwas nicht gibt (oder es Ihnen nichts ausmacht, damit zu kollidieren), dann können Sie alles oder nichts dort hinstellen. "Kollidieren Sie nur mit Dingen gleichen Namens und gleichen Inhalts (die ebenfalls ein' Produkt' sind und einen Samen mit derselben offensichtlichen Methode gewählt haben) "ist eine sehr vernünftige Politik. –

4

am source code von MurmurHash3 vermuten lässt etwas wie folgt aus:

override def hashCode = { 
    import util.hashing.MurmurHash3._ 

    val h = symmetricSeed // I'm not sure which seed to use here 
    val h1 = mix(h, id) 
    val h2 = mixLast(h1, path ##) 
    finalizeHash(h2, 2) 
} 

oder, in (fast) eine Zeile:

import util.hashing.MurmurHash3._ 
override def hashCode = finalizeHash(mix(mix(symmetricSeed, id), path ##), 2) 
+0

Sieht gut aus. Ich nehme an, dass ich "productSeed" verwenden werde, da mein ursprünglicher Code auf dem Produkt-Hash-Generator für Arity 2 basierte. –