免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: zhangzhh05
打印 上一主题 下一主题

[算法] 对Google算法优越性的一点小体会 [复制链接]

论坛徽章:
8
CU大牛徽章
日期:2013-04-17 10:59:39CU大牛徽章
日期:2013-04-17 11:01:45CU大牛徽章
日期:2013-04-17 11:02:15CU大牛徽章
日期:2013-04-17 11:02:36CU大牛徽章
日期:2013-04-17 11:02:58技术图书徽章
日期:2013-12-04 10:48:50酉鸡
日期:2014-01-03 10:32:30辰龙
日期:2014-03-06 15:04:07
281 [报告]
发表于 2008-06-27 15:00 |只看该作者
方案太多了。做过项目的应当能想到吧。

比如:

旧,直接在100MHZ 200M内存机上调用:
bool bloomfilter_is_exist(username);
{
verify(username);
if(bloomfilter1_verify(username) && bloomfilter2_verify(username) && ...)
{
   return true;
}
return false;
}

新,在100MHZ 200M内存的前端机调用:

bool bloomfilter_is_exist(username);
{
verify(username);
if(bloomfilter1_verify(username) && bloomfilter2_verify(username) && ...)
{
   return true;
}
return false;
}

所不同者,bloomfilter1_verify等函数内部由本地查询修改为远程调用,可能需要添加一点网络异常处理代码。


至于google,他们有更好的封装,比如可以自动做任务分解甚至网络节点(主机)失效的容错——详见他们的公开文档。
如上的简化处理代码同样也可以做到这一点。只是要达到通用化甚至整个框架的风格统一化,还需要不少工作。


所谓通用化,就是希望能忽略底层细节,直接写出这样的代码:
bloomfilter bf1();
//初始化网格计算;内部可以以一个dispatch方法完成任务分割。
bf1.initnetwork(bfServerNum, bfServerList);
//初始化黑名单或用户名
bf1.init(StrSource);
//检索用户是否存在
bf1.verify(username);
//添加一个用户到bf
bf1.insert(username);



当然,这只是很原始的接口设计——不在其位,不谋其政,俺也懒得真把这玩意儿做得尽善尽美(7×24小时肯定没问题;但不可能封装更高级更智能的东西,如上面的举例);何况,就是认真做了,也不可能能够拿出来和google的宏大方案相比。

毕竟,人家有大量的相关技术作底,比如他们的任务自动分配、并行执行和自动容错等方面的封装。

在没有把这一整套都搞清楚的情况下,在下连bloom filter在人家的系统中的位置都没搞清,哪里能搞出可以放到google眼里的东西。


其实说到底,还是在讽刺某人来着
他做的时候是单纯的字符串识别;我们一上来就要ACID;我说是1亿用户的gmail;他非说是几十、几百亿;所以当他得意洋洋地说我们搞多层结构时,俺就讽刺他硬把需求从1亿提升到几百亿~~

论坛徽章:
0
282 [报告]
发表于 2008-06-27 15:08 |只看该作者
原帖由 wwwsq 于 2008-6-27 14:38 发表



谁告诉你一个ID要一位?

麻烦你认真看下文档。


A Bloom filter with 1% error and an optimal value of k, on the other hand, requires only about 9.6 bits per element — regardless of the size of the elements.
google说是两上字节, 这里说的是每个元素1.2个字节,所以我说1亿还是要125M,没错吧?几百亿地址需要几十G内存, 难道不对吗?

论坛徽章:
0
283 [报告]
发表于 2008-06-27 15:21 |只看该作者
原帖由 shan_ghost 于 2008-6-27 15:00 发表
方案太多了。做过项目的应当能想到吧。

比如:

旧,直接在100MHZ 200M内存机上调用:
bool bloomfilter_is_exist(username);
{
verify(username);
if(bloomfilter1_verify(username) && bloomfilter2 ...



感谢

论坛徽章:
0
284 [报告]
发表于 2008-06-27 17:20 |只看该作者
原帖由 zszyj 于 2008-6-27 08:44 发表

你说的这种说法, 适合于小规模网站,每输入一个字符,就往服务器提交一次查询请求. 但对于大型网站,我认为是不合适的, 这会给服务器增加了数倍的压力. 其实前面已经有人提到了,数据库查询是很快的, 生成网页显示 ...


分析了一下,觉的有道理,除非在客户端自己检测,否则发送到服务器那么人那么多次的信息都可以让服务器啥也干不了.
而且同时在线的人越多服务器的压力越多.

论坛徽章:
0
285 [报告]
发表于 2008-06-27 22:29 |只看该作者
原帖由 lose 于 2008-6-26 22:31 发表

准备把数据库查询,和broom filter查询都写个程序比较一下。看看相互的优劣。
在这里光看贴还是没有感觉。


我做了一个Bloom Filter的实现来测了下,结论是插入和查询的性能都好到没话说。
查询快到我设的1k个数据一瞬间就查完了,以至于偶实在没什么办法贴数据出来
开始看了两天大家讨论,还疑惑会不会插入慢,查询快,后来一编码,发现插入和查询其实是一个过程
至于怎么和具体的需求结合起来,我就不关心了,只care怎么查询快些而以
做数据时才晓得,6位用户名有好多啊,不知道google区不区分大小写,我反正是不敢区分,37^6和63^6差得太大了,没耐心等~
找hash时发现,貌似越长的单词分散的效果越好,难道这是google要求用户名最少6位的原因??
本来取了8个hash函数,后来发现压根没有碰撞,囧,就一直减少到两个,想了下,如果把存储的空间放大到两倍需求的话,估计两三个hash函数也足够了,本来想几个hash共享一段内存,后来有一次用了两个相像的hash函数搞的不断出现误判,干脆就分两段内存了~
还有就是如果注册用户数不是太离谱的话,也不耗多少内存,并且可以极轻松的把数组写到文件里,随时交换出来~
这果然是个很好的算法,如果不考虑其他需求,查询要优于db;要考虑其他需求的话,还有的吵
代码我改了下,把几个程序合到一个C文件里去了,方便有兴趣的人测试。
注意下,我用的是uint,如果自己改数据千万别越界;还有就是时间,我在linux上发现取不到多精确的时间
后来干脆用rdtsc又测了一次,怕有人不能用,代码里又改成time了~

机器1,公司的ia64
Linux version 2.6.9-5.13 (root@dev3-254.dev.cn.tlan) (gcc version 3.4.3 20041212 (TurboLinux 3.4.3-9.2)) #1 SMP Wed Aug 24 23:26:07 EDT 2005
4 CPUs available, 4 CPUs total
CPU 0: base freq=199.971MHz, ITC ratio=13/2, ITC freq=1299.814MHz+/-650ppm
CPU 1: base freq=199.971MHz, ITC ratio=13/2, ITC freq=1299.814MHz+/-650ppm
CPU 2: base freq=199.971MHz, ITC ratio=13/2, ITC freq=1299.814MHz+/-650ppm
CPU 3: base freq=199.971MHz, ITC ratio=13/2, ITC freq=1299.814MHz+/-650ppm
Brought up 4 CPUs
Total of 4 processors activated (7780.48 BogoMIPS).
Memory: 8299584k/8347472k available (5476k code, 60928k reserved, 2192k data, 384k init)
Adding 2031584k swap on /dev/VolGroup00/LogVol01.  Priority:-1 extents:1

结果
[hejie@rx5670-2 bf]$ ls
a  hash.c  newref.c  ref.c  table.c
[hejie@rx5670-2 bf]$ ./a chk.list
1214562549
833 known!
167 ignore!
1214562549
[hejie@rx5670-2 bf]$

机器2,回家后拿自己本本又跑~
FreeBSD 7.0-RELEASE #0: Mon Jun 16 08:32:32 CST 2008
CPU: Genuine Intel(R) CPU           T2050  @ 1.60GHz (1596.01-MHz 686-class CPU)
  Cores per package: 2
real memory  = 526974976 (502 MB)
avail memory = 505946112 (482 MB)
FreeBSD/SMP: Multiprocessor System Detected: 2 CPUs
cpu0 (BSP): APIC ID:  0
cpu1 (AP): APIC ID:  1

结果一样,我没啥兴趣做更大的数据量了,有兴趣的自己测吧~

论坛徽章:
0
286 [报告]
发表于 2008-06-27 22:41 |只看该作者
原帖由 bbpet 于 2008-6-27 22:29 发表


我做了一个Bloom Filter的实现来测了下,结论是插入和查询的性能都好到没话说。
查询快到我设的1k个数据一瞬间就查完了,以至于偶实在没什么办法贴数据出来
开始看了两天大家讨论,还疑惑会不会插入慢,查 ...


我把几个程序合成一个了,好贴些,待检查的列表也弄到程序里去了,省掉io那段,时间也从rdtsc改成time了
有兴趣的自己改吧,数据可以适当放大,别越界,算清楚内存,就行了,友情提醒下,设太大要等久
另,代码很丑,不用批了,只是用来看效果,平时的程序不是这样的~

  1. #include    <stdio.h>
  2. #include    <stdlib.h>
  3. #include    <string.h>
  4. #include    <unistd.h>

  5. #define HASHSIZE        300000000
  6. #define NAMESIZE        126934395
  7. #define STARTPOS        69343957

  8. static int      initab();
  9. static void     freetab();
  10. static int      fillname();
  11. static int      check(char *name);
  12. static int      testSet1(unsigned int code);
  13. static int      testSet2(unsigned int code);
  14. static unsigned int hash_larbin(char *name);
  15. static unsigned int hash_php(char *name);

  16. char            nametab[] = {
  17.     'a', 'b', 'c', 'd', 'e', 'f', 'g',
  18.     'h', 'i', 'j', 'k', 'l', 'm', 'n',
  19.     'o', 'p', 'q', 'r', 's', 't', 'u',
  20.     'v', 'w', 'x', 'y', 'z',
  21.     '0', '1', '2', '3', '4', '5', '6',
  22.     '7', '8', '9',
  23.     '_'
  24. };

  25. char           *chklist[] = {
  26.     "2",
  27.     "to",
  28.     "nice",
  29.     "great",
  30.     "aaaaaa",
  31.     "aaaaab",
  32.     "aaaaac",
  33.     "aaaaad",
  34.     "baaaaa",
  35.     "caaaaa",
  36.     "daaaaa",
  37.     "aaaaca",
  38.     "bbbbba",
  39.     "bbbbbb",
  40.     "bbbbbc",
  41.     "bbbbbd",
  42.     "abbbbb",
  43.     "bbbbbb",
  44.     "cbbbbb",
  45.     "dbbbbb",
  46.     "fi3a87",
  47.     "fi3a8asfasvaf7",
  48.     NULL
  49. };

  50. static char    *table1;
  51. static char    *table2;

  52. int
  53. main(int argc, char **argv)
  54. {
  55.     char          **p;

  56.     if (initab()) {
  57.         printf("omg!\n");
  58.         return 0;
  59.     }
  60.     fillname();

  61.     printf("%d\n", time(NULL));
  62.     for (p = chklist; *p != NULL; p++) {
  63.         printf("%s ", *p);
  64.         if (check(*p))
  65.             printf("known!\n");
  66.         else
  67.             printf("ignore!\n");
  68.     }
  69.     printf("%d\n", time(NULL));

  70.     freetab();
  71.     return 0;
  72. }

  73. static int
  74. initab()
  75. {
  76.     ssize_t         total;
  77.     ssize_t         i;

  78.     total = HASHSIZE / 8;
  79.     table1 = (char *) malloc(total);
  80.     table2 = (char *) malloc(total);
  81.     if (!table1 || !table2)
  82.         return -1;
  83.     for (i = 0; i < HASHSIZE / 8; i++) {
  84.         table1[i] = 0;
  85.         table2[i] = 0;
  86.     }
  87.     return 0;
  88. }

  89. static void
  90. freetab()
  91. {
  92.     free(table1);
  93.     free(table2);
  94. }

  95. static int
  96. fillname()
  97. {
  98.     int             i;
  99.     int             j;
  100.     int             x;
  101.     unsigned int    code;
  102.     char            username[10];
  103.     for (i = STARTPOS; i < NAMESIZE; i++) {
  104.         memset(username, 0, sizeof(username));
  105.         for (x = i, j = 0; x > 0; j++) {
  106.             username[j] = nametab[x % 37];
  107.             x /= 37;
  108.         }
  109.         code = hash_larbin(username);
  110.         testSet1(code);
  111.         code = hash_php(username);
  112.         testSet2(code);
  113.     }
  114. }

  115. static int
  116. check(char *name)
  117. {
  118.     int             x;
  119.     int             y;
  120.     unsigned int    code;
  121.     code = hash_larbin(name);
  122.     x = testSet1(code);
  123.     code = hash_php(name);
  124.     y = testSet2(code);
  125.     return (x > 0) && (y > 0);
  126. }

  127. static int
  128. testSet1(unsigned int code)
  129. {
  130.     unsigned int    pos;
  131.     unsigned int    bits;
  132.     int             res;

  133.     pos = code / 8;
  134.     bits = 1 << (code % 8);
  135.     res = table1[pos] & bits;
  136.     table1[pos] |= bits;
  137.     return res;
  138. }

  139. static int
  140. testSet2(unsigned int code)
  141. {
  142.     unsigned int    pos;
  143.     unsigned int    bits;
  144.     int             res;

  145.     pos = code / 8;
  146.     bits = 1 << (code % 8);
  147.     res = table2[pos] & bits;
  148.     table2[pos] |= bits;
  149.     return res;
  150. }


  151. static unsigned int
  152. hash_larbin(char *name)
  153. {
  154.     unsigned int    h;
  155.     unsigned int    i;

  156.     h = 0;
  157.     i = 0;
  158.     while (name[i] != 0) {
  159.         h = 31 * h + name[i];
  160.         i++;
  161.     }
  162.     return h % HASHSIZE;
  163. }

  164. static unsigned int
  165. hash_php(char *name)
  166. {
  167.     unsigned int    h;
  168.     unsigned int    g;
  169.     h = 0;
  170.     g = 0;

  171.     while (*name != 0) {
  172.         h = (h << 4) + *name++;
  173.         if ((g = (h & 0xF0000000))) {
  174.             h = h ^ (g >> 24);
  175.             h = h ^ g;
  176.         }
  177.     }
  178.     return h;
  179. }
复制代码

论坛徽章:
0
287 [报告]
发表于 2008-06-27 22:48 |只看该作者
原帖由 bbpet 于 2008-6-27 22:29 发表


我做了一个Bloom Filter的实现来测了下,结论是插入和查询的性能都好到没话说。
查询快到我设的1k个数据一瞬间就查完了,以至于偶实在没什么办法贴数据出来
开始看了两天大家讨论,还疑惑会不会插入慢,查 ...


这个ia64是个很普通的hp服务器,跟我上次测db2得出主索引0.1ms时的z990不可同日而语
连z990的零头的零头的零头的 …… 都不到~
毕竟国内能买得起(或者会买来用)z990的企业用手指头就能数出来了~
恩,快纯粹是Bloom Filter的功劳,我承认~

论坛徽章:
0
288 [报告]
发表于 2008-06-27 23:51 |只看该作者
原帖由 cugb_cat 于 2008-6-22 11:54 发表
如果做了索引,这个数据量放在数据库中去查也很快的。

这中系统必然做了索引啊

论坛徽章:
0
289 [报告]
发表于 2008-06-28 10:47 |只看该作者
原帖由 bbpet 于 2008-6-27 22:48 发表


这个ia64是个很普通的hp服务器,跟我上次测db2得出主索引0.1ms时的z990不可同日而语
连z990的零头的零头的零头的 …… 都不到~
毕竟国内能买得起(或者会买来用)z990的企业用手指头就能数出来了~
恩,快 ...

不知道你的Z990配了多少C, tpmC有多大. 你的ia64 4c/8g, 也不弱了. 不过, 对于单个DB查询或者bloom filter, 都只用到单个CPU的1/4以下资源.因此真正决定其速度的是单个CPU的频率. 不信的话,你可以只有HP上测试一下DB的性能. 我在自已笔记本上的装了个LINUX虚拟机,上面装了个ORACLE,查询一次也是<1ms, 当然, 我没法装入大量数据.
cpu的增加, 只提升了其并发处理的能力.
另外,碰撞的程度,与KEY值的离散程度有关, 越相似,碰撞的可能性就越大. google要8组,还是有其道理的.
补充一些测试数据.
我发现原来生成的名字, 过于离散, 而且名字前几个字符都不同.我想这就是碰撞不大的原因, 我觉得, 用户ID一般前面字符重复的多,因为前面几个字符通常是姓名的拼音或者英文名,而且以3-8个字符的为多,超过8个的少. 因此我修改了一下生成名字的程序, 生成的名字将如下:
aaaaaaaa;
aaaaaaab;
......
Z9999999;
......
Z________;

并增加碰撞结果的统计,程序如下:

static int
fillname()
{
  inti;
  intj;
  intbit;
  unsigned int    code;
  charusername[10];
  intbits[10];
  intres;
  intcollision;

     for (i=0; i<10; i++)
       bits [ i ] =0;

    memset(username, 0, 10);

    collision=0;
    for (i = STARTPOS; i < NAMESIZE; i++) {
        for (j=0; j<8; j++)
            username[j] = nametab[bits[j]];

        bits[7] += 1;
        for (j=7; j>=0; j--)
        {
            if (bits[j]==37)
            {
                bits[j]=0;
                bits[j-1] += 1;
            }
        }

        code = hash_larbin(username);
        res = 0;
        res=testSet1(code);
        code = hash_php(username);
        res += testSet2(code);
        if (res==2)
            collision++;
    }
    printf("%d names, %d collision\n", i, collision);
}

测试结果:
/home/house/tmp>./tt
126934395 names, 3293092 collision // 冲突
1214187341
2 ignore!
to ignore!
nice ignore!
great ignore!
aaaaaa ignore!
aaaaab ignore!
aaaaac ignore!
aaaaad ignore!
baaaaa ignore!
caaaaa ignore!
daaaaa ignore!
aaaaca ignore!
bbbbba ignore!
bbbbbb ignore!
bbbbbc ignore!
bbbbbd ignore!
abbbbb ignore!
bbbbbb known!  // 误判
cbbbbb ignore!
dbbbbb ignore!
fi3a87 ignore!
fi3a8asfasvaf7 ignore!
1214187341

也就是说, 1.2亿个名字中,有3百多万是冲突的.
而且20多个检查中,就已经有一个误判.
说明了一点, 好的hash函数,很重要, 而且, 只靠2个,恐怕是不够的.
这里还是要感谢bbpet的热心,希望能找出更多更好的hash函数.

[ 本帖最后由 zszyj 于 2008-6-28 13:37 编辑 ]

论坛徽章:
0
290 [报告]
发表于 2008-06-28 20:23 |只看该作者
我完全是个门外汉了
我想问一点 Bloom Filter 这种方法
1万台机器如果做同步一半会同过什么方法来做?
效率如何?  谢谢
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP