这段时间学了一些redis五种常用类型基本操作,看见好多人说有序集合比较适合实现各种各样的排行榜功能,我就想到了微信步数排行榜,想到了我是不是可以通过有序集合来实现这个功能呢。

那就来试试看吧! (想法可能不成熟,勿喷!!)

微信步数排行榜的基本功能

要实现微信步数排行榜先看看微信步数排行榜都有什么功能

  1. 最基本的功能,查看排行信息 、点赞

  2. 凌晨刷新步数,全部清除为0

  3. 已占领N个朋友的封面

  4. 加入、退出 排行榜

    消息可以使用spring的Task定时每天十点半发送消息,不是redis的功能

  5. 不与他排行

    不让这个人参与我的排行榜

  6. 停用

    与退出排行榜差不多

功能实现

首先假定微信运动用户为以下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
127.0.0.1:6379> zadd rankall 0 aaaa 0 bbbb 0 cccc 0 dddd 0 eeee 0 ffff 0 gggg 0 hhhh 0 iiii 0 jjjj 0 kkkk 0  xiaoming  0 libai 0 zhangsan 0 lisi  0 wangwu 0 xiongda 0 kirari
127.0.0.1:6379> ZRANGE rankall 0 -1
1) "aaaa"
2) "bbbb"
3) "cccc"
4) "dddd"
5) "eeee"
6) "ffff"
7) "gggg"
8) "hhhh"
9) "iiii"
10) "jjjj"
11) "kirari"
12) "kkkk"
13) "libai"
14) "lisi"
15) "wangwu"
16) "xiaoming"
17) "xiongda"
18) "zhangsan"

用户Kirari的好友们有

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> zadd kirariRank 0 aaaa 0 bbbb 0  cccc 0 libai 0 lisi 0 xiaoming 0 kirari
(integer) 6
127.0.0.1:6379> ZRANGE kirariRank 0 -1
1) "libai"
2) "xiaoming"
3) "lisi"
4) "cccc"
5) "kirari"
6) "aaaa"
7) "bbbb"

排行榜的实现

默默造数据中…..不会写shell脚本

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> ZINCRBY rankall 9999 kirari
"9999"
127.0.0.1:6379> ZINCRBY rankall 10000 aaaa
"10000"
127.0.0.1:6379> ZINCRBY rankall 3691 lisi
"3691"
127.0.0.1:6379> ZINCRBY rankall 5963 cccc
"5963"
127.0.0.1:6379> ZINCRBY rankall 20000 bbbb
"20000"

微信运动在数据来源(用户的手机、手表)收集到了运动数据后现在总排行榜进行设置运动步数

当用户发动请求查看运动排行榜时使用并集把数据赋值给赋值给用户就完成了排行榜的实现:

ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
127.0.0.1:6379> ZINTERSTORE kirariRank 2 kirariRank rankall aggregate max
(integer) 7
127.0.0.1:6379> ZREVRANGE kirariRank 0 -1 withscores
1) "bbbb"
2) "20000"
3) "aaaa"
4) "10000"
5) "kirari"
6) "9999"
7) "cccc"
8) "5963"
9) "lisi"
10) "3691"
11) "xiaoming"
12) "0"
13) "libai"
14) "0"

注意进行交集运算的时候是要rankall总排行榜与用户的交集而不是把rankall整个复制(踩坑了…)

并且设置模式为最大值替换,因为你的好友可能会在运动!

排行榜做好了,发现bbbb用户是运动步数最多的人,并且按照步数从大到小进行排名!

整点运动步数清零

我想到的方法是再创建一个有序集合,这个有序集合中的所有score均为0

每当一天过去的零点整点发送命令:

ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]

来实现零点运动步数清零(这里使用交集和并集合似乎都可以,但是为了后面的停用功能使用交集)

测试:

现在的情况只有kirari是有步数(懒得造数据….只要被清零效果都一样)

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> ZREVRANGE rankall 0 -1 withscores
1) "kirari"
2) "11"
3) "zhangsan"
4) "0"
5) "xiongda"
6) "0"
7) "xiaoming"
8) "0"
....

到了零点发送命令:ZINTERSTORE rankall 1 zero aggregate min

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> ZINTERSTORE rankall 2 zero rankall aggregate min
(integer) 18
127.0.0.1:6379> ZRANGE rankall 0 -1 withscores
1) "aaaa"
2) "0"
3) "bbbb"
4) "0"
5) "cccc"
6) "0"
......

发现所有步数数据已经清零

点赞

使用集合来实现

用户aaaa、bbbb、cccc点赞给kirari点赞,查看点赞的人是谁,随后bbbb又取消点赞的实现:

  1. 用户aaaa、bbbb、cccc惊叹我的运动步数来给我点赞
    1
    2
    127.0.0.1:6379> sadd kirariGood aaaa bbbb cccc
    (integer) 3
  2. 我查看有谁给我点赞了
    1
    2
    3
    4
    127.0.0.1:6379> SMEMBERS kirariGood
    1) "cccc"
    2) "bbbb"
    3) "aaaa"
  3. 看看点赞的人数
    1
    2
    127.0.0.1:6379> SCARD kirariGood
    (integer) 3
  4. bbbb不知道是嫉妒我的运动步数,还是喜欢我害羞了不敢看我的运动步数取消了点赞
    1
    2
    127.0.0.1:6379> SREM kirariGood bbbb
    (integer) 1
  5. 我这个时候查看给我点赞的人发现bbbb不见了
    1
    2
    3
    127.0.0.1:6379> SMEMBERS kirariGood
    1) "cccc"
    2) "aaaa"
  6. 点赞人数也变成了2
    1
    2
    127.0.0.1:6379> SCARD kirariGood
    (integer) 2
  7. 第二天到了清除所有的点赞数据
    1
    2
    3
    4
    127.0.0.1:6379> del kirariGood
    (integer) 1
    127.0.0.1:6379> SCARD kirariGood
    (integer) 0

占领N个朋友的封面

我的想法只有遍历所有开通微信运动的好友中遍历一边,看自己的排名是第几名

是第一就加一,不是则遍历到最后

先看一下排行榜:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
127.0.0.1:6379> ZREVRANGE kirariRank 0 -1 withscores
1) "bbbb"
2) "20000"
3) "aaaa"
4) "10000"
5) "kirari"
6) "9999"
7) "cccc"
8) "5963"
9) "lisi"
10) "3691"
11) "xiaoming"
12) "0"
13) "libai"
14) "0"

查看排名:

1
2
127.0.0.1:6379> ZREVRANK kirariRank kirari
(integer) 2

注意此时的索引是从0开始的,所以排名要在索引加上1

即此时我的排名在我的排行榜里是第三名

不让他参与我的排名

类似删除好友,把这个用户从我的好友中移除

我们先看一下排行榜

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
127.0.0.1:6379> ZINTERSTORE kirariRank 2 kirariRank rankall aggregate max
(integer) 7
127.0.0.1:6379> ZREVRANGE kirariRank 0 -1 withscores
1) "bbbb"
2) "20000"
3) "aaaa"
4) "10000"
5) "kirari"
6) "9999"
7) "cccc"
8) "5963"
9) "lisi"
10) "3691"
11) "xiaoming"
12) "0"
13) "libai"
14) "0"

可恶!!bbbb居然比我多这么多步,我不想见到他!

不想见到他

1
2
127.0.0.1:6379> zrem kirariRank bbbb
(integer) 1

再看一下排行榜

1
2
3
4
5
6
7
8
9
10
11
12
13
127.0.0.1:6379> ZREVRANGE kirariRank 0 -1 withscores
1) "aaaa"
2) "10000"
3) "kirari"
4) "9999"
5) "cccc"
6) "5963"
7) "lisi"
8) "3691"
9) "xiaoming"
10) "0"
11) "libai"
12) "0"

发现bbbb从我的排行榜消失了

不加入排行榜

把我从我自己的表中删除,且从rankall集合中删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
127.0.0.1:6379> zrem kirariRank kirari
(integer) 1
127.0.0.1:6379> zrem rankall kirari
(integer) 1
127.0.0.1:6379> ZREVRANGE kirariRank 0 -1 withscores
1) "aaaa"
2) "10000"
3) "cccc"
4) "5963"
5) "lisi"
6) "3691"
7) "xiaoming"
8) "0"
9) "libai"
10) "0"

我就从排行榜消失了

停用微信运动

从排行榜集合和整点清零集合中移除,且删除用户 的排行榜集合

1
2
3
4
5
6
127.0.0.1:6379> zrem kirariRank kirari
(integer) 1
127.0.0.1:6379> zrem zero kirari
(integer) 1
127.0.0.1:6379> del kirariRank
(integer) 1