现在很多社交都有关注或者添加粉丝的功能, 类似于这样的功能我们如果采用数据库做的话只是单纯得到用户的一些粉丝或者关注列表的话是很简单也很容易实现, 但是如果我想要查出两个甚至多个用户共同关注了哪些人或者想要查询两个或者多个用户的共同粉丝的话就会很麻烦, 效率也不会很高. 但是如果你用redis去做的话就会相当的简单而且效率很高. 原因是redis自己本身带有专门针对于这种集合的交集,并集, 差集的一些操作。

设计思路如下:

总体思路我们采用redis里面的zset完成整个功能, 原因是zset有排序(我们要按照关注时间的倒序排列), 去重(我们不能多次关注同一用户)功能. 一个用户我们存贮两个集合, 一个是保存用户关注的人 另一个是保存关注用户的人.
用到的命令是:

1、 zadd 添加成员:命令格式:zadd key score member [[score][member] …]

2、zrem 移除某个成员:命令格式:zrem key member [member …]

3、 zcard 统计集合内的成员数:命令格式:zcard key

4、 zrange 查询集合内的成员:命令格式:ZRANGE key start stop [WITHSCORES]

描述:返回指定区间的成员。其中成员位置按 score 值递增(从小到大)来排序。 WITHSCORES选项是用来让成员和它的score值一并返回.

5、 zrevrange跟zrange作用相反
6、zrank获取成员的排名:命令格式:zrank key member

描述:返回有序集key中成员member的排名。成员按 score 值递增(从小到大)顺序排列。排名以0开始,也就是说score 值最小的为0。返回值:返回成员排名,member不存在返回nil.

7、 zinterstore 取两个集合的交集:命令格式:ZINTERSTORE destination numkeys key [key …][WEIGHTS weight [weight …]] [AGGREGATE SUM|MIN|MAX]

描述:计算给定的一个或多个有序集的交集。其中给定 key 的数量必须以 numkeys 参数指定,并将该交集(结果集)储存到 destination 。默认情况下,结果集中某个成员的 score 值是所有给定集下该成员 score 值之 和 。

返回值:保存到 destination 的结果集成员数。

下面我用Java写了一个简单的例子 maven构建

第一步: 添加Redis客户端

<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>


第二步: 封装一个简单的redis工具类

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public final class RedisUtil {
//Redis服务器IP
private static String ADDR = "localhost";
//Redis的端口号
private static int PORT = 6379;
//访问密码
private static String AUTH = "admin";
//控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
private static int MAX_IDLE = 200;
private static int TIMEOUT = 10000;
//在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
private static boolean TEST_ON_BORROW = true;
private static JedisPool jedisPool = null; static {
try {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(MAX_IDLE);
config.setTestOnBorrow(TEST_ON_BORROW);
jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
} catch (Exception e) {
e.printStackTrace();
}
} public synchronized static Jedis getJedis() {
try {
if (jedisPool != null) {
Jedis resource = jedisPool.getResource();
return resource;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
} @SuppressWarnings("deprecation")
public static void returnResource(final Jedis jedis) {
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
}

  

第三步: 封装简单的Follow类

 import java.util.HashSet;
import java.util.Set; import redis.clients.jedis.Jedis; import com.indulgesmart.base.util.RedisUtil;
public class FollowUtil { private static final String FOLLOWING = "FOLLOWING_";
private static final String FANS = "FANS_";
private static final String COMMON_KEY = "COMMON_FOLLOWING"; // 关注或者取消关注
public static int addOrRelease(String userId, String followingId) {
if (userId == null || followingId == null) {
return -1;
}
int isFollow = 0; // 0 = 取消关注 1 = 关注
Jedis jedis = RedisUtil.getJedis();
String followingKey = FOLLOWING + userId;
String fansKey = FANS + followingId;
if (jedis.zrank(followingKey, followingId) == null) { // 说明userId没有关注过followingId
jedis.zadd(followingKey, System.currentTimeMillis(), followingId);
jedis.zadd(fansKey, System.currentTimeMillis(), userId);
isFollow = 1;
} else { // 取消关注
jedis.zrem(followingKey, followingId);
jedis.zrem(fansKey, fansKey);
}
return isFollow;
} // 验证两个用户之间的关系
// 0=没关系 1=自己 2=userId关注了otherUserId 3= otherUserId是userId的粉丝 4=互相关注
public int checkRelations (String userId, String otherUserId) { if (userId == null || otherUserId == null) {
return 0;
} if (userId.equals(otherUserId)) {
return 1;
}
Jedis jedis = RedisUtil.getJedis();
String followingKey = FOLLOWING + userId;
int relation = 0;
if (jedis.zrank(followingKey, otherUserId) != null) { // userId是否关注otherUserId
relation = 2;
}
String fansKey = FANS + userId;
if (jedis.zrank(fansKey, userId) != null) {// userId粉丝列表中是否有otherUserId
relation = 3;
}
if ((jedis.zrank(followingKey, otherUserId) != null)
&& jedis.zrank(fansKey, userId) != null) {
relation = 4;
}
return relation;
} // 获取用户所有关注的人的id
public static Set<String> findFollwings(String userId) {
return findSet(FOLLOWING + userId);
} // 获取用户所有的粉丝
public static Set<String> findFans(String userId) {
return findSet(FANS + userId);
} // 获取两个共同关注的人
public static Set<String> findCommonFollowing(String userId, String otherUserId) {
if (userId == null || otherUserId == null) {
return new HashSet<>();
}
Jedis jedis = RedisUtil.getJedis();
String commonKey = COMMON_KEY + userId + "_" + otherUserId;
// 取交集
jedis.zinterstore(commonKey + userId + "_" + otherUserId, FOLLOWING + userId, FOLLOWING + otherUserId);
Set<String> result = jedis.zrange(commonKey, 0, -1);
jedis.del(commonKey);
return result;
} // 根据key获取set
private static Set<String> findSet(String key) {
if (key == null) {
return new HashSet<>();
}
Jedis jedis = RedisUtil.getJedis();
Set<String> result = jedis.zrevrange(key, 0, -1); // 按照score从大到小排序
return result;
}
}

  

使用Redis实现关注好友的功能的更多相关文章

  1. php + redis 实现关注功能

    产品价值 1: 关注功能 2: 功能分析之"关注"功能 3: 平平无奇的「关注」功能,背后有4点重大价值 应用场景 在做PC或者APP端时,掺杂点社交概念就有关注和粉丝功能; 数据 ...

  2. 简单实现Redis缓存中的排序功能

    1.在实现缓存排序功能之前,必须先明白这一功能的合理性.不妨思考一下,既然可以在数据库中排序,为什么还要把排序功能放在缓存中实现呢?这里简单总结了两个原因:首先,排序会增加数据库的负载,难以支撑高并发 ...

  3. 【springboot】【redis】springboot+redis实现发布订阅功能,实现redis的消息队列的功能

    springboot+redis实现发布订阅功能,实现redis的消息队列的功能 参考:https://www.cnblogs.com/cx987514451/p/9529611.html 思考一个问 ...

  4. redis(四)--简单实现Redis缓存中的排序功能

    在实现缓存排序功能之前,必须先明白这一功能的合理性.不妨思考一下,既然可以在数据库中排序,为什么还要把排序功能放在缓存中实现呢?这里简单总结了两个原因:首先,排序会增加数据库的负载,难以支撑高并发的应 ...

  5. redis 实现发布订阅的功能

    redis 除了作为缓存的功能外还可以用作消息中间件的功能,这片博客主要是介绍一下 redis 整合spring 实现消息的发布和订阅功能: 1:redis依赖,依赖两个包,redis 包, spri ...

  6. Redis位图实现用户签到功能

    场景需求 适用场景如签到送积分.签到领取奖励等,大致需求如下: 签到1天送1积分,连续签到2天送2积分,3天送3积分,3天以上均送3积分等. 如果连续签到中断,则重置计数,每月初重置计数. 当月签到满 ...

  7. 基于Redis位图实现用户签到功能

    场景需求 适用场景如签到送积分.签到领取奖励等,大致需求如下: 签到1天送1积分,连续签到2天送2积分,3天送3积分,3天以上均送3积分等. 如果连续签到中断,则重置计数,每月初重置计数. 当月签到满 ...

  8. python开发-实现redis中的发布订阅功能

    Python3学习(二十七):python实现Redis的订阅与发布(sub-pub机制) 先介绍一下redis的pub/sub功能: Pub/Sub功能(means Publish, Subscri ...

  9. swift 实现QQ好友列表功能

    最近项目中有类似QQ好友列表功能,整理了一下,话不多说,直接上代码 import UIKit class QQFriend: NSObject { var name: String? var intr ...

随机推荐

  1. 利用信号量semaphore实现两个进程读写同步 Linux C

    这篇帖子主要是记录一下自己使用信号量遇到的坑. 首先是需求:创建两个进程A,B.A往buffer中写,B读.两个进程利用命名管道进行通信,并实现读写同步.即A写完后通知B读,B读完后通知A写. 如果A ...

  2. Go的优雅终止姿势

    最近优化了一版程序:用到了golang的优雅退出机制. 程序使用etcd的election sdk做高可用选主,需要在节点意外下线的时候,主动去etcd卸任(删除10s租约), 否则已经下线的节点还会 ...

  3. 清理 Docker 占用的磁盘空间

    Docker 很占用空间,每当我们运行容器.拉取镜像.部署应用.构建自己的镜像时,我们的磁盘空间会被大量占用. 如果你也被这个问题所困扰,咱们就一起看一下 Docker 是如何使用磁盘空间的,以及如何 ...

  4. nginx加大缓存

    http { server { listen 0.0.0.0:81; server_name localhost; -- proxy_buffer_size 128k; proxy_buffers 3 ...

  5. monowall

    https://www.cat-home.org/?action=show&id=158

  6. C# Control.BeginInvoke、synchronizationcontext.post、delegate.BeginInvoke的运行原理

    背景 用到的知识点 1.windows消息机制 备注:鼠标点击.键盘等事件产生的消息要放入系统消息队列,然后再分配到应用程序线程消息队列.软件PostMessage的消息直接进入应用程序线程消息队列, ...

  7. Python迭代器,生成器,装饰器

    迭代器 通常来讲从一个对象中依次取出数据,这个过程叫做遍历,这个手段称为迭代(重复执行某一段代码块,并将每一次迭代得到的结果作为下一次迭代的初始值). 可迭代对象(iterable):是指该对象可以被 ...

  8. 图解机器学习 | LightGBM模型详解

    作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/34 本文地址:http://www.showmeai.tech/article-det ...

  9. Jmeter--由PV估算tps和最大并发数

    需求 "假设一个系统的业务有登录.浏览帖子.发送新贴.回复帖子,访问高峰是上午10点,日访问高峰PV约5208(含登录1300.浏览2706.发帖526.回帖676).系统响应时间要求小于3 ...

  10. Thinkphp3.2数据库字段自动转小写,字段大小写自动转换,以及thinkphp3一些bug

    公司在使用thinkphp框架,版本也有些老,被一些bug坑了,记录一下 自动转小写解决办法,最简单的就是在配置文件加上 'DB_PARAMS' => [\PDO::ATTR_CASE => ...