利用 Redis 的 bitmap 實現簡單的布隆過濾器

littlexiaoshuishui發表於2020-06-28

布隆過濾器原理和作用:
www.cnblogs.com/heihaozi/p/1217447...
這裡使用goredis來實現一個簡單的布隆過濾器,使用3個雜湊函式

建立hash.go儲存雜湊函式

package hash

func BKDRHash(str string) uint64 {
    seed := uint64(131) // 31 131 1313 13131 131313 etc..
    hash := uint64(0)
    for i := 0; i < len(str); i++ {
        hash = (hash * seed) + uint64(str[i])
    }
    return hash & 0x7FFFFFFF
}

func SDBMHash(str string) uint64{
    hash := uint64(0)
    for i := 0; i < len(str); i++ {
        hash = uint64(str[i]) + (hash << 6) + (hash << 16) - hash
    }
    return hash & 0x7FFFFFFF
}

func DJBHash(str string) uint64{
    hash := uint64(0)
    for i := 0; i < len(str); i++ {
        hash = ((hash << 5) + hash) + uint64(str[i])
    }
    return hash & 0x7FFFFFFF

建立bloom.go

package hash
import (
    "fmt"
    "github.com/garyburd/redigo/redis"
)

type Bloom struct{
    Conn redis.Conn
    Key string //這個bitmap的鍵
}
 func NewBloom(con redis.Conn) *Bloom{
     return &Bloom{Conn:con,Key:"bloom"}
 }

 func (b *Bloom)Add(str string) error{
     offsetOne := BKDRHash(str)
     offsetTwo := SDBMHash(str)
     offsetThr := DJBHash(str)
     _,err := b.Conn.Do("setbit", b.Key, offsetOne,1)
     _,err = b.Conn.Do("setbit", b.Key, offsetTwo,1)
     _,err = b.Conn.Do("setbit", b.Key, offsetThr,1)
     return err
 }

 func (b *Bloom)Exist(str string) bool{
     var a int64=1
     offsetOne := BKDRHash(str)
     offsetTwo := SDBMHash(str)
     offsetThr := DJBHash(str)
     bitValueOn,_ := b.Conn.Do("getbit", b.Key, offsetOne)
     bitValueTwo,_ := b.Conn.Do("getbit", b.Key, offsetTwo)
     bitValueThr,_ := b.Conn.Do("getbit", b.Key, offsetThr)
     fmt.Println(bitValueOn,bitValueTwo,bitValueThr)
     if bitValueOn==a && bitValueTwo==a && bitValueThr==a{
         return true
     }else{
         return false
     }
 }
func main() {
    con,err := redis.Dial("tcp", ":6379")//連線redis
    print(err,"connect")
    defer con.Close()

    bloom := hash.NewBloom(con) //建立過濾器
    bloom.Add("newClient") //往過濾器寫入資料
    b := bloom.Exist("aaa") //判斷是否存在這個值
    fmt.Println(b)
}

相關的redis命令

1、setbit

  語法:setbit key offset value

  描述:

    對key所儲存的字串值,設定或清除指定偏移量上的位(bit)。

    位的設定或清除取決於 value 引數,可以是 0 也可以是 1 。

    當 key 不存在時,自動生成一個新的字串值。

    字串會進行伸展(grown)以確保它可以將 value 儲存在指定的偏移量上。當字串值進行伸展時,空白位置以 0 填充。

  注意:
    offset 引數必須大於或等於 0 ,小於 2^32 (bit 對映被限制在 512 MB 之內)。
    因為 Redis 字串的大小被限制在 512 兆(megabytes)以內, 所以使用者能夠使用的最大偏移量為 2^29-1(536870911) , 如果你需要使用比這更大的空間, 請使用多個 key。

2、getbit

  語法:getbit key offset
  描述:
    對 key 所儲存的字串值,獲取指定偏移量上的位(bit)。
    當 offset 比字串值的長度大,或者 key 不存在時,返回 0
3、bitcount
  語法:bitcount key [start] [end]
  返回值:被設定為 1 的位的數量
  描述:
    計算給定字串中,被設定為 1 的位元位的數量
    一般情況下,給定的整個字串都會被進行計數,通過指定額外的 start 或 end 引數,可以讓計數只在特定的位上進行。
    start 和 end 引數的設定和 GETRANGE key start end 命令類似,都可以使用負數值: 比如 -1表示最後一個位元組, -2 表示倒數第二個位元組,以此類推。
    不存在的 key 被當成是空字串來處理,因此對一個不存在的 key 進行 BITCOUNT 操作,結果為 0 。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章