Redis实用技巧之点赞系统设计

点赞系统设计


点赞在社交类平台中,作为一个最常见的操作,每天会有成千上万的操作。如果每次都将操作写入数据库,那么对于数据库会形成很大的操作负担,因此,本文讲述如何通过Redis构件一个定时写入数据库的点赞功能。


点赞操作存储在一个set中,key以review:ID作为标识,value记录了点赞人ID:操作(1点赞/0取消点赞),这样针对同一个set即代表了指定时间内所有对于这个评论的点赞或取消。

另外有一个单独的set,记录了此单位时间内,所有被点赞的书评列表索引,此索引可以快速的找到上面提到的点赞set。当计划任务处理所有的评论时,除了一次写入点赞信息之外,同时可以合并数量为用户做消息推送动作。


Redis中的存储结构如下图所示:                



Redis实用技巧之点赞系统设计_第1张图片


以下是点赞记录功能,采用PHP实现:

(简要逻辑:首先讲评论索引加入到reviewindex中,然后判断数据库中是否有点赞,如果有,则在redis中加入取消此点赞操作。如果数据库没有点赞,那么在redis中记录点赞操作。相应的,如果redis中有点赞,那么可以直接在redis中取消,这样以后就不需要与数据库发生任何交互了。)



public function likeByRedis($reviewId, $fromUserId){


        $redis=…//获取Redis连接


        $redisKey='review:'.$reviewId;

        $redis->sadd('reviewindex',$redisKey);  //将此评论加入索引


        $likeSetMember=$fromUserId.':1';  //:1代表点赞操作

        $unlikeSetMember=$fromUserId.':0';  //:0代表取消点赞操作

        if($this->is_like_exists($reviewId,$fromUserId)){  //数据库中存在

            if($redis->sismember($redisKey,$unlikeSetMember)){

                $redis->srem($redisKey,$unlikeSetMember);

            }else{

                $redis->sadd($redisKey,$unlikeSetMember);

            }

        }elseif($redis->sismember($redisKey,$likeSetMember)){ //redis中存在,那么取消之

            $redis->srem($redisKey,$likeSetMember);

        }else{ //点赞操作

            $redis->srem($redisKey,$unlikeSetMember);

            $redis->sadd($redisKey,$likeSetMember);

        }

      }


接下来,附上计划任务中的批量处理点赞功能,因业务原因才用python实现:

(简要逻辑:从Redis中,拿到reviewindex,然后迭代取出每一个书评信息,解析书评中的点赞和取消点赞操作,之后统一写入到数据库中)


def process(self):

          redisClient = #连接Redis

          likesInfo=redisClient.smembers('reviewindex')


          likeOperation=[]

          unlikeOperation=[]


          for item in likesInfo:

              reviewID=0

              try:

               reviewIndexInfo=item.split(':')

                reviewID=reviewIndexInfo[1]

              except e:

                  pass

              if reviewID!=0:

                 

                reviewDetail=redisClient.smembers(item)

                   for likeDetail in reviewDetail:

                      try:

                         operationInfo=likeDetail.split(':')

                         #使用元祖模式而不使用对象模式 方便批量无区分的快速插入数据库

                         if operationInfo[1]=='1':  #点赞

                            likeOperation.append((reviewID,reviewInfo['user_id'],operationInfo[0]))

                         else:                    #取消赞    

                           unlikeOperation.append((reviewID,reviewInfo['user_id'],operationInfo[0]))

                       except Exception,e:

                              pass

                       redisClient.delete(item)


          redisClient.delete('reviewindex')


          # 数据库同步

          likeDAO=LikesDAO()

          likeDAO.persistLikeInfo(likeOperation,LikesDAO.LIKE_OPERATION)

          likeDAO.persistLikeInfo(unlikeOperation,LikesDAO.UNLINE_OPERATION)

          

          # 推送通知给用户

         # 因为上述结构可以方便的统计到单个书评收到了哪些用户的点赞,所以可以推送类似“您的书评收到周杰伦,李宗盛等10位好友的点赞”



只是初步简单实现了点赞功能,如果有写错的地方,欢迎做过此类功能的大牛指正。

你可能感兴趣的:(网站,Redis,PHP)