使用Redis實現關注好友的功能

使用Redis實現關注好友的功能

如今不少社交都有關注或者添加粉絲的功能, 相似於這樣的功能咱們若是採用數據庫作的話只是單純獲得用戶的一些粉絲或者關注列表的話是很簡單也很容易實現, 可是若是我想要查出兩個甚至多個用戶共同關注了哪些人或者想要查詢兩個或者多個用戶的共同粉絲的話就會很麻煩, 效率也不會很高. 可是若是你用redis去作的話就會至關的簡單並且效率很高. 緣由是redis本身自己帶有專門針對於這種集合的交集,並集, 差集的一些操做。java

設計思路以下:

​ 整體思路咱們採用redis裏面的zset完成整個功能, 緣由是zset有排序(咱們要按照關注時間的倒序排列), 去重(咱們不能屢次關注同一用戶)功能. 一個用戶咱們存貯兩個集合, 一個是保存用戶關注的人 另外一個是保存關注用戶的人.
用到的命令是:
​ 一、 zadd 添加成員:命令格式: zadd key score member [score …]
​ 二、zrem 移除某個成員:命令格式: zrem key member [member ...]
​ 三、 zcard 統計集合內的成員數:命令格式: zcard key
​ 四、 zrange 查詢集合內的成員:命令格式: ZRANGE key start stop [WITHSCORES]
​ 描述:返回指定區間的成員。其中成員位置按 score 值遞增(從小到大)來排序。 WITHSCORES選項是用來讓成員和它的score值一併返回.
​ 五、 zrevrange跟zrange做用相反
​ 六、zrank獲取成員的排名:命令格式: zrank key member
​ 描述:返回有序集key中成員member的排名。成員按 score 值遞增(從小到大)順序排列。排名以0開始,也就是說score 值最小的爲0。返回值:返回成員排名,member不存在返回nil.
​ 七、 zinterstore 取兩個集合的交集:命令格式:ZINTERSTORE destination numkeys key key ...] [AGGREGATE SUM|MIN|MAX]
​ 描述:計算給定的一個或多個有序集的交集。其中給定 key 的數量必須以 numkeys 參數指定,並將該交集(結果集)儲存到 destination 。默認狀況下,結果集中某個成員的 score 值是全部給定集下該成員 score 值之 和 。
返回值:保存到 destination 的結果集成員數。redis

下面我用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;
        }
    }

這是一點點小小的總結, 但願能幫到要用到的人。服務器

相關文章
相關標籤/搜索