推薦緩存服務

日萌社

人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度學習實戰(不定時更新)


5.6 推薦緩存服務

學習目標

  • 目標
  • 應用

5.6.1 待推薦結果的redis緩存

  • 目的:對待推薦結果進行二級緩存,多級緩存減少數據庫讀取壓力
  • 緩存存儲:redis:'reco:{}:{}art' ,對應某個用戶,某個頻道的緩存結果
  • 步驟:
    • 1、獲取redis結果,進行判斷
      • 如果redis有,讀取需要推薦的文章數量放回,並刪除這些文章,並且放入推薦歷史推薦結果中
      • 如果redis當中不存在,則從wait_recommend中讀取
        • 如果wait_recommend中也沒有,直接返回
        • 如果wait_recommend有,從wait_recommend取出所有結果,定一個數量(如100篇)存入redis,剩下放回wait_recommend,不夠100,全部放入redis,然後清空wait_recommend
        • 從redis中拿出要推薦的文章結果,然後放入歷史推薦結果中

增加一個緩存數據庫

# 緩存在8號當中
cache_client = redis.StrictRedis(host=DefaultConfig.REDIS_HOST,
                                 port=DefaultConfig.REDIS_PORT,
                                 db=8,
                                 decode_responses=True)

1、redis 8 號數據庫讀取

# 1、直接去redis拿取對應的鍵,如果爲空
 # - 首先從獲取redis結果,進行判斷(緩存拿)
    key = 'reco:{}:{}:art'.format(temp.user_id, temp.channel_id)
    res = cache_client.zrevrange(key, 0, temp.article_num - 1)
    # - 如果redis有,讀取需要推薦的文章數量放回,並刪除這些文章,並且放入推薦歷史推薦結果中
    if res:
        cache_client.zrem(key, *res)

2、redis沒有數據,進行wait_recommend讀取,放入redis中

# - 如果redis當中不存在,則從wait_recommend中讀取
        # 刪除redis這個鍵
        cache_client.delete(key)
        try:
            # 字符串編程列表
            hbase_cache = eval(hbu.get_table_row('wait_recommend',
                                                 'reco:{}'.format(temp.user_id).encode(),
                                                 'channel:{}'.format(temp.channel_id).encode()))

        except Exception as e:
            logger.warning("{} WARN read user_id:{} wait_recommend exception:{} not exist".format(
                datetime.now().strftime('%Y-%m-%d %H:%M:%S'), temp.user_id, e))

            hbase_cache = []
        if not hbase_cache:
            #   - 如果wait_recommend中也沒有,直接返回空,去進行一次召回讀取、排序然後推薦
            return hbase_cache
        #   - wait_recommend有,從wait_recommend取出所有結果,定一個數量(如100篇)的文章存入redis
        if len(hbase_cache) > 100:
            logger.info(
                "{} INFO reduce user_id:{} channel:{} wait_recommend data".format(
                    datetime.now().strftime('%Y-%m-%d %H:%M:%S'), temp.user_id, temp.channel_id))
            # 拿出固定數量(100)給redis
            cache_redis = hbase_cache[:100]
            # 放入redis緩存
            cache_client.zadd(key, dict(zip(cache_redis, range(len(cache_redis)))))
            # 剩下的放回wait hbase結果
            hbu.get_table_put('wait_recommend',
                              'reco:{}'.format(temp.user_id).encode(),
                              'channel:{}'.format(temp.channel_id).encode(),
                              str(hbase_cache[100:]).encode())
        else:
            logger.info(
                "{} INFO delete user_id:{} channel:{} wait_recommend data".format(
                    datetime.now().strftime('%Y-%m-%d %H:%M:%S'), temp.user_id, temp.channel_id))
            # - wait_recommend不夠一定數量,全部取出放入redis當中,直接推薦出去
            # 清空wait_recommend
            hbu.get_table_put('wait_recommend',
                              'reco:{}'.format(temp.user_id).encode(),
                              'channel:{}'.format(temp.channel_id).encode(),
                              str([]).encode())

            # 放入redis緩存
            cache_client.zadd(key, dict(zip(hbase_cache, range(len(hbase_cache)))))

        res = cache_client.zrevrange(key, 0, temp.article_num - 1)
        if res:
            cache_client.zrem(key, *res)

3、推薦出去的結果放入歷史結果

# 進行類型轉換
    res = list(map(int, res))
    logger.info("{} INFO get cache data and store user_id:{} channel:{} cache history data".format(
        datetime.now().strftime('%Y-%m-%d %H:%M:%S'), temp.user_id, temp.channel_id))

    # 放入歷史記錄
    hbu.get_table_put('history_recommend',
                      'reco:his:{}'.format(temp.user_id).encode(),
                      'channel:{}'.format(temp.channel_id).encode(),
                      str(res).encode(),
                      timestamp=temp.time_stamp)
    return res

完整邏輯代碼:

from server import cache_client
import logging
from datetime import datetime

logger = logging.getLogger('recommend')


def get_cache_from_redis_hbase(temp, hbu):
    """
    進行用戶頻道推薦緩存結果的讀取
    :param temp: 用戶請求的參數
    :param hbu: hbase工具
    :return:
    """

    # - 首先從獲取redis結果,進行判斷(緩存拿)
    key = 'reco:{}:{}:art'.format(temp.user_id, temp.channel_id)
    res = cache_client.zrevrange(key, 0, temp.article_num - 1)
    # - 如果redis有,讀取需要推薦的文章數量放回,並刪除這些文章,並且放入推薦歷史推薦結果中
    if res:
        cache_client.zrem(key, *res)
    else:
        # - 如果redis當中不存在,則從wait_recommend中讀取
        # 刪除redis這個鍵
        cache_client.delete(key)
        try:
            # 字符串編程列表
            hbase_cache = eval(hbu.get_table_row('wait_recommend',
                                                 'reco:{}'.format(temp.user_id).encode(),
                                                 'channel:{}'.format(temp.channel_id).encode()))

        except Exception as e:
            logger.warning("{} WARN read user_id:{} wait_recommend exception:{} not exist".format(
                datetime.now().strftime('%Y-%m-%d %H:%M:%S'), temp.user_id, e))

            hbase_cache = []
        if not hbase_cache:
            #   - 如果wait_recommend中也沒有,直接返回空,去進行一次召回讀取、排序然後推薦
            return hbase_cache
        #   - wait_recommend有,從wait_recommend取出所有結果,定一個數量(如100篇)的文章存入redis
        if len(hbase_cache) > 100:
            logger.info(
                "{} INFO reduce user_id:{} channel:{} wait_recommend data".format(
                    datetime.now().strftime('%Y-%m-%d %H:%M:%S'), temp.user_id, temp.channel_id))
            # 拿出固定數量(100)給redis
            cache_redis = hbase_cache[:100]
            # 放入redis緩存
            cache_client.zadd(key, dict(zip(cache_redis, range(len(cache_redis)))))
            # 剩下的放回wait hbase結果
            hbu.get_table_put('wait_recommend',
                              'reco:{}'.format(temp.user_id).encode(),
                              'channel:{}'.format(temp.channel_id).encode(),
                              str(hbase_cache[100:]).encode())
        else:
            logger.info(
                "{} INFO delete user_id:{} channel:{} wait_recommend data".format(
                    datetime.now().strftime('%Y-%m-%d %H:%M:%S'), temp.user_id, temp.channel_id))
            # - wait_recommend不夠一定數量,全部取出放入redis當中,直接推薦出去
            # 清空wait_recommend
            hbu.get_table_put('wait_recommend',
                              'reco:{}'.format(temp.user_id).encode(),
                              'channel:{}'.format(temp.channel_id).encode(),
                              str([]).encode())

            # 放入redis緩存
            cache_client.zadd(key, dict(zip(hbase_cache, range(len(hbase_cache)))))

        res = cache_client.zrevrange(key, 0, temp.article_num - 1)
        if res:
            cache_client.zrem(key, *res)

    # 進行執行PL,然後寫入歷史推薦結果
    # 進行類型轉換
    res = list(map(int, res))
    logger.info("{} INFO get cache data and store user_id:{} channel:{} cache history data".format(
        datetime.now().strftime('%Y-%m-%d %H:%M:%S'), temp.user_id, temp.channel_id))

    # 放入歷史記錄
    hbu.get_table_put('history_recommend',
                      'reco:his:{}'.format(temp.user_id).encode(),
                      'channel:{}'.format(temp.channel_id).encode(),
                      str(res).encode(),
                      timestamp=temp.time_stamp)

    return res

5.6.2 在推薦中心加入緩存邏輯

  • from server import redis_cache
# 1、獲取緩存
res = redis_cache.get_reco_from_cache(temp, self.hbu)

# 如果沒有,然後走一遍算法推薦 召回+排序,同時寫入到hbase待推薦結果列表
 if not res:
     logger.info("{} INFO get user_id:{} channel:{} recall/sort data".
                 format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), temp.user_id, temp.channel_id))

     res = self.user_reco_list(temp)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章