布隆过滤器(Bloom Filter)详解 一.作用: 二.基本原理通俗: 三.算法原理详细: 四.优缺点 五.简单代码实现 六.参考链接

判断一个元素是否存在一个集合中

二.基本原理通俗:

当一个元素被加入集合时,通过K个Hash函数将这个元素映射成一个一维的布尔型的数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。这就是布隆过滤器的基本思想。

三.算法原理详细:

  1. n个要添加的元素
  2. k个hash函数
  3. m位的空的bitArray
  4. 添加一个元素key时,用k个hash函数计算出k个散列值,并把bitArray对应的比特位置为1
  5. 判断一个元素key是否存在时,用k个hash函数计算出k个散列值,并查询bitArray中对应的比特位;如果至少有一位不为1,则一定不在集合中;如果全部都为1,则认为在集合中(存在误判)

四.优缺点

优点:

新增,查询速度足够快,内存小,代码简单

缺点:

有一定误判率且随数据增加而增加; 不支持删除

五.简单代码实现

package scala02

import scala.collection.mutable.ArrayBuffer
import scala.math.abs
import scala.util.hashing.MurmurHash3

 object BloomFilter {

   private val BYTE_SIZE: Int = 8
   private var m: Int = _   //m 为要存的比特数组长度
   private var k: Int = _       //k 为哈希函数的个数
   private var bitmapCharArray: Array[Char] = _  
   private var seedArray: Array[Int] = _


   /**
     * 生成空的bitArray
     * @param m
     * @return
     */
  private def generateEmptyBitmap(m:Int): Array[Char] ={
    val charNum = (m.toDouble/BYTE_SIZE).ceil.toInt //ceil 不小于该浮点数的最小整数, (2.1).ceil则为3.0
    val charArrayBuffer = ArrayBuffer.empty[Char]
    val char=0x00.toChar
    for (elem <- 0 until charNum ) {//0 until len  或者 0 to len-1
      charArrayBuffer.append(char)
    }
    charArrayBuffer.toArray

  }

   /**
     * 判断字符串是否可能存在于过滤器中
     *
     * @param str
     * @return
     */
   def exists(str: String): Boolean = {
     var flag = true
     var s = 0
     while (s < k) {
       val pos = hash(str, seedArray(s))
       if (!getBit(pos)) {
         flag = false
         s = k
       }
       s = s + 1
     }
     flag
   }


   /**
     * 将字符串添加到过滤器中
     *
     * @param str
     */
   def put(str: String) = {
     seedArray.foreach(seed => {
       val pos = hash(str, seed)
       setBit(pos)
     })
   }

   /**
     * 将bitmap的第pos个bit置为1
     *
     * @param pos
     */
   private def setBit(pos: Int): Unit = {
     val charPos = getCharPos(pos)
     val char = bitmapCharArray(charPos)
     val bitPos = pos - charPos * BYTE_SIZE
     val byte = char.toByte
     val mask = 0x01 << bitPos
     val or = byte | mask
     bitmapCharArray(charPos) = or.toChar
   }
   


   /**
     * 基于MurmurHash3算法计算字符串的hash值
     *
     * @param str
     * @param seed hash种子
     * @return 取值范围 0 ~ m-1
     */
   private def hash(str: String, seed: Int): Int = {
     abs(MurmurHash3.stringHash(str, seed)) % m
   }

   /**
     * 读取bitmap的第pos个bit
     *
     * @param pos
     */
   private def getBit(pos: Int): Boolean = {
     val charPos = getCharPos(pos)
     val char = bitmapCharArray(charPos)
     val bitPos = pos - charPos * BYTE_SIZE
     val byte = char.toByte
     val mask = 0x01 << bitPos
     val and = byte & mask
     if (0 == and) false else true
   }

   /**
     * 获取第pos个bit对应的char的位置(从0开始编号)
     *
     * @param pos
     * @return 0 ~ m/BYTE_SIZE-1
     */
   private def getCharPos(pos: Int): Int = {
     (pos.toDouble / BYTE_SIZE).toInt
   }

   /**
     * 判断n是否为质数
     *
     * @param n
     * @return
     */
   private def isPrime(n: Int) = {
     var flag = true
     for (i <- 2 to n - 1) {
       if (n % i == 0) flag = false
     }
     flag
   }
   

}

六.参考链接

布隆过滤器原理及数学推导

https://www.cnblogs.com/allensun/archive/2011/02/16/1956532.html