利用BloomFilter算法实现手机号码的判断筛选
关于BloomFilter算法别人介绍的很详细,我就不重复造轮子了,参见:
(1)wiki百科算法介绍和错误率分析 http://en.wikipedia.org/wiki/Bloom_filter
(2)中文资料 http://blog.csdn.net/jiaomeng/article/details/1495500
既然你已经了解了什么是bitset和BloomFilter那么,开始我们本篇。
首先我已经将全国号段的数据库处理成txt文本了,其内容示例如下:
[beijingshi] 151 100-119,150-169,1000-1029,1690-1699,1790-1799,2000-2009 150 100-139,1000-1159 153 0-39,100-139,1100-1199,1300-1399,2100-2199,3000-3029,3104,3108-3109,4000-4019,5101-5105
...
...
ps:我这里提供一下我写的spider蜘蛛抓取的全国手机号段数据sqlite库以及这个库格式化后完整的database.txt文件,包含最新的'147','155','156','170','176','177','178','181','184'等号段,截止2014年7月份收录号段 299488条:sqlite库下载地址 database.txt下载地址
在blog贴大段的代码毫无美感,代码我放在github上了,我说下使用方法和测试结果。
1 <?php 2 include('diparser.class.php'); 3 $dp =new DIParser(); 4 5 //init load test 6 $start = microtime(true); 7 $dp->load('phonenum.database.txt'); 8 $end = microtime(true); 9 $time=$end-$start; 10 echo "database load time:".$time."s<br/>"; 11 12 //no hit test 13 $sec = $dp->getSection('beijingshi'); 14 $start = microtime(true); 15 var_dump($sec->has('1386596')); // return true or false 16 $end = microtime(true); 17 $time=$end-$start; 18 echo "1386596 time:".$time."s<br/>"; 19 20 //hit test 21 $start = microtime(true); 22 var_dump($sec->has('1800137')); // return true or false 23 $end = microtime(true); 24 $time=$end-$start; 25 echo "1800137 time:".$time."s<br/>"; 26 27 //spend time test 28 $start = microtime(true); 29 for ($i=1380000; $i<1389999; $i++) 30 { 31 // echo sprintf("%s:%d<br/>",$i,$sec->has($i)); 32 } 33 $end = microtime(true); 34 $time=$end-$start; 35 echo "has 1380000-1389999 time:".$time."s<br/>";
测试结果:
database load time:0.10922789573669s //init load test bool(false) 1386596 time:0.0054430961608887s //no hit test bool(true) 1800137 time:0.017890214920044s //hit test has 1380000-1389999 time:0.00032496452331543s //spend time test
和与建立好index索引的mysql搜索,命中hit的时间是差不多的(mysql hit 0.0188s),但多条查询的效率比利用key-value数据库要好。当然,选择用数据库还是用位图和位向量方法去筛选具体还要看生产环境和需求。这里我无意去比对两种方法孰优孰劣。
BloomFilter算法使用了php的bitset模块,如果你不清楚请查看我之前的文章: