Browse Source

recommend opt

liqian 3 years ago
parent
commit
e59d831450
3 changed files with 107 additions and 48 deletions
  1. 4 4
      app.py
  2. 7 2
      config.py
  3. 96 42
      recommend.py

+ 4 - 4
app.py

@@ -7,7 +7,7 @@ import time
 from flask import Flask, request
 from log import Log
 from config import set_config
-from recommend import video_recommend, video_relevant_recommend
+from recommend import video_homepage_recommend, video_relevant_recommend
 from category import get_category_videos
 from video_recall import PoolRecall
 from db_helper import RedisHelper
@@ -47,8 +47,8 @@ def homepage_recommend():
             size = 10
         if category_id in config_.CATEGORY['recommend']:
             # 推荐
-            videos = video_recommend(mid=mid, uid=uid, size=size, app_type=app_type,
-                                     algo_type=algo_type, client_info=client_info)
+            videos = video_homepage_recommend(mid=mid, uid=uid, size=size, app_type=app_type,
+                                              algo_type=algo_type, client_info=client_info)
             result = {'code': 200, 'message': 'success', 'data': {'videos': videos}}
             log_.info('category_id: {}, mid: {}, uid: {}, result: {}, execute time = {}ms'.format(
                 category_id, mid, uid, result, (time.time() - start_time)*1000))
@@ -88,7 +88,7 @@ def relevant_recommend():
         app_type = request_data.get('appType')
         log_.info('relevant_recommend request data: {}'.format(request_data))
 
-        videos = video_relevant_recommend(mid=mid, uid=uid, size=page_size, app_type=app_type)
+        videos = video_relevant_recommend(video_id=video_id, mid=mid, uid=uid, size=page_size, app_type=app_type)
 
         result = {'code': 200, 'message': 'success', 'data': {'videos': videos}}
         log_.info('app_type: {}, mid: {}, uid: {}, relevant-result: {}, execute time = {}ms'.format(

+ 7 - 2
config.py

@@ -9,10 +9,15 @@ class BaseConfig(object):
         'LAO_HAO_KAN_VIDEO': 18,  # 老好看视频
         'ZUI_JING_QI': 19,  # 票圈最惊奇
     }
+    # abTest
+    AB_TEST = {
+        'w_h_rate': [APP_TYPE['LONG_VIDEO']]  # 视频宽高比实验(每组的前两个视频调整为横屏视频)
+    }
     # abCode
     AB_CODE = {
         'initial': 10000,  # 初始
         'w_h_rate': 10001,  # 视频宽高比实验(每组的前两个视频调整为横屏视频)
+        'relevant_video_op': 10002,  # 运营对某些视频给定一些相关视频,调整为对应视频相关推荐的头部
     }
 
     # pushFrom
@@ -237,6 +242,6 @@ class ProductionConfig(BaseConfig):
 
 def set_config():
     # return DevelopmentConfig()
-    # return TestConfig()
+    return TestConfig()
     # return PreProductionConfig()
-    return ProductionConfig()
+    # return ProductionConfig()

+ 96 - 42
recommend.py

@@ -47,7 +47,7 @@ def video_recommend(mid, uid, size, app_type, algo_type, client_info):
     recall_result_list = []
     pool_recall = PoolRecall(app_type=app_type, mid=mid, uid=uid, ab_code=ab_code, client_info=client_info)
     _, last_rov_recall_key, _ = pool_recall.get_video_last_idx()
-    t = [gevent.spawn(pool_recall.rov_pool_recall, size), gevent.spawn(pool_recall.flow_pool_recall, size) ]
+    t = [gevent.spawn(pool_recall.rov_pool_recall, size), gevent.spawn(pool_recall.flow_pool_recall, size)]
     gevent.joinall(t)
     recall_result_list = [i.get() for i in t]
 
@@ -76,49 +76,70 @@ def video_recommend(mid, uid, size, app_type, algo_type, client_info):
         log_.info('mid: {}, uid: {}, bottom strategy result: {}, execute time = {}ms'.format(
             mid, uid, rank_result, (end_bottom - start_bottom) * 1000))
 
-    # # ####### 视频宽高比AB实验
-    # # 对内容精选进行 视频宽高比分发实验
-    # if app_type == config_.APP_TYPE['LONG_VIDEO']:
-    #     videos = rank_result
-    #     rank_result = video_rank_by_w_h_rate(videos=videos)
-    #     log_.info('app_type: {}, mid: {}, uid: {}, rank_result: {}, execute time = {}ms'.format(
-    #         app_type, mid, uid, rank_result, (end_rank - start_rank) * 1000))
+    return rank_result, last_rov_recall_key
 
-    # ####### redis数据刷新
-    # log_.info('====== update redis')
-    # 预曝光数据同步刷新到Redis, 过期时间为0.5h
-    redis_helper = RedisHelper()
-    preview_key_name = config_.PREVIEW_KEY_PREFIX + '{}.{}'.format(app_type, mid)
-    preview_video_ids = [int(item['videoId']) for item in rank_result]
-    if preview_video_ids:
-        # log_.error('key_name = {} \n values = {}'.format(preview_key_name, tuple(preview_video_ids)))
-        redis_helper.add_data_with_set(key_name=preview_key_name, values=tuple(preview_video_ids), expire_time=30*60)
-        log_.info('preview redis update success!')
-
-    # 将此次获取的ROV召回池config_.K末位视频id同步刷新到Redis中,方便下次快速定位到召回位置,过期时间为1天
-    rov_recall_video = [item['videoId'] for item in rank_result[:config_.K]
-                        if item['pushFrom'] == config_.PUSH_FROM['rov_recall']]
-    if len(rov_recall_video) > 0:
-        if not redis_helper.get_score_with_value(key_name=config_.UPDATE_ROV_KEY_NAME, value=rov_recall_video[-1]):
-            redis_helper.set_data_to_redis(key_name=last_rov_recall_key, value=rov_recall_video[-1])
-
-    # if 0 < len(rov_recall_video) <= config_.K:
-    #     if not redis_helper.get_score_with_value(key_name=config_.UPDATE_ROV_KEY_NAME, value=rov_recall_video[-1]):
-    #         redis_helper.set_data_to_redis(key_name=last_rov_recall_key, value=rov_recall_video[-1])
-    # elif len(rov_recall_video) > config_.K:
-    #     if not redis_helper.get_score_with_value(key_name=config_.UPDATE_ROV_KEY_NAME, value=rov_recall_video[config_.K - 1]):
-    #         redis_helper.set_data_to_redis(key_name=last_rov_recall_key, value=rov_recall_video[config_.K - 1])
-    log_.info('last video redis update success!')
-
-    # 将此次分发的流量池视频,对 本地分发数-1 进行记录
-    flow_recall_video = [item for item in rank_result if item['pushFrom'] == config_.PUSH_FROM['flow_recall']]
-    if flow_recall_video:
-        update_local_distribute_count(flow_recall_video)
-        log_.info('update local distribute count success!')
+
+def ab_test_op(rank_result, ab_code_list, app_type, mid, uid, **kwargs):
+    """
+    对排序后的结果 按照AB实验进行对应的分组操作
+    :param rank_result: 排序后的结果
+    :param ab_code_list: 此次请求参与的 ab实验组
+    :param app_type: 产品标识
+    :param mid: mid
+    :param uid: uid
+    :param kwargs: 其他参数
+    :return:
+    """
+    # ####### 视频宽高比AB实验
+    # 对内容精选进行 视频宽高比分发实验
+    if config_.AB_CODE['w_h_rate'] in ab_code_list and app_type in config_.AB_TEST.get('w_h_rate', []):
+        rank_result = video_rank_by_w_h_rate(videos=rank_result)
+        log_.info('app_type: {}, mid: {}, uid: {}, rank_by_w_h_rate_result: {}'.format(
+            app_type, mid, uid, rank_result))
 
     return rank_result
 
 
+def update_redis_data(result, app_type, mid, last_rov_recall_key):
+    """
+    根据最终的排序结果更新相关redis数据
+    :param result: 排序结果
+    :param app_type: 产品标识
+    :param mid: mid
+    :param last_rov_recall_key: 用户上一次在rov召回池对应的位置 redis key
+    :return: None
+    """
+    # ####### redis数据刷新
+    try:
+        # log_.info('====== update redis')
+        # 预曝光数据同步刷新到Redis, 过期时间为0.5h
+        redis_helper = RedisHelper()
+        preview_key_name = config_.PREVIEW_KEY_PREFIX + '{}.{}'.format(app_type, mid)
+        preview_video_ids = [int(item['videoId']) for item in result]
+        if preview_video_ids:
+            # log_.error('key_name = {} \n values = {}'.format(preview_key_name, tuple(preview_video_ids)))
+            redis_helper.add_data_with_set(key_name=preview_key_name, values=tuple(preview_video_ids), expire_time=30 * 60)
+            log_.info('preview redis update success!')
+
+        # 将此次获取的ROV召回池config_.K末位视频id同步刷新到Redis中,方便下次快速定位到召回位置,过期时间为1天
+        rov_recall_video = [item['videoId'] for item in result[:config_.K]
+                            if item['pushFrom'] == config_.PUSH_FROM['rov_recall']]
+        if len(rov_recall_video) > 0:
+            if not redis_helper.get_score_with_value(key_name=config_.UPDATE_ROV_KEY_NAME, value=rov_recall_video[-1]):
+                redis_helper.set_data_to_redis(key_name=last_rov_recall_key, value=rov_recall_video[-1])
+            log_.info('last video redis update success!')
+
+        # 将此次分发的流量池视频,对 本地分发数-1 进行记录
+        flow_recall_video = [item for item in result if item['pushFrom'] == config_.PUSH_FROM['flow_recall']]
+        if flow_recall_video:
+            update_local_distribute_count(flow_recall_video)
+            log_.info('update local distribute count success!')
+
+    except Exception as e:
+        log_.error("update redis data fail!")
+        log_.error(traceback.format_exc())
+
+
 def update_local_distribute_count(videos):
     """
     更新本地分发数
@@ -145,17 +166,50 @@ def update_local_distribute_count(videos):
         log_.error(traceback.format_exc())
 
 
-def video_relevant_recommend(mid, uid, size, app_type):
+def video_homepage_recommend(mid, uid, size, app_type, algo_type, client_info):
+    """
+    首页线上推荐逻辑
+    :param mid: mid type-string
+    :param uid: uid type-string
+    :param size: 请求视频数量 type-int
+    :param app_type: 产品标识  type-int
+    :param algo_type: 算法类型  type-string
+    :param client_info: 用户位置信息 {"country": "国家",  "province": "省份",  "city": "城市"}
+    :return:
+    """
+    # 简单召回 - 排序 - 兜底
+    rank_result, last_rov_recall_key = video_recommend(mid=mid, uid=uid, size=size, app_type=app_type,
+                                                       algo_type=algo_type, client_info=client_info)
+    # ab-test
+    result = ab_test_op(rank_result=rank_result, ab_code_list=[config_.AB_CODE['w_h_rate']],
+                        app_type=app_type, mid=mid, uid=uid)
+    # redis数据刷新
+    update_redis_data(result=result, app_type=app_type, mid=mid, last_rov_recall_key=last_rov_recall_key)
+
+    return result
+
+
+def video_relevant_recommend(video_id, mid, uid, size, app_type):
     """
     相关推荐逻辑
+    :param video_id: 相关推荐的头部视频id
     :param mid: mid type-string
     :param uid: uid type-string
     :param size: 请求视频数量 type-int
     :param app_type: 产品标识  type-int
     :return: videos type-list
     """
-    videos = video_recommend(mid=mid, uid=uid, size=size, app_type=app_type, algo_type='', client_info=None)
-    return videos
+    # videos = video_recommend(mid=mid, uid=uid, size=size, app_type=app_type, algo_type='', client_info=None)
+    # 简单召回 - 排序 - 兜底
+    rank_result, last_rov_recall_key = video_recommend(mid=mid, uid=uid, size=size, app_type=app_type,
+                                                       algo_type='', client_info=None)
+    # ab-test
+    result = ab_test_op(rank_result=rank_result, ab_code_list=[config_.AB_CODE['w_h_rate']],
+                        app_type=app_type, mid=mid, uid=uid, video_id=video_id)
+    # redis数据刷新
+    update_redis_data(result=result, app_type=app_type, mid=mid, last_rov_recall_key=last_rov_recall_key)
+
+    return result
 
 
 if __name__ == '__main__':