Redis常用数据结构及其场景归纳

469 阅读5分钟

1 mset、mget、msetnx

批量处理字符串更新、获取、加锁
场景:文章的标题、内容、作者等多个key 批量发布和查看(对于这种可以直接用序列化反序列化。。)

2 strlen、getrange

统计文章字数、预览文章(截取文章)
场景:博客字数统计和文章预览

3 append

拼接字符串
场景:日志拼接(也是很少用)

4 hset、hget

场景:记录生成次数

5 lindex、lset、linsert、ltrim、lrem、lpush

  • 获取list指定下标元素:lindex mylist 0 "bar"
  • 更新list指定下标元素:lset mylist 0 "bar"
  • 插入list指定前后的元素:linsert key BEFORE|AFTER pivot value
  • 删除list除了某个范围外的所有数据:ltrim mylist 1 -1 // -1表示最后一个元素,即除了[1, 最后一个],其余都删掉
  • 删除list指定范围元素:lrem mylist 1 -1 // 删除[1, 最后一个]元素
  • 添加list元素:lpush list "bar"

6 lpush、brpop

用redis实现类型MQ功能,lpush key value, brpop key // brpop是阻塞式,有数据就弹出

7 sadd、scard

加入集合、统计集合元素个数
场景:uv统计(统计当前去重后的用户数量 - 不用hyperloglog条件下)

8 srem、sismember、smembers、sinter、sdiff

删除集合元素、判断是否存在集合中、返回集合所有元素、取两个集合交集、取两个集合差集
场景:可结合7中的两个来 对标签进行管理

场景二:朋友圈点赞。sadd添加点赞的好友、srem取消点赞、sismember判断是否被某人点赞(sismember moment_like_users::1 10086,1是朋友圈ID,10086是用户ID)、smember获取点赞的所有用户、scard统计点赞数量

场景三:投票。同《场景二》

场景四:类似微博的社交关系。需要sadd每次维护关注和被关注集合,然后取关srem移除这两个集合。对于千万级关注量的,就需要维护关注、被关注的计数器,并且只存储部分关注id

场景五:微博关注与推荐关注。首先微博关注上线是 2000 ,所以取两个用户共同关注的(也可以用sdiff取差集 - 推荐关注(就是朋友关注了我没关注的)),直接取交集即可(sinter)。

场景六:为商品搜索构建反向索引。sadd给对应关键词添加一个集合,sinter取关键词的交集返回。其实就是为每一个关键词赋予一个集合,但是这样反向的关键词量级可能会比较大。

void addProduct(long produceId, List<String> kws) {
    for (String kw : kws) jedis.sadd("kw::" + kw + "::products", String.valueOf(produceId));
}
Set<String> searchProduct(List<String> kws) {
    List<String> kwsList = new ArrayList<>();
    for (String kw : kws) kwsList.add("kw::" + kw + "::products");
    return jedis.sinter(kwsList.toArray(new String[kwsList.size()]))
}

9 srandommember、spop

随机从集合返回几个元素、随机从集合弹出几个元素
场景:网站上的抽奖程序。sadd加入待抽奖名单,smembers返回所有待抽奖人,scard返回待抽奖人数,srandommember返回随机抽中的名单

  • smembers可能出现的性能问题?

如果集合里面数据量超过千万级别,调用该命令会造成线程长时间阻塞,所以需要把集合拆分成多个小集合来处理。

10 zadd、zscore、zrem、zincrby、zrevrank、zrevrange

  • 添加有序集合元素:zadd key score value
  • 获取当前元素的分数:score key member [member ...]
  • 删除有序集合中指定的元素:zrem key member
  • 增加有序集合元素分数:zincrby key increment member
  • 获取当前元素在集合中的排序:zrevrank key member
  • 获取递增或递减分数的范围的数据:
    • ZRANGE salary 0 -1 WITHSCORES # 递增排列
    • ZREVRANGE salary 0 -1 WITHSCORES # 递减排列

场景:实现音乐网站的排行榜程序

11 pfadd、pfcount、pfmerge

  • 添加元素:pfadd key element [element ...]
  • 统计去重后的数据结果:pfcount key
  • 合并多个HyperLogLog:pfmerge destKey sourceKey1 sourceKey2

场景:HyperLogLog统计访问UV(去重),上亿用户统计也只占用12kb,标准误差率0.81%。

场景2:周活跃用户数、月活跃用户数、年活跃用户数的统计。为每一天、月建立一个hyperloglog,然后pfmerge合并出周、月、年的统计。

12 setbit、getbit、bitcount

  • 设置对应偏移量的值:setbit key offset [value] // value是0或1
  • 获取对应偏移量的值:getbit key offset
  • 统计当前位图的1的个数:bitcount key

场景:基于位图统计用户访问UV。比如记录用户id=10086:setbit visit_uv 10086 1 // 如果一个位不够统计,那就两个位

13 geoadd、geopos、geodist、georadius、georadiusbymember、geohash

  • 存储地理位置:geoadd key 经度 纬度 member [经度 纬度 member]

  • 获取地理位置:geopos key member [member]

  • 返回两个给定位置之间距离:geodist key member1 member2 [m|km|ft|mi] // 最后一个参数是单位,米、千米、英尺、英里

  • 返回给定坐标下一定范围距离的所有位置元素:georadius key 经度 纬度 radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]

    • 举例:GEORADIUS Sicily 15 37 200 km WITHDIST
  • 返回给定元素一定范围距离的所有位置元素:georadiusbymember key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]

  • 获取一个或多个位置元素的 geohash 值:geohash key member [member ...]

场景:基于GeoHash的你与商铺距离计算的程序。
场景2:查找附近的人。用georadiusbymember即可找到其在一定范围的用户

14 pipeline

管道命令批量传输