布隆过滤器的学习整理

bloomFilter是70年代提出来的一个利用时间,错误率来换取空间的应用。

应用在大数据量的情况下,比如爬虫抓取的大量url,用来判断哪些url是已经爬取过的。

m => 使用的散列长度,这个值通常用来创建BitSet的长度,java.util.BitSet

n => 待散列的字符串的个数。

k => 使用的hash函数的个数

建议使用的这几个值是 m/n => 22, k=>17 基本可以保证万分之二点二的错误率。

放一篇论文地址

http://pages.cs.wisc.edu/~cao/papers/summary-cache/node8.html

 

稍微晚点再把自己写的bloomFilter的代码放过来

简单hash

class SimpleHash(val cap: Int, val seed: Int) { 
def hash(value: String):Int = { 
var result = 0 
val len = value.length 
(1 to len).foreach(i => result += seed * result + value.charAt(i - 1)) 
result % cap 
} 
} 

object SimpleHash extends App { 
val strings = "近日,中石化与腾讯达成框架协议," + 
"将探索移动支付、广告、地图、大数据等多领域合作;" + 
"此次合作空间及深度究竟如何,会否只是蜻蜓点水," + 
"到底能否长久共赢存较大疑问。" 
strings split ",|;|。" flatMap(_.toList) foreach println 
// strings split(",|;|、| 。") foreach println 
val cap = 64 
val hashes = (1 to 64) map { new SimpleHash(cap, _)} 
for { 
hash <- hashes 
string<-strings split ",|;|、| 。" 
} println(s"${hash hash string}, $string , ${hash.seed}, ${hash.cap}") 

}
 
 
// 布隆过滤器类

class BloomFilter(cap: Long, hashes: List[SimpleHash]) {   //Allocate 2^24 size for bitset   //   def capability = cap

  var bitSet = new util.BitSet()   def addString(str: String): BloomFilter = {     println(s"------------------------------------检查:$str")     for {       hash <- hashes     } {       if (bitSet.get(hash.hash(str)))         println(s"$str  已存在")       else         println(s"加入 $str")         bitSet.set(hash.hash(str), true)     }     this   }

def contains(str: String): Boolean = {     var count = 0     for {       hash <- hashes     } if (bitSet.get(hash.hash(str)))       count += 1     count == hashes.length   } }

object BloomFilter extends App{   // asuume we have several strings. and   val template = """语言模型基本概念-n元语法                    |                    |                    |                    |                    |  一个语言模型通常构建为字符串s的概率分布p(s),这里p(s)试图反映的是字符串s作为一个句子出现的频率。例如,在一个人所说的话中每100个句子里面大约有一句是Okay,则可以认为p(Okay)约等于0.01。而对于句子“An apple ate the chicken”我们可以认为其概率是0,因为几乎没有人会说这样的句子。需要注意的是,与语言学中不同,语言模型与句子是否合乎语法是没有关系的,即使一个句子完全合乎语法逻辑,我们仍然可以认为它出现的概率接近为0。                    |                    |  对于一个由l个基元(“基元”可以为字,词或短语等,为了表述方便,用“词”来通指)构成的句子, 其概率计算公式如下                    |                    |p(s) = p(w1) p(w2|w1) P(w3|w2w1)...p(wi|w1..wi-1)                    |                    |一般地,我们把钱i-1个词w1w2..wi-1称作第i个词的“历史”。在这种计算方法中,随着历史长度的增加,不同的历史数目按指数级增长。如果历史的长度为i-1,那么就有种不同的历史(假设L为词汇集的大小),而我们必须考虑在所有的L^(i-1)种不同的历史情况下,产生第i个词的概率。这样的话,模型中就有L^i个自由参数,使得我们几乎不可能从训练数据中正确的估计出这些参数,实际上,绝大多数历史根本就不可能在训练数据中出现。因此,为了解决这个问题,需要把上面的公式进行一定的简化,或者说近似。可以奖励是w1w2...wi-1按照某个法则映射到等价类E(w1w2...wi-1),而这些等价类的数目远远小于不同历史的数目。                    |                    |假定p(s)=p(wi|E(w1,w2,...,wi-1)),那么自由参数的数目就会大大减少,有很多方法可以将历史划分成等价类,其中一种比较实际的做法是,将两个历史wi-n+2 ... wi-1 wi 和vk-n+2 ... vk-1vk映射到同一个等价类,当且仅当这两个历史最近的n-1(1<=n<=l)个词相同,即如果E(w1,w2,...,wi-1)) = E(v1v2...vk-1vk),当且仅当(wi-n+2 ... wi-1 wi) = (vk-n+2 ... vk-1 vk)。                    |                    |满足上述条件的语言模型称为n元语法或n元文法(n-gram)。通常情况下,n的取之不能太大,否则等价类太多,自由参数过多的问题依然存在。                    |                    |下面举一个例子来说明:句子: “今天” "天气"“下雨”                    |                    |如果n=1,意味着每一个独立的词都是一个独立的模型,与上下文无关。如果n=2,意味着每个词只和它的上一个词有关,"天气"的出现依赖“今天”, “下雨”依赖“天气”,二元文法(n=2时)被称作一阶马尔科夫链,基座bigram,当n=3时,称作三元文法,三元文法模型称作二阶马尔科夫链,记做trigram或gri-gram.                    |"""  

template replace(" |\t\n|", "")

// k = 17, m/n = 22

  val n = template.length

  val m = n * 22  

  val hashFs: List[SimpleHash] = {List(2,5,7,11,13,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79) map {new SimpleHash(m, _)}   }

  val bf = new BloomFilter(m, hashFs)   template.foreach(c => bf.addString(c.toString))

}

posted @ 2014-08-28 11:01  道友慢走  阅读(179)  评论(0编辑  收藏  举报