redis sorted sets操作学习笔记

萧红SEO SEO爱好者,分享SEO经验~

sorted set是set的一个升级版本,它在set的基础上增加了一个顺序属性,这一属性在添加修改元素的时候可以指定,每次指定后,zset会自动重新按新的值调整顺序,可以理解为有两列的mysql表,一列存value,一列存顺序,操作中key理解为zset的名字.

和set一样sorted set也是string类型元素的集合,不同的是每个元素都会关联一个double类型的score。sorted set的实现是skip list和hash table的混合体。

当元素被添加到集合中时,一个元素到score的映射被添加到hash table中,所以给定一个元素获取score的开销是O(1),另一个score到元素的映射被添加到skip list,并按照score排序,所以就可以有序的获取集合中的元素。添加,删除操作开销都是O(log(N))和skip list的开销一致,redis 的skip list实现用的是双向链表,这样就可以逆序从尾部取元素。sorted set最经常的使用方式应该是作为索引来使用.我们可以把要排序的字段作为score存储,对象的id当元素存储.

下面讲一个使用 Sorted Sets 的例子:

mysql中有一张表,假设名字为 summary_data吧,记录数为30M左右,有一个字段first_path 为varchar(256),需要找到出现次数最多的10个first_path.

方法一,直接sql语句,sql语句很好写,代码如下:

SELECT first_path, COUNT(*) AS c FROM summary_data GROUP BY first_path ORDER BY c DESC LIMIT 10;

表上面是有索引的,但是索引的长度为 KEY `first_path` (`first_path`(255)),也许是这个原因导致了无法使用索引.

  1. id:1
  2. select_type:SIMPLE
  3. table:summary_data
  4. type:ALL
  5. possible_keys:NULL
  6. key:NULL
  7. key_len:NULL
  8. ref:NULL
  9. rows:28136948
  10. Extra:Usingtemporary;Usingfilesort

这条sql运行了9分钟,把first_path都导出来,生成文件 input/first_path,每行一条记录,话说这个导出的过程真的很慢.

方法二:sort 与 uniq

sort input/first_path | uniq -c |sort -nr | head -n 10

排好序的状态,就是分组的状态了.

uniq -c 用来统计每组的数量.

sort -nr 再对统计结果进行降序.

一分半钟搞定.

方法三:redis的sorted set

用这种方法,只因为突然想到sorted set就是为此而生的嘛.

client libary 准备用 hiredis.

安装很简单:make && make install

可以看到库文件安装到了 /usr/local/lib/ 目录头文件安装到了 /usr/local/include/hiredis/ 目录,需要把 /usr/local/lib/ 添加到 /etc/ld.so.conf.

然后ldconfig,编译一下,代码如下:

  1. gcc-I/usr/local/include/hiredis-lhiredis./example.c
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<string.h>
  5. #include<hiredis.h>
  6. intmain(intargc,char**argv){
  7. unsignedintj;
  8. redisContext*c;
  9. redisReply*reply;
  10. constchar*hostname=(argc>1)?argv[1]:"127.0.0.1";
  11. intport=(argc>2)?atoi(argv[2]):6379;
  12. structtimevaltimeout={1,500000};//1.5seconds
  13. c=redisConnectWithTimeout(hostname,port,timeout);
  14. if(c==NULL||c->err){
  15. if(c){
  16. printf("Connectionerror:%sn",c->errstr);
  17. redisFree(c);
  18. }else{
  19. printf("Connectionerror:can'tallocaterediscontextn");
  20. }
  21. exit(1);
  22. }
  23. FILE*fp;
  24. fp=fopen(argv[3],"r");
  25. if(!fp)exit(1);
  26. charline[256];
  27. while(fgets(line,sizeof(line)-1,fp)!=NULL){
  28. reply=redisCommand(c,"ZINCRBYmyzset_firstpath1%s",line);
  29. freeReplyObject(reply);
  30. }
  31. fclose(fp);
  32. reply=redisCommand(c,"ZREVRANGEBYSCOREmyzset_firstpath+inf-infWITHSCORESLIMIT010");
  33. if(reply->type==REDIS_REPLY_ARRAY){
  34. for(j=0;j<reply->elements;j+=2){
  35. printf("%u)%s%sn",(unsignedint)(j/2),reply->element[j]->str,reply->element[j+1]->str);
  36. }//phpfensi.com
  37. }
  38. freeReplyObject(reply);
  39. /*Disconnectsandfreesthecontext*/
  40. redisFree(c);
  41. return0;
  42. }

16分钟出结果,not good enough.

相关广告
  • redis sorted sets操作学习笔记 redis sorted sets操作学习笔记 redis sorted sets操作学习笔记
相关阅读

redis sorted sets操作学习笔记

2019/10/10 17:36:51 | 谷歌SEO算法 | Dropbox