日萌社
人工智能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中拿出要推薦的文章結果,然後放入歷史推薦結果中
- 1、獲取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)