原文:Redis简单案例(三) 连续登陆活动的简单实现

  连续登陆活动,或许大家都不会陌生,简单理解就是用户连续登陆了多少天之后,系统就会送一些礼品给相应的用户。最常见的

莫过于游戏和商城这些。游戏就送游戏币之类的东西,商城就送一些礼券。正值国庆,应该也有不少类似的活动。

  下面就对这个的实现提供两个思路,并提供解决方案。

  思路1(以用户为维度):

连续登陆活动,必然是要求连续登陆,不能有间隔。用1表示登陆,0表示没有登陆,这样我们可以为每个用户创建一个key去存储

他的登陆情况,就可以得到类似这样的一个二进制序列:1110111,如果是7个1,就表示连续7天,如果不是7个1就表示没有连续登

陆7天。所以就能实现这个登陆活动的要求了。

  思路2(以天数为维度):

  一天之内,用户要么是登陆过,要么是没有登陆过。同样的用1来表示登陆过,用0表示没有登陆过。假设我们连续登陆的活动是2天,

同时有3个用户,那么就要有2个key去存储这3个用户的登陆信息,这样就会得到类似这样的两个二进制序列:101(key1),111(key2)。

此时,对这两个key的每一位都进行逻辑与运算,就会得到101,就表明,用户1和用户3连续登陆了两天。从而达到活动的要求。

之前在string的基础教程中曾经说过关于二进制的相关操作会用一个简单的案例来给大家讲解,现在是兑现这个诺言的时候了。

  下面就简单模拟一下国庆7天假期连续登陆七天的活动。

  方案1 :以用户为维度

先为每个用户创建一个key(holiday:用户标识),对于我们的例子来说,每个key就会有7位二进制位。这时key会有这样的结构

  这时我们就会得到每个用户对应的二进制序列,然后就可以用bitcount命令去得到key含有的1的个数。如果等于7,就是连续登陆了

七天。这样就可以在第七天用户登陆的时间去处理了是否发送礼品了。处理的逻辑是十分简单的。控制器简单逻辑如下:

 1          [HttpPost]
 2         public IActionResult LoginForEveryone()
 3         {
 4             Random rd = new Random();
 5             var tran = _redis.GetTransaction();
 6             for (int i = 0; i < 7; i++)
 7             {
 8                 for (int j = 0; j < 1000; j++)
 9                 {
10                     string activity_key = string.Format("holiday:{0}", j.ToString());
11                     // login 1(true) other 0(false)
12                     if (rd.Next(0,10) > 6)
13                     {
14                         tran.StringSetBitAsync(activity_key, i, true);
15                     }
16                 }
17             }
18             tran.ExecuteAsync();
19
20             List<int> res = new List<int>();
21             for (int i = 0; i < 1000; i++)
22             {
23                 string activity_key = string.Format("holiday:{0}", i.ToString());
24                 //7 days
25                 if (_redis.BitCount(activity_key) == 7)
26                 {
27                     res.Add(i);
28                 }
29             }
30             return Json(new { code = "000", data = res, count = res.Count });
31         }

在这里还是用随机数的方法来模拟数据。主要操作有两个,一个是模拟登陆后把当天对应的偏移设置为1(true),另一个是取出用户

登陆的天数。这是一次性模拟操作,与正常情况的登陆操作还是有些许不同的。大致如下:

 1         [HttpPost]
 2         public IActionResult LoginForEveryone()
 3         {
 4             //1.login and get the identify of user
 5             //2.get the Current day and write to redis
 6             string activity_key = string.Format("holiday:{0}", "identify of user");
 7             _redis.SetBit(activity_key, currend day, true);
 8             //3.send gift
 9             if(currend day==7&& _redis.BitCount(activity_key)==7)
10             {
11                 send gift
12             }
13             return ...;
14         }

  回到我们模拟的情况,在界面展示时,模拟登陆后会显示累计登陆用户的id。

 1  <script id="everyoneTpl" type="text/html">
 2         <span>total:{{count}}</span>
 3         <ul>
 4             {{each data as item}}
 5             <li>
 6                 {{item}}
 7             </li>
 8             {{/each}}
 9         </ul>
10     </script>
11     <script>
12         $(function () {
13             $("#btn_everyone").click(function () {
14                 $.ajax({
15                     url: "/Holiday/LoginForEveryone",
16                     dataType: "json",
17                     method:"post",
18                     success: function (res) {
19                         if (res.code == "000") {
20                             var html = template('everyoneTpl', res);
21                             $("#div_everyone").html(html);
22                         }
23                     }
24                 })
25             });
26         })
27     </script>

下面来看看效果:

演示中:38、103、234、264、412、529这6位用户将得到连续登陆7天的礼品。

  方案2 :以天数为维度 
既然是以天数为维度,那么就要定义7个redis的key用来当作每天的登陆记录,类似:

  这样的话就要让我们的用户标识是数字才行,如果是用guid做的用户标识就要做一定的处理将其转化成数字,这样方便我们

在给用户设置是否登陆。现在假设我们的用户标识是从1~1000。用户标识对应的就是在key中的偏移量。这时我们就会得到每天

对应的二进制序列,然后就可以用bitop命令去得到逻辑与运算之后的key/value。如果这个key对应偏移量(用户标识)是1,就是

连续登陆了七天,处理的逻辑是十分简单的。控制器简单逻辑如下:

  1         [HttpPost]
  2         public IActionResult LoginForEveryday()
  3         {
  4             var tran = _redis.GetTransaction();
  5
  6             for (int i = 0; i < 7; i++)
  7             {
  8                 for (int j = 0; j < 1000; j++)
  9                 {
 10                     //i day,j userId
 11                     SetBit(i, j, tran);
 12                 }
 13             }
 14             tran.Execute();
 15             //get the result
 16             _redis.BitOP(_bitWise, _res, _redisKeys.ToArray());
 17             IList<int> res = new List<int>();
 18             for (int i = 0; i < 1000; i++)
 19             {
 20                 if (_redis.GetBit(_res, i) == true)
 21                 {
 22                     res.Add(i);
 23                 }
 24             }
 25             return Json(new { code = "000", data = res, count = res.Count });
 26         }
 27
 28
 29         private void SetBit(int day, int userId, StackExchange.Redis.ITransaction tran)
 30         {
 31             switch (day)
 32             {
 33                 case 0:
 34                     if (_rd.Next(0, 10) > 3)
 35                     {
 36                         tran.StringSetBitAsync(_first, userId, true);
 37                     }
 38                     else
 39                     {
 40                         tran.StringSetBitAsync(_first, userId, false);
 41                     }
 42                     break;
 43                 case 1:
 44                     if (_rd.Next(0, 10) > 3)
 45                     {
 46                         tran.StringSetBitAsync(_second, userId, true);
 47                     }
 48                     else
 49                     {
 50                         tran.StringSetBitAsync(_second, userId, false);
 51                     }
 52                     break;
 53                 case 2:
 54                     if (_rd.Next(0, 10) > 3)
 55                     {
 56                         tran.StringSetBitAsync(_thrid, userId, true);
 57                     }
 58                     else
 59                     {
 60                         tran.StringSetBitAsync(_thrid, userId, false);
 61                     }
 62                     break;
 63                 case 3:
 64                     if (_rd.Next(0, 10) > 3)
 65                     {
 66                         tran.StringSetBitAsync(_fourth, userId, true);
 67                     }
 68                     else
 69                     {
 70                         tran.StringSetBitAsync(_fourth, userId, false);
 71                     }
 72                     break;
 73                 case 4:
 74                     if (_rd.Next(0, 10) > 3)
 75                     {
 76                         tran.StringSetBitAsync(_fifth, userId, true);
 77                     }
 78                     else
 79                     {
 80                         tran.StringSetBitAsync(_fifth, userId, false);
 81                     }
 82                     break;
 83                 case 5:
 84                     if (_rd.Next(0, 10) > 3)
 85                     {
 86                         tran.StringSetBitAsync(_sixth, userId, true);
 87                     }
 88                     else
 89                     {
 90                         tran.StringSetBitAsync(_sixth, userId, false);
 91                     }
 92                     break;
 93                 case 6:
 94                     if (_rd.Next(0, 10) >3)
 95                     {
 96                         tran.StringSetBitAsync(_seventh, userId, true);
 97                     }
 98                     else
 99                     {
100                         tran.StringSetBitAsync(_seventh, userId, false);
101                     }
102                     break;
103                 default:
104                     break;
105             }
106         }

前台的处理与方案一的一模一样,所以就不贴代码了。下面来看看效果图。
可能光看效果图没太大意义,还是要看一下redis中的数据来验证一下的。图中取了76和991这两个用户标识(偏移量)来验证。

  可以看到76和991这两个偏移量(用户标识)对应的二进制位是1,也验证了其连续登陆了7天。当然,更多的明细数据也贴出来了

一大堆16进制的东西,有兴趣可以去转换成二进制试试。

对这两种方案简单的总结一下:
方案 优点 缺点
以用户为维度 1.可以无缝对接,无论用户标识是数字还是其他
2.key对应的数据较少便于观察
随着用户数量的增长,要管理的key会越来越多
以天数为维度 1.有确定数量的key,方便管理
2.key对应的基数大
1.偏移量可能需要根据实际情况处理
2.数据查看不是很清晰

  可至于实际中用那种方案更合适,要根据情况来选择。用户量少的时候,可以用第一种方案,也可以用第二种方案,当用户量很大的时候,

建议采用第二种方案,毕竟只要用户数量没有超过43亿,就不会超出其二进制位数的限制。是可以比较放心使用的。

Redis简单案例(三) 连续登陆活动的简单实现相关推荐

  1. Redis简单案例(二) 网站最近的访问用户

    原文:Redis简单案例(二) 网站最近的访问用户 我们有时会在网站中看到最后的访问用户.最近的活跃用户等等诸如此类的一些信息.本文就以最后的访问用户为例, 用Redis来实现这个小功能.在这之前,我 ...

  2. Redis简单案例(四) Session的管理

    Redis简单案例(四) Session的管理 原文:Redis简单案例(四) Session的管理 负载均衡,这应该是一个永恒的话题,也是一个十分重要的话题.毕竟当网站成长到一定程度,访问量自然也是 ...

  3. sql案例分析:统计连续登陆、日活、蚂蚁森林、排名等

    # 当天新用户hive -e \'select count(1) from hm2.daily_helper \where guid not in (select guid from hm2.hist ...

  4. Android复习12【广播接收者-BroadcastReceiver(简单案例-发送广播、静态注册、动态注册、本地广播、代码示例(别处登陆踢用户下线)、常用系统广播总结、音乐播放器)】

    2020-04-28[11周-周二] 音乐播放器Android代码下载:https://wws.lanzous.com/ifqzihaxvij 目   录 简单案例-发送广播 2)动态注册实例(监听网 ...

  5. zabbix生产环境案例(三)

    生产环境案例(三) 链接:https://pan.baidu.com/s/1q5YwJMTcZLcS5OQ0iOu44A 提取码:8gdi 复制这段内容后打开百度网盘手机App,操作更方便哦 1. Z ...

  6. 简单冲裁模、连续冲裁模、复合冲裁模,你搞懂了吗?

    一.冲裁模具按工序组合程度可分为:简单冲裁模.连续冲裁模.复合冲裁模. (一)简单冲裁模即敞开模 1.定义:它是指在一次冲裁中只完成冲孔或落料的一个工序. 2.简单冲裁模按其导向方式可分为: (1)无 ...

  7. Spring认证中国教育管理中心-Spring Data Redis框架教程三

    原标题:Spring认证中国教育管理中心-Spring Data Redis框架教程三 10.15.支持类 Packageorg.springframework.data.redis.support提 ...

  8. Redis故障案例(一)-特定key批量丢失

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/n88Lpo/article/details/78591111 作者:RogerZhuo 来源:DBA ...

  9. 数据分析与挖掘 - R语言:贝叶斯分类算法(案例三)

    案例三比较简单,不需要自己写公式算法,使用了R自带的naiveBayes函数. 代码如下: > library(e1071)> classifier<-naiveBayes(iris ...

最新文章

  1. 谈谈android反编译和防止反编译的方法
  2. ML之HierarchicalClustering:自定义HierarchicalClustering层次聚类算法
  3. C++类中成员变量的初始化有两种方式
  4. 在国外当程序员是什么体验?
  5. app后端设计(php)
  6. Tomcat为Cookie设置HttpOnly属性
  7. MySQl中文1001无标题_Mysql中字段类型不一致导致索引无效的处理办法
  8. mysql更新数据库中int 1_Mysql数据库int(1)和tinyint(1)的区别扩展阅读
  9. 属猴的人2021年运势预测
  10. 找不到Share Project(Subversion)_android studio
  11. ArcMAp10.2生成栅格数据时报错
  12. E - 娜娜梦游仙境系列——莫名其妙的插曲
  13. 电脑录音软件哪个好?六款常见的录音软件介绍
  14. docker使用阿里云Docker镜像库加速
  15. 服务器主机防护系统有哪些,什么是DDoS防护主机?
  16. wingide运行两个项目_Wing IDE使用教程:部分调试功能介绍
  17. Tesseract(识别验证码)
  18. 第二讲 中国古代密码艺术
  19. Buct oj 1015
  20. Ubuntu20.04修改root用户密码

热门文章

  1. python3抓取b站弹幕_python3写爬取B站视频弹幕功能
  2. iCMS v8.0.0多终端内容管理系统
  3. 魔众商城系统源码 v4.0.0 beta
  4. 安装服务器加硬盘分区,DOL服务器硬盘分区与安装模式
  5. oracle udev 多路径,Suse 11下多路径及udev配置
  6. 怎么让图片从左往右移动php,javascript - 想让图片上那个块,在增加块的宽度的时候向右边移动,而不是向左边移动。需要怎么解决?...
  7. 高性能JavaScript DOM编程
  8. DNS攻击原理与防范
  9. 视差滚动的爱情故事之优化篇
  10. 为facebook添加html/iframe页面 Create A Facebook Landing Page (Static HTML / iFrame)