阅读 355

《盲盒交友》内部如何保证不重复抽到同一个人?

前言

近期的《盲盒交友》甚是有些火热,但是作为职业反应,最关心的是程序实现是否复杂,以及有什么难度。

image.png

从本图中可以看到,他的界面简单易懂,大部分元素都是张图片,似乎用不了多大功夫就可以开发完成,但是难的地方在后端,有两个地方:支付以及保证不重复,支付咋门先不说,说说抽取功能如何保证同一个人抽不到相同的号,总不能让人家花上钱,抽到同一个人,这就过分了,所以这是必须要解决的。

解决办法很多,最粗暴的是获取到用户id,把每次抽到的微信号和用户id存储到数据表A里面,下次抽取的时候,判断A表中有没有这条对应记录即可,比如下面语句。

先获取u1用户所有抽过的记录的id,接着查询所有微信号,并使用not in从中剔除掉,接着在从里面随机取出一条即可。

SELECT * from test.tb_weichat  where id not in (SELECT  id from test.tb_recored  where user_id ='u1')
复制代码

比如使用RAND函数和LIMIT函数,进行随机一条,但是要记得把随机出来的插入到tb_recored表中。

SELECT * from test.tb_weichat  where id not in (SELECT  id from test.tb_recored  where user_id ='u1') order by RAND() LIMIT 1
复制代码

那还有什么好的办法呢?

当然有,我所知道的方式就是用位数组来实现。

位数组就是一个很长的数组,只不过内容除了1就是0,比如下面这样,当用户u1获取过id为4的微信号记录,那么我们就把第4位内容设置成1,代表读取过了。

image.png

有了这个历史记录,那么下次查询的时候同样可以使用not in剔除。

在Java中,可以使用BitSet,或者就是使用Redis,本来是要拿Redis演示的,但是无意间发现Java中有个官方的类,这个类就可以实现上述操作,缺点也很明显,还需要手动保存、手动加载,不像Redis可以自动持久化。

下面是BitSet的用法

 BitSet bitSet = new BitSet();
 bitSet.set(4);
 bitSet.set(5);
 bitSet.set(6);
 long[] longs = bitSet.toLongArray();
 for (long aLong : longs) {
     System.out.println(aLong);
 }
 System.out.println(bitSet);
复制代码

toLongArray会返回一个数组,但是里面的值你会觉得奇奇怪怪,这个值就是你设置过的bit信息,他会更具你设置的bit信息,生成一个long,也可以根据这个数组反向解析回去,比如下面这样。

BitSet bitSet = new BitSet();
bitSet.set(4);
bitSet.set(5);
bitSet.set(6);
long[] longs = bitSet.toLongArray();
System.out.println(BitSet.valueOf(longs).get(4));
复制代码

至于原理,看了半天源码,给我整不会了,因为有大量的位运算,不太好懂,但是要知道,使用这样的方法,可以减少大量空间,提高速度。

但是最后结果还是要在系统停止的时候保存到本地,可以是数据库,也可以是文件。数据库中也是一个Map,key是用户id,values是这个数组,系统启动的时候,重新加载这个值。

在抽取的时候,同样先获取BitSet中被设置过的id集合,使用not in 进行剔除。

使用下面的方法,就可以获取以前在多少位设置过。

int[] ints = bitSet.stream().toArray();
复制代码

总体还是和数据库那种办法一样,但是速度肯定是很快的。

文章分类
后端
文章标签