瀏覽代碼

add route: /applet/ad/roi/predict

liqian 1 年之前
父節點
當前提交
a02235e482
共有 3 個文件被更改,包括 188 次插入6 次删除
  1. 109 0
      ad_recommend.py
  2. 50 6
      app.py
  3. 29 0
      config.py

+ 109 - 0
ad_recommend.py

@@ -477,3 +477,112 @@ def ad_recommend_predict(app_type, mid, video_id, ab_exp_info, ab_test_code, car
     except Exception as e:
         log_.error(traceback.format_exc())
         return None
+
+
+def ad_recommend_predict_with_roi(app_type, mid, video_id, ads, arpu, roi_param):
+    """
+    广告推荐预测
+    :param app_type: app_type
+    :param mid: mid
+    :param video_id: video_id
+    :param ads: 需要发放广告列表 list
+    :param arpu: 上一周期arpu值
+    :param roi_param: 计算roi使用参数
+    :return: ad_predict, type-int, 1-不发放广告,2-发放广告
+    """
+    try:
+        now_date = datetime.datetime.today()
+        now_dt = datetime.datetime.strftime(now_date, '%Y%m%d')
+        ad_info = ads[0]
+        ad_id = ad_info['adId']
+        ad_type = ad_info['adType']
+        ecpm = float(ad_info['ecpm'])
+
+        # 获取参数
+        params = config_.PARAMS_NEW_STRATEGY[int(app_type)]
+        # 判断mid所属分组
+        group_class_key = params.get('group_class_key')
+        mid_group_key_name = f"{config_.KEY_NAME_PREFIX_MID_GROUP}{group_class_key}:{mid}"
+        mid_group = redis_helper.get_data_from_redis(key_name=mid_group_key_name)
+        if mid_group is None:
+            mid_group = 'mean_group'
+
+        # 获取用户组出广告后分享的概率
+        share_user_data_key = params['user'].get('data')
+        share_user_rule_key = params['user'].get('rule')
+        group_share_rate_key_with_ad = \
+            f"{config_.KEY_NAME_PREFIX_GROUP_WITH_AD}{share_user_data_key}:{share_user_rule_key}:{now_dt}"
+        if not redis_helper.key_exists(group_share_rate_key_with_ad):
+            redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
+            group_share_rate_key_with_ad = \
+                f"{config_.KEY_NAME_PREFIX_GROUP_WITH_AD}{share_user_data_key}:{share_user_rule_key}:{redis_dt}"
+        group_share_rate_with_ad = redis_helper.get_score_with_value(key_name=group_share_rate_key_with_ad,
+                                                                     value=mid_group)
+
+        # 获取视频出广告后分享的概率
+        share_video_data_key = params['video'].get('data')
+        video_share_rate_key_with_ad = f"{config_.KEY_NAME_PREFIX_VIDEO_WITH_AD}{share_video_data_key}:{now_dt}"
+        if not redis_helper.key_exists(video_share_rate_key_with_ad):
+            redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
+            video_share_rate_key_with_ad = f"{config_.KEY_NAME_PREFIX_VIDEO_WITH_AD}{share_video_data_key}:{redis_dt}"
+        video_share_rate_with_ad = redis_helper.get_score_with_value(key_name=video_share_rate_key_with_ad,
+                                                                     value=int(video_id))
+        if video_share_rate_with_ad is None:
+            video_share_rate_with_ad = redis_helper.get_score_with_value(key_name=video_share_rate_key_with_ad,
+                                                                         value=-1)
+
+        # 获取用户组不出广告后分享的概率
+        group_share_rate_key_no_ad = \
+            f"{config_.KEY_NAME_PREFIX_GROUP_NO_AD}{share_user_data_key}:{share_user_rule_key}:{now_dt}"
+        if not redis_helper.key_exists(group_share_rate_key_no_ad):
+            redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
+            group_share_rate_key_no_ad = \
+                f"{config_.KEY_NAME_PREFIX_GROUP_NO_AD}{share_user_data_key}:{share_user_rule_key}:{redis_dt}"
+        group_share_rate_no_ad = redis_helper.get_score_with_value(key_name=group_share_rate_key_no_ad, value=mid_group)
+
+        # 获取视频不出广告后分享的概率
+        video_share_rate_key_no_ad = f"{config_.KEY_NAME_PREFIX_VIDEO_NO_AD}{share_video_data_key}:{now_dt}"
+        if not redis_helper.key_exists(video_share_rate_key_with_ad):
+            redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
+            video_share_rate_key_no_ad = f"{config_.KEY_NAME_PREFIX_VIDEO_NO_AD}{share_video_data_key}:{redis_dt}"
+        video_share_rate_no_ad = redis_helper.get_score_with_value(key_name=video_share_rate_key_no_ad,
+                                                                   value=int(video_id))
+        if video_share_rate_no_ad is None:
+            video_share_rate_no_ad = redis_helper.get_score_with_value(key_name=video_share_rate_key_no_ad, value=-1)
+
+        if group_share_rate_with_ad is None or video_share_rate_with_ad is None \
+                or group_share_rate_no_ad is None or video_share_rate_no_ad is None:
+            return None
+        # 计算此次请求出广告后分享的概率
+        share_rate_with_ad = float(group_share_rate_with_ad) * float(video_share_rate_with_ad)
+        # 计算此次请求不出广告分享的概率
+        share_rate_no_ad = float(group_share_rate_no_ad) * float(video_share_rate_no_ad)
+        # 计算此次请求出广告的收入增益
+        roi_ad = ecpm / 1000 - float(roi_param) * float(arpu) * (share_rate_no_ad - share_rate_with_ad)
+        # 收入增益判断
+        if roi_ad > 0:
+            # 大于0,出广告
+            ad_predict = 2
+        else:
+            # 否则,不出广告
+            ad_predict = 1
+        result = {
+            'arpu': arpu,
+            'roi_param': roi_param,
+            'ad_id': ad_id,
+            'ad_type': ad_type,
+            'mid_group': mid_group,
+            'group_share_rate_with_ad': group_share_rate_with_ad,
+            'video_share_rate_with_ad': video_share_rate_with_ad,
+            'group_share_rate_no_ad': group_share_rate_no_ad,
+            'video_share_rate_no_ad': video_share_rate_no_ad,
+            'share_rate_with_ad': share_rate_with_ad,
+            'share_rate_no_ad': share_rate_no_ad,
+            'roi_ad': roi_ad,
+            'ad_predict': ad_predict
+        }
+        return result
+
+    except Exception as e:
+        log_.error(traceback.format_exc())
+        return None

+ 50 - 6
app.py

@@ -22,7 +22,7 @@ from utils import update_video_w_h_rate
 from user2new import user2new
 from params_helper import Params
 from manager_op import get_video_list, search_video
-from ad_recommend import ad_recommend_predict
+from ad_recommend import ad_recommend_predict, ad_recommend_predict_with_roi
 # from werkzeug.middleware.profiler import ProfilerMiddleware
 # from geventwebsocket.handler import WebSocketHandler
 from apscheduler.schedulers.background import BackgroundScheduler
@@ -46,17 +46,22 @@ def update_flow_pool_config():
     level_weight_initial = redis_helper.get_data_from_redis(key_name=config_.FLOWPOOL_LEVEL_WEIGHT_KEY_NAME)
     if level_weight_initial is not None:
         level_weight = json.loads(level_weight_initial)
-    # log_.info({
-    #     "now_date": datetime.datetime.strftime(datetime.datetime.today(), '%Y%m%d %H:%M:%S'),
-    #     "level_weight": level_weight
-    # })
-    # print(level_weight)
+
     global flow_pool_abtest_config
     flow_pool_abtest_config = redis_helper.get_data_from_redis(key_name=config_.FLOWPOOL_ABTEST_KEY_NAME)
     if flow_pool_abtest_config is not None:
         flow_pool_abtest_config = json.loads(flow_pool_abtest_config)
 
 
+def update_ad_predict_params():
+    """
+    定时更新广告预测相关预设配置到内存变量中
+    1. level_weight: 流量池层级权重
+    2. flow_pool_abtest_config: 流量池ab实验配置
+    :return: None
+    """
+
+
 sched = BackgroundScheduler(daemon=True, timezone='Asia/Shanghai')  # 指定时区
 sched.add_job(func=update_flow_pool_config, trigger="interval", seconds=10*60)  # 间隔10min后启动
 update_flow_pool_config()
@@ -441,6 +446,45 @@ def ad_predict():
         return json.dumps(result)
 
 
+# 广告推荐新策略
+@app.route('/applet/ad/roi/predict', methods=['GET', 'POST'])
+def ad_roi_predict():
+    start_time = time.time()
+    try:
+        request_data = json.loads(request.get_data())
+        mid = request_data.get('mid')
+        video_id = request_data.get('videoId')
+        app_type = request_data.get('appType')
+        ads = request_data.get('ads')
+        predict_result = ad_recommend_predict_with_roi(app_type=app_type,
+                                                       mid=mid,
+                                                       video_id=video_id,
+                                                       ads=ads,
+                                                       arpu=arpu,
+                                                       roi_param=roi_param)
+        if predict_result is None:
+            result = {'code': -1, 'message': 'fail'}
+        else:
+            result = {'code': 200, 'message': 'success', 'data': predict_result.get('ad_predict')}
+        log_message = {
+            'requestUri': '/applet/ad/roi/predict',
+            'request_data': request_data,
+            'logTimestamp': int(time.time() * 1000),
+            'app_type': app_type,
+            'mid': mid,
+            'video_id': video_id,
+            'predict_result': predict_result,
+            'result': result,
+            'executeTime': (time.time() - start_time) * 1000
+        }
+        log_.info(log_message)
+        return json.dumps(result)
+    except Exception as e:
+        log_.error(traceback.format_exc())
+        result = {'code': -1, 'message': 'fail'}
+        return json.dumps(result)
+
+
 # app热榜
 @app.route('/app/video/hot_list', methods=['GET', 'POST'])
 def app_video_hot_list():

+ 29 - 0
config.py

@@ -1748,6 +1748,35 @@ class BaseConfig(object):
     # 广告推荐关怀模式实验阈值结果存放 redis key 前缀,完整格式:ad:threshold:care:{abtestId}:{abtestConfigTag}:{abtestGroup}:{group}
     KEY_NAME_PREFIX_AD_THRESHOLD_CARE_MODEL = 'ad:threshold:care:'
 
+    # 新策略使用
+    # 视频有广告时的分享率预测结果存放 redis key 前缀,完整格式:video:predict:share:rate:with:ad:{video_data_key}:{date}
+    KEY_NAME_PREFIX_VIDEO_WITH_AD = 'video:predict:share:rate:with:ad:'
+    # 视频无广告时的分享率预测结果存放 redis key 前缀,完整格式:video:predict:share:rate:no:ad:{video_data_key}:{date}
+    KEY_NAME_PREFIX_VIDEO_NO_AD = 'video:predict:share:rate:no:ad:'
+    # 用户组有广告时的分享率预测结果存放 redis key 前缀,完整格式:users:group:predict:share:rate:with:ad:{user_data_key}:{user_rule_key}:{date}
+    KEY_NAME_PREFIX_GROUP_WITH_AD = 'users:group:predict:share:rate:with:ad:'
+    # 用户组无广告时的分享率预测结果存放 redis key 前缀,完整格式:users:group:predict:share:rate:no:ad:{user_data_key}:{user_rule_key}:{date}
+    KEY_NAME_PREFIX_GROUP_NO_AD = 'users:group:predict:share:rate:no:ad:'
+
+    PARAMS_NEW_STRATEGY = {
+        APP_TYPE['VLOG']: {
+            'video': {'data': 'videos0'},
+            'user': {'data': 'user0', 'rule': 'rule1'},
+            'group_class_key': 'class1'
+        },  # vlog
+        APP_TYPE['LOVE_LIVE']: {
+            'video': {'data': 'videos4'},
+            'user': {'data': 'user4', 'rule': 'rule1'},
+            'group_class_key': 'class1'
+        },  # 票圈视频
+        APP_TYPE['LONG_VIDEO']: {
+            'video': {'data': 'videos5'},
+            'user': {'data': 'user5', 'rule': 'rule1'},
+            'group_class_key': 'class1'
+        },  # 内容精选
+    }
+
+
 
 class DevelopmentConfig(BaseConfig):
     """开发环境配置"""