资讯专栏INFORMATION COLUMN

使用Redis实现关注好友的功能

whatsns / 1790人阅读

摘要:排名以开始,也就是说值最小的为。返回值返回成员排名,不存在返回取两个集合的交集命令格式描述计算给定的一个或多个有序集的交集。其中给定的数量必须以参数指定,并将该交集结果集储存到。返回值保存到的结果集成员数。

使用Redis实现关注好友的功能

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

设计思路如下:

​ 总体思路我们采用redis里面的zset完成整个功能, 原因是zset有排序(我们要按照关注时间的倒序排列), 去重(我们不能多次关注同一用户)功能. 一个用户我们存贮两个集合, 一个是保存用户关注的人 另一个是保存关注用户的人.
用到的命令是:
​ 1、 zadd 添加成员:命令格式: zadd key score member [score …]
​ 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 ...] [AGGREGATE SUM|MIN|MAX]
​ 描述:计算给定的一个或多个有序集的交集。其中给定 key 的数量必须以 numkeys 参数指定,并将该交集(结果集)储存到 destination 。默认情况下,结果集中某个成员的 score 值是所有给定集下该成员 score 值之 和 。
返回值:保存到 destination 的结果集成员数。

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

第一步: 添加Redis客户端

    redis.clients
    jedis
    2.9.0
第二步: 封装一个简单的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 findFollwings(String userId) {
            return findSet(FOLLOWING + userId);
        }
    
        // 获取用户所有的粉丝
        public static Set findFans(String userId) {
            return findSet(FANS + userId);
        }
        
        // 获取两个共同关注的人
        public static Set 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 result = jedis.zrange(commonKey, 0, -1);
            jedis.del(commonKey);
            return result;
        }
        
        // 根据key获取set
        private static Set findSet(String key) {
            if (key == null) {
                return new HashSet<>();
            }
            Jedis jedis = RedisUtil.getJedis();
            Set result = jedis.zrevrange(key, 0, -1); // 按照score从大到小排序
            return result;
        }
    }

这是一点点小小的总结, 希望能帮到要用到的人。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/65365.html

相关文章

  • Redis 8 大应用场景!

    摘要:之前讲过的介绍,及使用带来的优势,这章整理了一下的应用场景,也是非常重要的,学不学得好,能正常落地是关键。下面一一来分析下的应用场景都有哪些。提供的有序集合数据类构能实现各种复杂的排行榜应用。 之前讲过Redis的介绍,及使用Redis带来的优势,这章整理了一下Redis的应用场景,也是非常重要的,学不学得好,能正常落地是关键。 下面一一来分析下Redis的应用场景都有哪些。 1、缓存...

    CastlePeaK 评论0 收藏0
  • 使用redis实现互粉功能

    摘要:数据库实现一下是数据库的代码,通过保存用户的和关注对象的以及关注状态来判断用户的关注列表和粉丝列表,通过联查获取用户的基本信息,入头像名称。 使用redis实现互粉 最近在写api的时候要实现一个相互关注的功能,发现如果用mysql做查询不是很理想, 所以想能不能用redis来实现这个功能,网上一搜有很多实现的方法,结合网上的博文,实现了自己的功能。 1.数据库实现 一下是数据库的代...

    aikin 评论0 收藏0

发表评论

0条评论

whatsns

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<