女神进化论 2017-12-26
Simhash的算法简单的来说就是,从海量文本中快速搜索和已知simhash相差小于k位的simhash集合,这里每个文本都可以用一个simhash值来代表,一个simhash有64bit,相似的文本,64bit也相似,论文中k的经验值为3。该方法的缺点如优点一样明显,主要有两点,对于短文本,k值很敏感;另一个是由于算法是以空间换时间,系统内存吃不消。
demo:
package main import ( "fmt" "math" "strconv" "strings" ) type SimHash struct { IntSimHash int64 HashBits int } func main() { str := "夜空中最亮的星是否记清那仰望的人 心里的孤独和叹息夜空中最亮的星是否记清那仰望的人 心里的孤独和叹息夜空中最亮的星是否记清那仰望的人 心里的孤独和叹息夜空中最亮的星是否记清那仰望的人 心里的孤独和叹息夜空中最亮的星是否记清那仰望的人 心里的孤独和叹息夜空中最亮的星是否记清那仰望的人 心里的孤独和叹息" str2 := "夜空中最亮的星是否记清那仰望的人 心里的孤独和叹息夜空中最亮的星是否记清那仰望的人 心里的孤独和叹息夜空中最亮的星是否记清那仰望的人 心里的孤独和叹息夜空中最亮的星是否记清那仰望的人 心里的孤独和叹息夜空中最亮的星是否记清那仰望的人 心里的孤独和叹息夜空中最亮的星是否记清那仰望的人 心里的孤独和叹息" //str3:="nai nai ge xiong cao" s := params() //str hash 值 hash := s.Simhash(str) fmt.Println(hash) //str2 距离 hash2 := s.Simhash(str2) fmt.Println(hash2) //计算相似度 sm := s.Similarity(hash, hash2) fmt.Println(sm) //距离 ts := s.HammingDistance(hash, hash2) fmt.Println(ts) } /** 距离 补偿 */ func (s *SimHash) HammingDistance(hash, other int64) int { x := (hash ^ other) & ((1 << uint64(s.HashBits)) - 1) tot := 0 for x != 0 { tot += 1 x &= x - 1 } return tot } /** 相似度 */ func (s *SimHash) Similarity(hash, other int64) float64 { a := float64(hash) b := float64(other) if a > b { return b / a } return a / b } /** 海明距离hash */ func (s *SimHash) Simhash(str string) int64 { m := strings.Split(str, " ") token_int := make([]int, s.HashBits) for i := 0; i < len(m); i++ { temp := m[i] t := s.Hash(temp) for j := 0; j < s.HashBits; j++ { bitMask := int64(1 << uint(j)) if t&bitMask != 0 { token_int[j] += 1 } else { token_int[j] -= 1 } } } var fingerprint int64 = 0 for i := 0; i < s.HashBits; i++ { if token_int[i] >= 0 { fingerprint += 1 << uint64(i) } } return fingerprint } /** 初始化 */ func params() (s *SimHash) { s = &SimHash{} s.HashBits = 64 return s } /** hash 值 */ func (s *SimHash) Hash(token string) int64 { if token == "" { return 0 } else { x := int64(int(token[0]) << 7) m := int64(1000003) mask := math.Pow(2, float64(s.HashBits-1)) s := strconv.FormatFloat(mask, 'f', -1, 64) tsk, _ := strconv.ParseInt(s, 10, 64) for i := 0; i < len(token); i++ { tokens := int64(int(token[0])) x = ((x * m) ^ tokens) & tsk } x ^= int64(len(token)) if x == -1 { x = -2 } return int64(x) } }