redis分布式缓存(二十四)一一微关系计算解决方案微关

微关系计算解决方案

1. 业务分析

微博微关系:

  • 共同关注:计算出A和B共同关注的人有哪些?

image.png

  • 我关注的人也关注他:是计算出A关注的人群中,有哪些人同时和A一样关注了B

image.png

2. 技术方案

传统开发,采用数据库持久化关系数据,如下

关注表:

id user_name fans
1 A C
2 A B
3 B A
4 C A
... ... ...

如果是采用数据库来实现用户的关系,一般SQL怎么写?

  • 例如:A关注2个人,B关注100个人,计算2人的共同关注那些人?
    • SQL的写法,一般是采用in 或 not in 来实现。但是对于互联网高并发的系统来说,in 或not in 明显不适合。
select fans from table_name where user_name='A' and fans in (select fans from table_name where user_name='B')
复制代码
  • 一般的做法是采用redis的set集合来实现。

Redis Set数据结构,非常适合存储好友、关注、粉丝、感兴趣的人的集合。然后采用set的命令就能得出我们想要的数据。

  1. sinter:获得A和B两个用户的共同好友
  2. sismember:判断C是否为B的好友
  3. scard:获取好友数量

3. 实战:共同关注

  • 关注顺序
    • A关注:B C D
    • B关注:A C D
    • C关注: A
    • D关注:A B
  • 微关系:
    • A和B的共同关注={C,D}

共同关注:redis计算出A和B共同关注的人有哪些?

@ApiOperation(value="求2个用户的关注交集")
@GetMapping(value = "/intersect")
public List<UserVO> intersect(Integer userId1, Integer userId2){
    return  this.relationService.intersect(userId1,userId2);
}
复制代码
/**
 * 求2个用户的关注交集
 */
public List<UserVO> intersect(Integer userId1,Integer userId2){
    SetOperations<String, Integer> opsForSet = redisTemplate.opsForSet();
    String fans1 = Constants.KEY_FANS + userId1;
    String fans2 = Constants.KEY_FANS + userId2;
    //求2个集合的交集
    Set<Integer> sets= opsForSet.intersect(fans1,fans2);
    //返回交集的用户信息
    return this.getUserInfo(sets);
}
复制代码

4. 实战:我关注的人也关注他

  • 关注顺序
    • A关注:B C D
    • B关注:A C D
    • C关注: A
    • D关注:A B C
  • 微关系:
    • A关注的人XXX也关注C
    • 求出XXX有哪些人?
        1. A关注的人有哪些{B,C,D}
          1. B关注的人是否关注C-true
          1. C关注的人是否关注C-false
          1. D关注的人是否关注C-true
          • XXX={B,D}

案例1:A关注的人XXX也关注C

查询出XXX有哪些人

/**
 *- 关注顺序
 *     - A关注:B C D
 *     - B关注:A C D
 *     - C关注: A
 *     - D关注:A B C
 * - 微关系:
 *     - A关注的人XXX也关注C:`XXX={B,D}  `
 *         - 1. A关注的人有哪些{B,C,D}
 *             - 2. B关注的人是否关注C-true
 *             - 3. C关注的人是否关注C-false
 *             - 4. D关注的人是否关注C-true
 * @param userId1 A
 * @param userId2 C
 * @return XXX: A关注的人XXX也关注C
 */
public List<UserVO> getUser1(String userId1, String userId2) {
    SetOperations<String, Integer> opsForSet = redisTemplate.opsForSet();
    Set<Integer> users = new HashSet<>();
    String followeekey1 = Constants.KEY_FANS + userId1;
    //a关注的人是否有c
    Boolean c = opsForSet.isMember(followeekey1, userId2);
    if (c) {
        //a关注人有哪些
        Set<Integer> aMembers = opsForSet.members(followeekey1);
        if (aMembers != null) {
            aMembers.forEach(m -> {
                String memberKsy = Constants.KEY_FANS + m;
                //a关注的人是否有关注c
                Boolean isMember = opsForSet.isMember(memberKsy, userId2);
                if (isMember) {
                    users.add(m);
                }
            });
            //根据用户id查询用户信息
            return this.getUserInfo(users);
        }
    }
    return null;
}
复制代码

redis分布式缓存系列文章

上一篇:redis分布式缓存(二十三)一一 微博关注与粉丝解决方案