Explorar o código

add ad abtest

liqian %!s(int64=2) %!d(string=hai) anos
pai
achega
edfc0cc95c
Modificáronse 3 ficheiros con 101 adicións e 85 borrados
  1. 75 57
      ad_recommend.py
  2. 11 1
      app.py
  3. 15 27
      config.py

+ 75 - 57
ad_recommend.py

@@ -1,6 +1,9 @@
+import traceback
 import datetime
 from utils import RedisHelper
 from config import set_config
+from log import Log
+log_ = Log()
 config_ = set_config()
 redis_helper = RedisHelper()
 
@@ -30,7 +33,7 @@ def get_params(ab_exp_info, ab_test_code):
 
     if len(config_value_dict) > 0:
         for ab_exp_code, config_value in config_value_dict.items():
-            for tag, value in config_value:
+            for tag, value in config_value.items():
                 if ab_test_code in value:
                     abtest_id = ab_exp_code
                     abtest_config_tag = tag
@@ -49,64 +52,79 @@ def ad_recommend_predict(app_type, mid, video_id, ab_exp_info, ab_test_code):
     :param ab_test_code: 用户对应的ab组
     :return: ad_predict, type-int, 1-不发放广告,2-发放广告
     """
-    now_date = datetime.datetime.today()
-    now_dt = datetime.datetime.strftime(now_date, '%Y%m%d')
-    # 获取实验参数
-    abtest_id, abtest_config_tag = get_params(ab_exp_info=ab_exp_info, ab_test_code=ab_test_code)
+    try:
+        now_date = datetime.datetime.today()
+        now_dt = datetime.datetime.strftime(now_date, '%Y%m%d')
+        # 获取实验参数
+        abtest_id, abtest_config_tag = get_params(ab_exp_info=ab_exp_info, ab_test_code=ab_test_code)
+        if abtest_id is None or abtest_config_tag is None:
+            return None
+        abtest_param = config_.AD_ABTEST_CONFIG.get(f'{abtest_id}-{abtest_config_tag}')
+        if abtest_param is None:
+            return None
 
-    # 判断mid所属分组
-    mid_group_key_name = f"{config_.KEY_NAME_PREFIX_MID_GROUP}{mid}"
-    mid_group = redis_helper.get_data_from_redis(key_name=mid_group_key_name)
-    if mid_group is None:
-        mid_group = 'mean_group'
+        user_data_key = abtest_param.get('user')
+        video_data_key = abtest_param.get('video')
 
-    # 判断用户是否在免广告用户组列表中
-    if mid_group in config_.NO_AD_MID_GROUP_LIST:
-        # 在免广告用户组列表中,则不出广告
-        ad_predict = 1
-        result = {
-            'mid_group': mid_group,
-            'ad_predict': ad_predict
-        }
-    else:
-        # 获取用户组分享率
-        group_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_GROUP}{now_dt}"
-        if not redis_helper.key_exists(group_share_rate_key):
-            redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
-            group_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_GROUP}{redis_dt}"
-        group_share_rate = redis_helper.get_score_with_value(key_name=group_share_rate_key, value=mid_group)
-        # 获取视频分享率
-        video_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_VIDEO}{now_dt}"
-        if not redis_helper.key_exists(video_share_rate_key):
-            redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
-            video_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_VIDEO}{redis_dt}"
-        video_share_rate = redis_helper.get_score_with_value(key_name=video_share_rate_key, value=int(video_id))
-        if video_share_rate is None:
-            video_share_rate = redis_helper.get_score_with_value(key_name=video_share_rate_key, value=-1)
+        # 判断mid所属分组
+        mid_group_key_name = f"{config_.KEY_NAME_PREFIX_MID_GROUP}{mid}"
+        mid_group = redis_helper.get_data_from_redis(key_name=mid_group_key_name)
+        if mid_group is None:
+            mid_group = 'mean_group'
 
-        # 计算 mid-video 分享率
-        mid_video_share_rate = float(group_share_rate) * float(video_share_rate)
-
-        # 获取对应的阈值
-        threshold_key_name = f"{config_.KEY_NAME_PREFIX_AD_THRESHOLD}{app_type}:{mid_group}"
-        threshold = redis_helper.get_data_from_redis(key_name=threshold_key_name)
-        if threshold is None:
-            threshold = 0
-        else:
-            threshold = float(threshold)
-        # 阈值判断
-        if mid_video_share_rate > threshold:
-            # 大于阈值,出广告
-            ad_predict = 2
-        else:
-            # 否则,不出广告
+        # 判断用户是否在免广告用户组列表中
+        if mid_group in config_.NO_AD_MID_GROUP_LIST:
+            # 在免广告用户组列表中,则不出广告
             ad_predict = 1
-        result = {
-            'mid_group': mid_group,
-            'group_share_rate': group_share_rate,
-            'video_share_rate': video_share_rate,
-            'mid_video_share_rate': mid_video_share_rate,
-            'threshold': threshold,
-            'ad_predict': ad_predict}
+            result = {
+                'mid_group': mid_group,
+                'ad_predict': ad_predict
+            }
+        else:
+            # 获取用户组分享率
+            group_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_GROUP}{user_data_key}:{now_dt}"
+            if not redis_helper.key_exists(group_share_rate_key):
+                redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
+                group_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_GROUP}{redis_dt}"
+            group_share_rate = redis_helper.get_score_with_value(key_name=group_share_rate_key, value=mid_group)
+            # 获取视频分享率
+            video_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_VIDEO}{video_data_key}:{now_dt}"
+            if not redis_helper.key_exists(video_share_rate_key):
+                redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
+                video_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_VIDEO}{redis_dt}"
+            video_share_rate = redis_helper.get_score_with_value(key_name=video_share_rate_key, value=int(video_id))
+            if video_share_rate is None:
+                video_share_rate = redis_helper.get_score_with_value(key_name=video_share_rate_key, value=-1)
+
+            # 计算 mid-video 分享率
+            if group_share_rate is None or video_share_rate is None:
+                return None
+            mid_video_share_rate = float(group_share_rate) * float(video_share_rate)
+
+            # 获取对应的阈值
+            threshold_key_name = f"{config_.KEY_NAME_PREFIX_AD_THRESHOLD}{abtest_id}:{abtest_config_tag}:{mid_group}"
+            threshold = redis_helper.get_data_from_redis(key_name=threshold_key_name)
+            if threshold is None:
+                threshold = 0
+            else:
+                threshold = float(threshold)
+            # 阈值判断
+            if mid_video_share_rate > threshold:
+                # 大于阈值,出广告
+                ad_predict = 2
+            else:
+                # 否则,不出广告
+                ad_predict = 1
+            result = {
+                'mid_group': mid_group,
+                'group_share_rate': group_share_rate,
+                'video_share_rate': video_share_rate,
+                'mid_video_share_rate': mid_video_share_rate,
+                'threshold': threshold,
+                'ad_predict': ad_predict}
+
+        return result
 
-    return result
+    except Exception as e:
+        log_.error(traceback.format_exc())
+        return None

+ 11 - 1
app.py

@@ -296,10 +296,20 @@ def ad_predict():
     start_time = time.time()
     try:
         request_data = json.loads(request.get_data())
+        log_.info(request_data)
         mid = request_data.get('mid')
         video_id = request_data.get('videoId')
         app_type = request_data.get('appType')
-        predict_result = ad_recommend_predict(app_type=app_type, mid=mid, video_id=video_id)
+        ab_exp_info = request_data.get('abExpInfo')
+        ab_test_code = request_data.get('abTestCode')
+        predict_result = ad_recommend_predict(app_type=app_type,
+                                              mid=mid,
+                                              video_id=video_id,
+                                              ab_exp_info=ab_exp_info,
+                                              ab_test_code=ab_test_code)
+        if predict_result is None:
+            result = {'code': -1, 'message': 'fail'}
+            return json.dumps(result)
         result = {'code': 200, 'message': 'success', 'data': predict_result.get('ad_predict')}
         log_message = {
             'requestUri': '/applet/ad/predict',

+ 15 - 27
config.py

@@ -634,45 +634,33 @@ class BaseConfig(object):
     # 广告模型abtest配置
     AD_ABTEST_CONFIG = {
         # 票圈vlog
-        '173-a': {'data': {'video': 'data1', 'user': 'data1'},
-                  'threshold': {'group': 25 / 48, 'mean_group': 25 / 48}},
+        '173-a': {'video': 'data1', 'user': 'data1'},
         # 票圈视频+
-        '190-a': {'data': {'video': 'data1', 'user': 'data1'},
-                  'threshold': {'group': 5 / 6, 'mean_group': 5 / 6}},
+        '190-a': {'video': 'data1', 'user': 'data1'},
         # 票圈视频
-        '194-a': {'data': {'video': 'data1', 'user': 'data1'},
-                  'threshold': {'group': 25 / 48, 'mean_group': 25 / 48}},
-        '194-b': {'data': {'video': 'data2', 'user': 'data2'},
-                  'threshold': {'group': 25 / 48, 'mean_group': 25 / 48}},
+        '194-a': {'video': 'data1', 'user': 'data1'},
+        '194-b': {'video': 'data2', 'user': 'data2'},
         # 内容精选
-        '195-a': {'data': {'video': 'data1', 'user': 'data1'},
-                  'threshold': {'group': 25 / 48, 'mean_group': 25 / 48}},
-        '195-b': {'data': {'video': 'data3', 'user': 'data3'},
-                  'threshold': {'group': 25 / 48, 'mean_group': 25 / 48}},
+        '195-a': {'video': 'data1', 'user': 'data1'},
+        '195-b': {'video': 'data3', 'user': 'data3'},
         # 票圈短视频
-        '196-a': {'data': {'video': 'data1', 'user': 'data1'},
-                  'threshold': {'group': 25 / 48, 'mean_group': 25 / 48}},
-        '196-b': {'data': {'video': 'data4', 'user': 'data4'},
-                  'threshold': {'group': 25 / 48, 'mean_group': 25 / 48}},
+        '196-a': {'video': 'data1', 'user': 'data1'},
+        '196-b': {'video': 'data4', 'user': 'data4'},
         # 老好看视频
-        '197-a': {'data': {'video': 'data1', 'user': 'data1'},
-                  'threshold': {'group': 25 / 48, 'mean_group': 25 / 48}},
-        '197-b': {'data': {'video': 'data5', 'user': 'data5'},
-                  'threshold': {'group': 25 / 48, 'mean_group': 25 / 48}},
+        '197-a': {'video': 'data1', 'user': 'data1'},
+        '197-b': {'video': 'data5', 'user': 'data5'},
         # 票圈最惊奇
-        '198-a': {'data': {'video': 'data1', 'user': 'data1'},
-                  'threshold': {'group': 25 / 48, 'mean_group': 25 / 48}},
-        '198-b': {'data': {'video': 'data6', 'user': 'data6'},
-                  'threshold': {'group': 25 / 48, 'mean_group': 25 / 48}},
+        '198-a': {'video': 'data1', 'user': 'data1'},
+        '198-b': {'video': 'data6', 'user': 'data6'},
     }
 
-    # 用户组有广告时的分享率预测结果存放 redis key 前缀,完整格式:ad:users:group:predict:share:rate:{date}
+    # 用户组有广告时的分享率预测结果存放 redis key 前缀,完整格式:ad:users:group:predict:share:rate:{user_data_key}:{date}
     KEY_NAME_PREFIX_AD_GROUP = 'ad:users:group:predict:share:rate:'
-    # 视频有广告时的分享率预测结果存放 redis key 前缀,完整格式:ad:video:predict:share:rate:{date}
+    # 视频有广告时的分享率预测结果存放 redis key 前缀,完整格式:ad:video:predict:share:rate:{video_data_key}:{date}
     KEY_NAME_PREFIX_AD_VIDEO = 'ad:video:predict:share:rate:'
     # 用户分组结果存放 redis key 前缀,完整格式:mid:group:{mid}
     KEY_NAME_PREFIX_MID_GROUP = 'mid:group:'
-    # 广告推荐阈值结果存放 redis key 前缀,完整格式:ad:threshold:{appType}:{group}
+    # 广告推荐阈值结果存放 redis key 前缀,完整格式:ad:threshold:{abtestId}:{abtestConfigTag}:{group}
     KEY_NAME_PREFIX_AD_THRESHOLD = 'ad:threshold:'
     # 免广告用户组列表
     NO_AD_MID_GROUP_LIST = ['return25_nmids']