redis基本数据类型分析

http://blog.csdn.net/shamohua/article/category/933347

 

redis:string数据类型与操作


redis的基本数据类型之一:string。

  • 类型说明

定义:src/sds.h

  1. 39 struct sdshdr {  
  2. 40     int len;  
  3. 41     int free;  
  4. 42     char buf[];  
  5. 43 };  

sds是Simple Dynamic Strings的缩写,即简单的动态字符串。其中,

len:buf数组的长度。

free:数组中剩余可用字节数,由此可以理解为什么string类型是二进制安全的了,因为它本质上就是个byte数组,当然可以包含任何数据了

buf:个char数组用于存贮实际的字符串内容,其实char和c#中的byte是等价的,都是一个字节。


  • 基本操作
[plain]  view plain copy print ?
  1. Command         Parameters             Description  
  2. SET                  key value               Set a key to a string value  
  3. GET                 key                        Return the string value of the key  
  4. GETSET           key value                Set a key to a string returning the old value of the key  
  5. MGET              key1 key2 ... keyN    Multi-get, return the strings values of the keys  
  6. SETNX            key value                Set a key to a string value if the key does not exist  
  7. SETEX            key time value         Set+Expire combo command  
  8. MSET              key1 value1 key2 value2 ... keyN valueN     Set multiple keys to multiple values in a single atomic operation  
  9. MSETNX          key1 value1 key2 value2 ... keyN valueN     Set multiple keys to multiple values in a single atomic operation if none of the keys already exist  
  10. INCR               key                          Increment the integer value of key  
  11. INCRBY           key integer             Increment the integer value of key by integer  
  12. DECR              key                       Decrement the integer value of key  
  13. DECRBY          key integer             Decrement the integer value of key by integer  
  14. APPEND           key value               Append the specified string to the string stored at key  
  15. SUBSTR          key start end         Return a substring of a larger string  

详细说明请参考:

中文: http://redis.readthedocs.org/en/2.4/string.html#setbit

英文: http://redis.io/commands#string 

下面是利用mrpi-redis-cplusplus-client,对上述基本操作加以验证:

  1. <pre name="code" class="cpp">#include "redisclient.h"  
  2.   
  3. #include "tests/functions.h"  
  4.   
  5. #include <iostream>  
  6.   
  7. #include <boost/date_time.hpp>  
  8.   
  9. #define OUT(x) std::cout<<#x<<" = "<<x<<std::endl;  
  10.   
  11. boost::shared_ptr<redis::client> init_non_cluster_client();  
  12.   
  13. void test_strings(redis::client & c);   
  14.   
  15. int main(int argv, char* argc[])   
  16. {  
  17.     boost::shared_ptr<redis::client> shared_c;  
  18.   
  19.     shared_c = init_non_cluster_client();  
  20.   
  21.     redis::client& c = *shared_c;  
  22.   
  23.     test_strings(c);  
  24.   
  25.     return 0;  
  26. }  
  27.   
  28. void test_strings(redis::client & c)   
  29. {  
  30.     std::cout<<"test save keys: "<<std::endl;  
  31.     std::string key = "key";  
  32.     std::string value = "value string for test ";  
  33.     std::string response;  
  34.     test("set & get");  
  35.     {  
  36.         c.set(key, value);  
  37.         response = c.get(key);  
  38.         OUT(response);  
  39.     }  
  40.   
  41.     test("append");  
  42.     {  
  43.         // append the key  
  44.         value += "1 ";  
  45.         c.append(key, value);  
  46.         response = c.get(key);  
  47.         OUT(response);  
  48.     }  
  49.   
  50.     test("substr");  
  51.     {  
  52.         // get the substring  
  53.         // params : key start index  
  54.         // end index: -1 the end  
  55.                 // 获得区间start,end之间的字串  
  56.                 string second_half = c.substr(key, value.size(), -1);  
  57.         OUT(second_half);  
  58.         second_half = c.substr(key, value.size(), 2*value.size());  
  59.         OUT(second_half);  
  60.     }  
  61.       
  62.     test("exists");  
  63.     {  
  64.         std::string key2 = "key2";  
  65.         std::string value2 = "value2";  
  66.         c.set(key2, value2);  
  67.         std::cout<<"check the key whether exist."<<std::endl;  
  68.         bool bExist = c.exists(key2);  
  69.         OUT(bExist);  
  70.         OUT( c.exists("key_exist") );  
  71.         if(!bExist) {  
  72.             c.set("key2""value2");  
  73.         }  
  74.     }  
  75.   
  76.     test("keys");  
  77.     {  
  78.                 // 获得关键字以key开头的集合  
  79.                 redis::client::string_vector keys;  
  80.         OUT(c.keys("key*", keys));  
  81.     }  
  82.     // infos  
  83.     redis::server_info info;  
  84. //  std::cout<<"the server info:"<<std::endl;  
  85. //  c.info(info);     
  86.       
  87.     test("getset");  
  88.     {  
  89.         // get the key value, and set the new value  
  90.         response = c.getset(key, "key_value_new");  
  91.         OUT(response);  
  92.         response = c.get(key);  
  93.         OUT(response);  
  94.     }  
  95.   
  96.     test("mset & mget");  
  97.     {  
  98.         redis::client::string_vector vkeys;  
  99.         redis::client::string_vector vvalues;  
  100.         vkeys.push_back("k1");  
  101.         vkeys.push_back("k2");  
  102.         vvalues.push_back("v1");  
  103.         vvalues.push_back("v2");  
  104.         c.mset(vkeys, vvalues);  
  105.         redis::client::string_vector vvls;  
  106.         c.mget(vkeys, vvls);  
  107.         OUT(vvls.size());  
  108.     }  
  109.   
  110.     test("setnx");  
  111.     {  
  112.         OUT(c.setnx(key, value));  
  113.         OUT(c.setnx("key_setnx""value_setnx"));  
  114.     }  
  115.   
  116.     test("setex");  
  117.     {  
  118.                 // 将值value关联到key,并将key的生存时间设为seconds(以秒为单位)  
  119.                 int sec = 5;  
  120.         c.setex("key_setex""value_setex", sec);  
  121.             OUT(c.get("key_setex"));  
  122.         sleep(2*sec);  
  123.         OUT(c.get("key_setex"));  
  124.     }  
  125.   
  126.     test("incr & inrcby");  
  127.     {  
  128.                 // inrc,key对应的value。步长为1的自加运算  
  129.                 c.set("key_age""20");  
  130.         OUT(c.get("key_age"));  
  131.         int step = 5;  
  132.         OUT(c.incr("key_age"));  
  133.         OUT(c.get("key_age"));  
  134.                 // inrc,key对应的value。步长为step的自加运算                  
  135.                 OUT(c.incrby("key_age", step));  
  136.         OUT(c.get("key_age"));    
  137.     }  
  138.   
  139.     test("derc & dercby");  
  140.     {  
  141.         int step = 3;  
  142.         OUT(c.get("key_age"));    
  143.         OUT(c.decr("key_age"));  
  144.         OUT(c.get("key_age"));  
  145.         OUT(c.decrby("key_age", step));  
  146.         OUT(c.get("key_age"));  
  147.     }  
  148. }</pre><br>  
  149. <br>  
  150. <pre></pre>  
  151. <br>  
  152. <br>  
  153. <p></p>  
redis:hash数据类型与操作

 Redis hash是一个string类型的field和value的映射表.一个key可对应多个field,一个field对应一个value。将一个对象存储为hash类型,较于每个字段都存储成string类型更能节省内存。新建一个hash对象时开始是用zipmap(又称为small hash)来存储的。这个zipmap其实并不是hash table,但是zipmap相比正常的hash实现可以节省不少hash本身需要的一些元数据存储开销。尽管zipmap的添加,删除,查找都是O(n),但是由于一般对象的field数量都不太多。所以使用zipmap也是很快的,也就是说添加删除平均还是O(1)。如果field或者value的大小超出一定限制后,Redis会在内部自动将zipmap替换成正常的hash实现.。这个限制在redis.conf中配置如下:

[plain]  view plain copy print ?
  1. 421 # Hashes are encoded in a special way (much more memory efficient) when they  
  2. 422 # have at max a given numer of elements, and the biggest element does not  
  3. 423 # exceed a given threshold. You can configure this limits with the following  
  4. 424 # configuration directives.  
  5. 425 hash-max-zipmap-entries 512  
  6. 426 hash-max-zipmap-value 64  

  • 操作

1. hset

HSET key field value
将哈希表 key中的域 field的值设为 value。如果 key不存在,一个新的哈希表被创建并进行hset操作。如果域 field已经存在于哈希表中,旧值将被覆盖。

2. hget


HGET key field


返回哈希表key中指定的field的值。


3. hsetnx

HSETNX key field value
将哈希表 key中的域 field的值设置为 value,当且仅当域 field不存在。若域 field已经存在,该操作无效。如果 key不存在,一个新哈希表被创建并执行hsetnx命令。

4. hmset

HMSET key field value [field value ...]

同时将多个field - value(域-值)对设置到哈希表key中。此命令会覆盖哈希表中已存在的域。如果key不存在,一个空哈希表被创建并执行hmset操作。

5. hmget


HMGET key field [field ...]

返回哈希表key中,一个或多个给定域的值。如果给定的域不存在于哈希表,那么返回一个nil值。因为不存在的key被当作一个空哈希表来处理,所以对一个不存在的key进行hmget操作将返回一个只带有nil值的表。


6. hgetall

HGETALL key 返回哈希表 key中,所有的域和值。在返回值里,紧跟每个域名(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。

7. hdel

HDEL key field [field ...] 删除哈希表 key中的一个或多个指定域,不存在的域将被忽略。

8. hlen


HLEN key

返回哈希表key对应的field的数量。


9. hexists

HEXISTS key field 查看哈希表 key中,给定域 field是否存在。

10. hkeys


HKEYS key

获得哈希表中key对应的所有field。


11. hvals


HVALS key

获得哈希表中key对应的所有values。


12. hincrby

为哈希表key中的域field的值加上增量increment。增量也可以为负数,相当于对给定域进行减法操作。如果key不存在,一个新的哈希表被创建并执行hincrby命令。如果域field不存在,那么在执行命令前,域的值被初始化为0。对一个储存字符串值的域field执行hincrby命令将造成一个错误。本操作的值限制在64位(bit)有符号数字表示之内。

更多详细信息请参照:http://redis.readthedocs.org/en/2.4/hash.html

下面是利用redis c++客户端编写的测试程序:

  1. #include "redisclient.h"  
  2.   
  3. #include "tests/functions.h"  
  4.   
  5. #include <iostream>  
  6.   
  7. #include <boost/date_time.hpp>  
  8.   
  9. #define OUT(x) std::cout<<#x<<" = "<<x<<std::endl;  
  10.   
  11. boost::shared_ptr<redis::client> init_non_cluster_client();  
  12. void test_hash(redis::client & c);  
  13.   
  14. int main(int argv, char* argc[])   
  15. {  
  16.     boost::shared_ptr<redis::client> shared_c;  
  17.   
  18.     shared_c = init_non_cluster_client();  
  19.   
  20.     redis::client& c = *shared_c;  
  21.   
  22.     test_hash(c);  
  23.   
  24.     return 0;  
  25. }  
  26. void test_hash(redis::client & c)  
  27. {  
  28.     test("test hash type");  
  29.   
  30.     test("hset & hget & hsetnx");  
  31.     {  
  32.         // hset: key, field, value  
  33.         OUT(c.hset("favorites""taobao""www.taobao.com"));  
  34.         OUT(c.hset("favorites""taobao""www.taobao.com#"));  
  35.         OUT(c.hget("favorites""taobao"));  
  36.         OUT(c.hsetnx("favorites""taobao""www.taobao.com"));  
  37.         OUT(c.hget("favorites""taobao"));  
  38.     }  
  39.   
  40.     test("hmset & hmget & hgetall & hdel & hexists");  
  41.     {  
  42.         redis::client::string_vector fields, values, getvalues;  
  43.         fields.push_back("tmall");  
  44.         fields.push_back("alibaba");  
  45.         values.push_back("www.tmall.com");  
  46.         values.push_back("www.1688.com");  
  47.         c.hmset("favorites", fields, values);  
  48.         // 类型错误,报错  
  49.         c.set("string_key""string_value");  
  50.         //c.hmset("string_key", fields, values);  
  51.         fields.push_back("etao");  
  52.         c.hmget("favorites", fields, getvalues);  
  53.         OUT(getvalues.size());  
  54.         for(int i=0; i<getvalues.size(); ++i) {  
  55.             OUT(getvalues[i]);  
  56.         }  
  57.   
  58.         redis::client::string_pair_vector pairs;  
  59.         c.hgetall("favorites", pairs);  
  60.         OUT(pairs.size());  
  61.         for(int i=0; i<pairs.size(); ++i) {  
  62.             OUT(pairs[i].first);  
  63.             OUT(pairs[i].second);  
  64.         }  
  65.   
  66.         OUT(c.hset("favorites""etao""www.etao.com"));  
  67.         OUT(c.hlen("favorites"));  
  68.         pairs.clear();  
  69.         c.hdel("favorites""etao");  
  70.         c.hdel("favorites""koubei");  
  71.         c.hgetall("favorites", pairs);  
  72.         OUT(pairs.size());  
  73.         for(int i=0; i<pairs.size(); ++i) {  
  74.             OUT(pairs[i].first);  
  75.             OUT(pairs[i].second);  
  76.         }  
  77.   
  78.         OUT(c.hexists("favorites""taobao"));  
  79.         OUT(c.hexists("favorites""koubei"));  
  80.     }  
  81.   
  82.     test("hincrby & hkeys & hvals");  
  83.     {  
  84.         OUT(c.hset("lists""age""20"));  
  85.         OUT(c.hincrby("lists""age", 5));  
  86.         redis::client::string_vector keys;  
  87.         c.hkeys("lists", keys);  
  88.         for(size_t i=0; i<keys.size(); ++i) {  
  89.             OUT(keys[i]);  
  90.         }  
  91.         redis::client::string_vector vals;  
  92.         c.hvals("lists", vals);  
  93.         for(size_t i=0; i<keys.size(); ++i) {  
  94.             OUT(vals[i]);  
  95.         }  
  96.     }  
  97. }  


redis:list数据类型与操作

redis数据类型之list:redis list数据类型是一个双向循环链表。redis.conf中的相关配置如下:

[plain]  view plain copy print ?
  1. 428 # Similarly to hashes, small lists are also encoded in a special way in order  
  2. 429 # to save a lot of space. The special representation is only used when  
  3. 430 # you are under the following limits:  
  4. 431 list-max-ziplist-entries 512  
  5. 432 list-max-ziplist-value 64  

对于list的操作详见: http://redis.readthedocs.org/en/2.4/list.html


redis c++接口的调用:

  1. #include "redisclient.h"  
  2.   
  3. #include "tests/functions.h"  
  4.   
  5. #include <iostream>  
  6.   
  7. #include <boost/date_time.hpp>  
  8.   
  9. #define OUT(x) std::cout<<#x<<" = "<<x<<std::endl;  
  10.   
  11. boost::shared_ptr<redis::client> init_non_cluster_client();  
  12.   
  13. void test_list(redis::client & c);  
  14.   
  15. int main(int argv, char* argc[])   
  16. {  
  17.     boost::shared_ptr<redis::client> shared_c;  
  18.   
  19.     shared_c = init_non_cluster_client();  
  20.   
  21.     redis::client& c = *shared_c;  
  22.   
  23.     test_list(c);  
  24.   
  25.     return 0;  
  26. }  
  27. void test_list(redis::client & c)  
  28. {  
  29.     test("test redis list type.");  
  30.   
  31.     while(c.llen("list")>0) {  
  32.         OUT(c.lpop("list"));  
  33.     }  
  34.   
  35.     test("lpush & rpush & lpop & rpop & blpop & brpop");  
  36.     {  
  37.         OUT( c.lpush("list""lpush1") );  
  38.         OUT( c.lpush("list""lpush2") );  
  39.         OUT( c.rpush("list""rpush1") );  
  40.         OUT( c.rpush("list""rpush2") );  
  41.         OUT( c.llen("list") );  
  42.   
  43.         redis::client::string_vector out;  
  44.         OUT( c.lrange("list", 0, 10, out) );  
  45.         for(size_t i=0; i<out.size(); ++ i) {  
  46.             OUT(out[i]);  
  47.         }  
  48.   
  49.         OUT( c.lpop("list") );  
  50.         OUT( c.rpop("list") );  
  51.         OUT( c.llen("list") );  
  52.         OUT( c.lpush("list""lpush2") );  
  53.         OUT( c.rpush("list""rpush2") );  
  54.         OUT( c.llen("list") );  
  55.         OUT( c.blpop("list1", 1) );  
  56.         OUT( c.blpop("list", 1) );  
  57.         OUT( c.brpop("list1", 1) );  
  58.         OUT( c.brpop("list", 1) );  
  59.         OUT( c.llen("list") );  
  60.     }  
  61.   
  62.     test("llen & lrange & ltrim");  
  63.     {  
  64.         OUT( c.llen("list") );  
  65.         redis::client::string_vector out;  
  66.         OUT( c.lrange("list", 0, 10, out) );  
  67.         for(size_t i=0; i<out.size(); ++ i) {  
  68.             OUT(out[i]);  
  69.         }  
  70.         c.ltrim("list", 0, 2);  
  71.         OUT( c.lrange("list", 0, 10, out) );  
  72.         for(size_t i=0; i<out.size(); ++ i) {  
  73.             OUT(out[i]);  
  74.         }  
  75.         OUT( c.llen("list") );  
  76.     }  
  77.   
  78.     test("lrem");  
  79.     {  
  80.         OUT( c.llen("list") );  
  81.         OUT( c.lrem("list", 1, "lpush1") );  
  82.         OUT( c.lrem("list", -1, "lpush2") );  
  83.         OUT( c.llen("list") );  
  84.     }  
  85.   
  86.     test("lset & lindex");  
  87.     {  
  88.         OUT( c.lindex("list", 0) );  
  89.         c.lset("list", 0, "set new value of index 0");  
  90.         OUT( c.lindex("list", 0) );  
  91.     }  
  92. }  

 

redis:set数据类型与操作


  set是集合。我们可以向一个集合中“插入”,“删除”元素,也可以计算两个集合的“交集”,“并集”,及“作差”。如:

假设有集合A,B。

其中,A={1,2,3,4,5},B={4,5,6,7,8}。

那么,

交集:inter(A,B)= {4,5}

并集:union(A, B)= {1,2,3,4,5,6,7,8}

差集:diff(A,B)= {1,2,3},即属于集合A,但不属于集合B的元素


    set的是通过hash table实现的,所以添加、删除和查找的复杂度都是O(1)。hash table会随着添加或者删除自动的调整大小。需要注意的是调整hash table大小时候需要同步(获取写锁)会阻塞其他读写操作,可能不久后就会改用跳表(skip list)来实现,跳表已经在sorted set中使用了。(引自:http://hb.qq.com/a/20111001/000022.htm)


    关于set数据类型的操作详见:http://redis.readthedocs.org/en/2.4/set.html

    下面结合redis c++接口,了解一下这些基本操作。

  1. #include "redisclient.h"  
  2.   
  3. #include "tests/functions.h"  
  4.   
  5. #include <iostream>  
  6.   
  7. #include <boost/date_time.hpp>  
  8.   
  9. #define OUT(x) std::cout<<#x<<" = "<<x<<std::endl;  
  10.   
  11. boost::shared_ptr<redis::client> init_non_cluster_client();  
  12.   
  13. void output_set(redis::client::string_set & sset);  
  14.   
  15. void test_set(redis::client & c);  
  16.   
  17. int main(int argv, char* argc[])   
  18. {  
  19.     boost::shared_ptr<redis::client> shared_c;  
  20.   
  21.     shared_c = init_non_cluster_client();  
  22.   
  23.     redis::client& c = *shared_c;  
  24.   
  25.     test_set(c);  
  26.   
  27.     return 0;  
  28. }  
  29.   
  30. void test_set(redis::client & c)  
  31. {  
  32.     test("test redis set type.");  
  33.   
  34.     test("sadd");  
  35.     {  
  36.         std::vector<std::string> vals;  
  37.         for(size_t i=0; i<10; ++i) {  
  38.             char ch = (char)('A'+i);  
  39.             std::string tmp ="";  
  40.             tmp += ch;  
  41.             vals.push_back(tmp);  
  42.         }  
  43.         std::vector<std::string>::iterator it;  
  44.         c.sadd("set_a", vals.begin(), vals.end());  
  45.     }  
  46.   
  47.     test("smembers");  
  48.     {  
  49.         redis::client::string_set out;  
  50.         OUT(c.smembers("set_a", out));  
  51.         output_set( out );  
  52.     }  
  53.   
  54.     test("srem");  
  55.     {  
  56.         c.srem("set_a""A");  
  57.         redis::client::string_set out;  
  58.         OUT(c.smembers("set_a", out));  
  59.         output_set( out );  
  60.     }  
  61.   
  62.     test("sismember");  
  63.     {  
  64.         OUT( c.sismember("set_a""A") );  
  65.         OUT( c.sismember("set_a""B") );  
  66.     }  
  67.   
  68.     test("scard");  
  69.     {  
  70.         OUT( c.scard("set_a") );  
  71.     }  
  72.   
  73.     test("smove");  
  74.     {  
  75.         c.smove("set_a""set_b""B");  
  76.         redis::client::string_set out;  
  77.         OUT(c.smembers("set_a", out));  
  78.         output_set(out);  
  79.   
  80.         out.clear();  
  81.         OUT(c.smembers("set_b", out));  
  82.         output_set( out );  
  83.     }  
  84.   
  85.     test("spop");  
  86.     {  
  87.         OUT( c.scard("set_a") );  
  88.         OUT( c.spop("set_a") );  
  89.         OUT( c.scard("set_a") );  
  90.     }  
  91.   
  92.     test("srandmember");  
  93.     {  
  94.         OUT( c.srandmember("set_a") );  
  95.     }  
  96.   
  97.     test("sinter");  
  98.     {  
  99.         c.sadd("set_b""C");  
  100.         c.sadd("set_b""F");  
  101.         redis::client::string_vector keys;  
  102.         keys.push_back("set_a");  
  103.         keys.push_back("set_b");  
  104.         redis::client::string_set out;  
  105.         c.smembers("set_a", out);  
  106.         std::cout<<"set a:  *******************"<<std::endl;  
  107.         output_set(out);  
  108.         out.clear();  
  109.         c.smembers("set_b", out);  
  110.         std::cout<<"set b:  *******************"<<std::endl;  
  111.         output_set(out);  
  112.         c.sinter(keys, out);  
  113.         output_set(out);  
  114.     }  
  115.   
  116.     test("sinterstore");  
  117.     {  
  118.         redis::client::string_vector keys;  
  119.         redis::client::string_set out;  
  120.         keys.push_back("set_a");  
  121.         keys.push_back("set_b");  
  122.         c.sinterstore("set_c", keys);  
  123.         c.smembers("set_c", out);  
  124.         output_set(out);  
  125.     }  
  126.   
  127.     test("sunion & sunionstore");  
  128.     {  
  129.         redis::client::string_vector keys;  
  130.         redis::client::string_set out;  
  131.         keys.push_back("set_a");  
  132.         keys.push_back("set_b");  
  133.         c.sunion(keys, out);  
  134.         output_set(out);  
  135.         out.clear();  
  136.         c.sunionstore("set_d", keys);  
  137.         c.smembers("set_d", out);  
  138.         std::cout<<"set d: ****************"<<std::endl;  
  139.         output_set(out);  
  140.     }  
  141.   
  142.     test("sdiff * sdiffstore");  
  143.     {  
  144.         redis::client::string_vector keys;  
  145.         redis::client::string_set out;  
  146.         keys.push_back("set_a");  
  147.         keys.push_back("set_b");  
  148.         c.sdiff(keys, out);  
  149.         output_set(out);  
  150.         out.clear();  
  151.         c.sdiffstore("set_e", keys);  
  152.         c.smembers("set_e", out);  
  153.         std::cout<<"set e: ****************"<<std::endl;  
  154.         output_set(out);      
  155.     }  
  156. }  
  157.   
  158. void output_set(redis::client::string_set & sset)  
  159. {  
  160.     size_t size = sset.size();  
  161.     OUT(size);  
  162.     redis::client::string_set::iterator it;  
  163.     for(it=sset.begin(); it!=sset.end(); ++it) {  
  164.         OUT(*it);  
  165.     }  
  166. }  


redis: sorted set数据类型与操作

  redis支持有序集合,即sorted sets数据类型。基本格式为:

key --> member -- score

    |  --> member -- score


    sorted set类型的实现采用了两个数据结构:hash table 和 skip list(跳跃表),其中hash table是具体使用redis中的dict来实现的,主要是为了保证查询效率为O(1) ,而skip list(跳跃表)主要是保证元素有序并能够保证INSERT和REMOVE操作是O(logn)的复杂度。


    sorted set的基本操作详见:http://redis.readthedocs.org/en/2.4/sorted_set.html

    利用redis c++接口,验证zset的基本操作:

  1. #include "redisclient.h"  
  2.   
  3. #include "tests/functions.h"  
  4.   
  5. #include <iostream>  
  6.   
  7. #include <boost/date_time.hpp>  
  8.   
  9. #define OUT(x) std::cout<<#x<<" = "<<x<<std::endl;  
  10.   
  11. boost::shared_ptr<redis::client> init_non_cluster_client();  
  12.   
  13. void output_set(redis::client::string_set & sset);  
  14. void output_sort_set(redis::client & c, std::string & key);  
  15.   
  16. void test_sorted_set(redis::client & c);  
  17.   
  18. int main(int argv, char* argc[])   
  19. {  
  20.     boost::shared_ptr<redis::client> shared_c;  
  21.   
  22.     shared_c = init_non_cluster_client();  
  23.   
  24.     redis::client& c = *shared_c;  
  25.   
  26.     test_sorted_set(c);  
  27.   
  28.     return 0;  
  29. }  
  30.   
  31. void test_sorted_set(redis::client & c)  
  32. {  
  33.     test("test sorted set:");  
  34.   
  35.     std::string key = "page_rank";  
  36.     test("zadd");  
  37.     {  
  38.         c.zadd(key, 10, "taobao.com");  
  39.         c.zadd(key, 9, "tmall.com");  
  40.         c.zadd(key, make_pair("tmall.com", 11.1) );  
  41.         output_sort_set(c, key);  
  42.     }  
  43.       
  44.     test("zrem");  
  45.     {  
  46.         c.zrem(key, "taobao.com");  
  47.         output_sort_set(c, key);  
  48.     }  
  49.   
  50.     test("zcount");  
  51.     {  
  52.         OUT(c.zcount(key, 0, 5));  
  53.         c.zadd(key, 3.6, "etao.com");  
  54.         OUT(c.zcount(key, 0, 5));  
  55.     }  
  56.   
  57.     test("zincrby");  
  58.     {  
  59.         c.zincrby(key,"etao.com", 3);  
  60.         c.zincrby(key,"koubei.com", 5);  
  61.         output_sort_set(c, key);  
  62.     }  
  63.   
  64.     test("zrevrange");  
  65.     {  
  66.         redis::client::string_vector out;  
  67.         c.zrevrange(key, 0, -1, out);  
  68.         for(size_t i=0; i<out.size(); ++i) {  
  69.             OUT(out[i]);  
  70.         }  
  71.     }  
  72.   
  73.     test("zrangebyscore");  
  74.     {  
  75.         redis::client::string_score_vector out;  
  76.         c.zrangebyscore(key, 0, 20, out, 0, 2);  
  77.         for(size_t i=0; i<out.size(); i++) {  
  78.             OUT(out[i].first);  
  79.             OUT(out[i].second);  
  80.         }  
  81.     }  
  82.   
  83.     test("zrank & zrevrank");  
  84.     {  
  85.         OUT(c.zrank(key, "etao.com"));  
  86.         OUT(c.zrevrank(key, "etao.com"));  
  87.     }  
  88.   
  89.     test("zremrangebyrank & zremrangebyscore");  
  90.     {  
  91.         c.zremrangebyrank(key, 0, 0);  
  92.         c.zremrangebyscore(key, 0, 10);  
  93.         output_sort_set(c, key);  
  94.     }  
  95.   
  96.     test("zinterstore & zunionstore");  
  97.     {  
  98.         c.zadd("website", 10, "taobao.com");  
  99.         c.zadd("website", 8, "google.com");  
  100.         c.zadd("website", 0, "baidu.com");  
  101.         c.zadd("website", 7, "tmall.com");  
  102.   
  103.         redis::client::string_vector keys;  
  104.         keys.push_back(key);  
  105.         keys.push_back("website");  
  106.       
  107.         std::string sinter("inter");  
  108.         std::string sunion("union");  
  109.         c.zinterstore(sinter, keys);  
  110.         c.zunionstore(sunion, keys);  
  111.   
  112.         std::cout<<"inter :"<<std::endl;  
  113.         output_sort_set(c, sinter);  
  114.         std::cout<<"union :"<<std::endl;  
  115.         output_sort_set(c, sunion);  
  116.     }  
  117. }  
  118.   
  119. void output_sort_set(redis::client & c, std::string & key)  
  120. {  
  121.     OUT( c.zcard(key) );  
  122.     redis::client::string_vector out;  
  123.     c.zrange(key, 0, -1, out);  
  124.     for(size_t i=0; i<out.size(); ++i) {  
  125.         OUT(out[i]);  
  126.         OUT( c.zscore(key, out[i]) );  
  127.     }  
  128. }  

PS:

redis c++接口在实现zset操作时,有两个小bug:

1. void recv_int_ok_reply_(int socket)

原来实现,当recv_int_reply_(socket) != 1时,就认为有错误,从而抛出异常:throw protocol_error("expecting int reply of 1");

但实际上,如zadd操作:

如果某个member已经是有序集的成员,那么更新这个memberscore值,并通过重新插入这个member元素,来保证该member在正确的位置上,并返回0; add成功返回1;如果key不存在,则创建一个空的有序集并执行zadd操作;当key存在但不是有序集类型时,返回一个错误。

修改:

  1. void recv_int_ok_reply_(int socket)  
  2. {      
  3.   if (recv_int_reply_(socket) < 0)   
  4.     throw protocol_error("expecting int reply of <0");  
  5. }   

2.  void zrangebyscore(const string_type & key, double min, double max, string_score_vector & out, int_type offset = 0, int_type      max_count = -1, int range_modification = 0)

调用,zrangebyscore_base(true, key, min, max, res, offset, max_count, range_modification);

第一个参数值等于true表明,需要返回score值。但是,zrangebyscore_base在实现时并未考虑这一参数。

修改:在zrangebyscore_base函数实现时,加上

  1. if(withscores) {  
  2.   m << "WITHSCORES";  
  3. }  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值