bloom filter与dawgdic(一种trie树)

我有一个做了一款移动浏览器的朋友。

他有这样一个需求:当用户输入一个网站的url时候,移动浏览器需要识别这个网址是否是一个恶意网址。另外,他有一个恶意网址库。

也许这样的解决方法有多种。

其中一种就是把恶意网址库放在本地,移动浏览器拿到一个网址的时候就把它与网址库中的每个地址匹配一下,根据匹配与否来判断网址的是否为一个恶意地址。

哦,我忘了补充的情况就是这个网址库中有150万条数据,压缩后23M,如果一个浏览器为了识别恶意网址这么一个功能而附加这么大的库,你会没有用户的。

我刚开始给出的解决方法是bloom filter(bloom过滤器)。关于它的详细机理,吴军先生的《数学之美》中当有提及,我这里只给出一些参数值:数组大小是1500000 * 20 / 8 B(即bitset大小是数据项的20倍),hash function数目为13,误差率为万分之一。我用C++和Java分别实现了这个算法,测试后效果令人满意。数组大小只有4M多,再用zip压缩后大小只有2.8M。4G时代移动浏览器附带一个3M大小的库,个人以为是可以让人接受的。

事情到此为止本该就此结束。朋友又有一个需求:当用户输入一个网址的前面一部分数据库的时候,浏览器要给出相关的最多十个相关网址。

这个网址库当然就更大了,而且又要不断地更新,意味着不能放在本地。但是,每个人浏览的网站一般不会超过一百个吧,刚开始这个库可以为零,随着用户使用次数增多,统计一下缓存在本地就okay啦,这个不需要去服务器拉一大堆网址库下来。再说,真要是匹配不到也无所谓啦。

我想到的算法是trie树。自己实现一个trie树当然是很蠢笨的事情,我去网上搜罗了一番,在stackoverflow上得到一个提示:dawgdic。它也自称是最优秀的trie树,查找速度最快,而且声称的字典库相对来说比二维数组实现的trie树还要节省空间。我在code.google.com上下载完代码后(最新代码是dawgdic-0.4.5.tar.gz,2011年),把它的example看了一遍,有如下功能:

1 根据排列有序的数据,它可以构建出一个非常节省空间的dawg dictionary;

2 它的dawg词典库的每一项可以只有一个key,也可以附带插入其value,即每个数据项是一个key-value对;

3 根据构建好的词典它可以进行kv查询,即给出一个key,返回其value;

4 如果只能给出key的一段前缀,它可以返回所有共同前缀的key,这些结果可以按照字母顺序排列后返回也可以按照value的大小排序后返回;

5 如果只能给出key的一段后缀,它可以返回所有共同后缀的key,这些结果可以按照字母顺序排列后返回也可以按照value的大小排序后返回。

根据以上特性,上面那个需求就稀里哗啦地解决了(^_^)。我们需要利用的特性是1、2和4。dawg字典的key当然是网址的url,其权值当然是浏览次数。由于dawg词典构建好了以后,不能进行modify,而用户对每个网址每一段时间内的浏览次数是变化的,这就需要没过一段时间内对这个dawg dictionary进行重新构建。

其实上面只是简单地分别列举了两个算法的各自应用场景,其实这两个算法的应用范围非常广。如bloom filter就不说了,dawg树就可以用在搜索中的热搜索提示、一些英汉词典的词语搜索和输入法的个性化提示等。

晚上吃完饭,写出此记,对自己最近一段时间的业余研究做一番总结,接着加班。

附带声明:不经本人允许,诸如推酷“www.tuicool.com”这种垃圾抄袭网站不得转载本人的blog。

时间: 2024-10-24 23:58:54

bloom filter与dawgdic(一种trie树)的相关文章

一种trie树 的实现方式

Trie树,又被称为前缀树. 它查询的基本原理是通过当前字的下一个字定位到其子节点.如果我们限制所有有效的输入仅是普通的英文字母,那么它最多会有52个子节点.我之前见过的一种做法就是一旦插入产生第一个子节点, 所有52个节点会同时生成.这种做法的好处是查询速度非常快, 因为直接通过输入的字符就直接可以定位到子节点.缺陷也非常的明显, 即是上述的应用场景都会造成严重的空间浪费..如果我们把字符集加大到所有汉字, 那么这个空间浪费将是承受不起的. 另一种建树的思路可以解决上述结构造成空间浪费的问题,

信息检索——初识Trie树

1.概述 Trie树( /tri:/ ),又称前缀树.字典树,是种快速检索的多叉树结构, Trie树的基本性质可以归纳为: (1)根节点不包含字符,除根节点意外每个节点只包含一个字符. (2)从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串. (3)每个节点的所有子节点包含的字符串不相同. 2.Trie基本实现 基本操作包括插入.删除.查找等. 考虑到通常用于字典等内存较大的情况,应该加入序列化,分割等操作. 3.应用 接触这一数据结构是因为分词处理中的字典存储问题,对这一问

[搜索]Trie树的一种实现

trie树也叫字典树,搜索树等. 如图所示 下面是用stl 的map来实现 class trie_item_c { public: trie_item_c(){} trie_item_c(const char nm) { name = nm; } void set_name(const char nm) { name = nm; } trie_item_c * get_child(const char nm) { map<const char ,trie_item_c*>::const_ite

布隆过滤器(Bloom Filter)的原理和实现

什么情况下需要布隆过滤器? 先来看几个比较常见的例子 字处理软件中,需要检查一个英语单词是否拼写正确 在 FBI,一个嫌疑人的名字是否已经在嫌疑名单上 在网络爬虫里,一个网址是否被访问过 yahoo, gmail等邮箱垃圾邮件过滤功能 这几个例子有一个共同的特点: 如何判断一个元素是否存在一个集合中? 常规思路 数组 链表 树.平衡二叉树.Trie Map (红黑树) 哈希表 虽然上面描述的这几种数据结构配合常见的排序.二分搜索可以快速高效的处理绝大部分判断元素是否存在集合中的需求.但是当集合里

[转载] 布隆过滤器(Bloom Filter)详解

转载自http://www.cnblogs.com/haippy/archive/2012/07/13/2590351.html   布隆过滤器[1](Bloom Filter)是由布隆(Burton Howard Bloom)在1970年提出的.它实际上是由一个很长的二进制向量和一系列随机映射函数组成,布隆过滤器可以用于检索一个元素是否在一个集合中.它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率(假正例False positives,即Bloom Filter报告某一

Bloom Filter(布隆过滤器)

布隆过滤器(英语:Bloom Filter)是1970年由布隆提出的.它实际上是一个很长的二进制矢量和一系列随机映射函数.布隆过滤器可以用于检索一个元素是否在一个集合中.它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难. 如果想判断一个元素是不是在一个集合里,一般想到的是将集合中所有元素保存起来,然后通过比较确定.链表.树.散列表(又叫哈希表,Hash table)等等数据结构都是这种思路.但是随着集合中元素的增加,我们需要的存储空间越来越大.同时检索速度也越来

Bloom filter(布隆过滤器)概念与原理

写在前面 在大数据与云计算发展的时代,我们经常会碰到这样的问题.我们是否能高效的判断一个用户是否访问过某网站的主页(每天访问量上亿)或者需要统计网站的pv.uv.最直接的想法是将所有的访问者存起来,然后每次用户访问的时候与之前集合进行比较.不管是将访问信息存在内存(或数据库)都会对服务器造成非常大的压力.那是否存在一种方式,容忍一定的错误率,高效(计算复杂度.空间复杂度)的实现访问量信息的跟踪.统计呢?接下来介绍的布隆过滤器(BloomFilter)就可以满足当前的使用场景(注释:基数计数法同样

布隆过滤器(Bloom Filter)详解

布隆过滤器(Bloom Filter)详解 2012-07-13 18:35 by Haippy, 29358 阅读, 6 评论, 收藏, 编辑   布隆过滤器[1](Bloom Filter)是由布隆(Burton Howard Bloom)在1970年提出的.它实际上是由一个很长的二进制向量和一系列随机映射函数组成,布隆过滤器可以用于检索一个元素是否在一个集合中.它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率(假正例False positives,即Bloom Fi

大数据量下的集合过滤—Bloom Filter

算法背景 如果想判断一个元素是不是在一个集合里,一般想到的是将集合中所有元素保存起来,然后通过比较确定.链表.树.散列表(又叫哈希表,Hash table)等等数据结构都是这种思路,存储位置要么是磁盘,要么是内存.很多时候要么是以时间换空间,要么是以空间换时间. 在响应时间要求比较严格的情况下,如果我们存在内里,那么随着集合中元素的增加,我们需要的存储空间越来越大,以及检索的时间越来越长,导致内存开销太大.时间效率变低. 此时需要考虑解决的问题就是,在数据量比较大的情况下,既满足时间要求,又满足