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 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))
}