ad_recommend.py 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. import json
  2. import traceback
  3. import datetime
  4. from utils import RedisHelper
  5. from config import set_config
  6. from log import Log
  7. log_ = Log()
  8. config_ = set_config()
  9. redis_helper = RedisHelper()
  10. def get_params(ab_exp_info, ab_test_code):
  11. """
  12. 根据实验分组给定对应的参数
  13. :param ab_exp_info: AB实验组参数
  14. :param ab_test_code: 用户对应的ab组
  15. :return:
  16. """
  17. abtest_id, abtest_config_tag = None, None
  18. ad_abtest_id_list = [key.split('-')[0] for key in config_.AD_ABTEST_CONFIG]
  19. # 获取广告实验配置
  20. config_value_dict = {}
  21. if ab_exp_info:
  22. ab_exp_list = ab_exp_info.get('ab_test002', None)
  23. if ab_exp_list:
  24. for ab_item in ab_exp_list:
  25. ab_exp_code = ab_item.get('abExpCode', None)
  26. if not ab_exp_code:
  27. continue
  28. if ab_exp_code in ad_abtest_id_list:
  29. config_value = ab_item.get('configValue', None)
  30. if config_value:
  31. config_value_dict[str(ab_exp_code)] = eval(str(config_value))
  32. if len(config_value_dict) > 0:
  33. for ab_exp_code, config_value in config_value_dict.items():
  34. for tag, value in config_value.items():
  35. if ab_test_code in value:
  36. abtest_id = ab_exp_code
  37. abtest_config_tag = tag
  38. break
  39. return abtest_id, abtest_config_tag
  40. def get_threshold(abtest_id, abtest_config_tag, ab_test_code, mid_group, care_model_status, abtest_param):
  41. """获取对应的阈值"""
  42. # 判断是否是关怀模式实验
  43. care_model_status_param = abtest_param.get('care_model_status_param', None)
  44. care_model_ab_mid_group = abtest_param.get('care_model_ab_mid_group', [])
  45. if care_model_status_param is None:
  46. # 无关怀模式实验
  47. threshold_key_name_prefix = config_.KEY_NAME_PREFIX_AD_THRESHOLD
  48. else:
  49. # 关怀模式实验
  50. if care_model_status is None or len(care_model_ab_mid_group) == 0 or care_model_status == 'null':
  51. # 参数缺失,走默认
  52. threshold_key_name_prefix = config_.KEY_NAME_PREFIX_AD_THRESHOLD
  53. elif int(care_model_status) == int(care_model_status_param) and mid_group in care_model_ab_mid_group:
  54. # 实验匹配,获取对应的阈值
  55. threshold_key_name_prefix = config_.KEY_NAME_PREFIX_AD_THRESHOLD_CARE_MODEL
  56. else:
  57. threshold_key_name_prefix = config_.KEY_NAME_PREFIX_AD_THRESHOLD
  58. threshold_key_name = f"{threshold_key_name_prefix}{abtest_id}:{abtest_config_tag}:{ab_test_code}:{mid_group}"
  59. threshold = redis_helper.get_data_from_redis(key_name=threshold_key_name)
  60. if threshold is None:
  61. threshold = 0
  62. else:
  63. threshold = float(threshold)
  64. return threshold
  65. def predict_with_rate_process(now_date, video_id, abtest_param, abtest_id, abtest_config_tag, ab_test_code, care_model_status, mid_group):
  66. now_dt = datetime.datetime.strftime(now_date, '%Y%m%d')
  67. user_data_key = abtest_param['user'].get('data')
  68. user_rule_key = abtest_param['user'].get('rule')
  69. video_data_key = abtest_param['video'].get('data')
  70. # 获取用户组分享率
  71. group_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_GROUP}{user_data_key}:{user_rule_key}:{now_dt}"
  72. if not redis_helper.key_exists(group_share_rate_key):
  73. redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
  74. group_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_GROUP}{user_data_key}:{user_rule_key}:{redis_dt}"
  75. group_share_rate = redis_helper.get_score_with_value(key_name=group_share_rate_key, value=mid_group)
  76. # 获取视频分享率
  77. video_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_VIDEO}{video_data_key}:{now_dt}"
  78. if not redis_helper.key_exists(video_share_rate_key):
  79. redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
  80. video_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_VIDEO}{video_data_key}:{redis_dt}"
  81. video_share_rate = redis_helper.get_score_with_value(key_name=video_share_rate_key, value=int(video_id))
  82. if video_share_rate is None:
  83. video_share_rate = redis_helper.get_score_with_value(key_name=video_share_rate_key, value=-1)
  84. # 计算 mid-video 分享率
  85. if group_share_rate is None or video_share_rate is None:
  86. return None
  87. mid_video_predict_res = float(group_share_rate) * float(video_share_rate)
  88. # 获取对应的阈值
  89. threshold = get_threshold(
  90. abtest_id=abtest_id,
  91. abtest_config_tag=abtest_config_tag,
  92. ab_test_code=ab_test_code,
  93. mid_group=mid_group,
  94. care_model_status=care_model_status,
  95. abtest_param=abtest_param
  96. )
  97. # 阈值判断
  98. if mid_video_predict_res > threshold:
  99. # 大于阈值,出广告
  100. ad_predict = 2
  101. else:
  102. # 否则,不出广告
  103. ad_predict = 1
  104. result = {
  105. 'mid_group': mid_group,
  106. 'group_share_rate': group_share_rate,
  107. 'video_share_rate': video_share_rate,
  108. 'mid_video_predict_res': mid_video_predict_res,
  109. 'threshold': threshold,
  110. 'ad_predict': ad_predict
  111. }
  112. return result
  113. def predict_mid_video_res(now_date, mid, video_id, abtest_param, abtest_id, abtest_config_tag, ab_test_code, care_model_status, app_type):
  114. # now_dt = datetime.datetime.strftime(now_date, '%Y%m%d')
  115. # user_data_key = abtest_param['user'].get('data')
  116. # user_rule_key = abtest_param['user'].get('rule')
  117. # video_data_key = abtest_param['video'].get('data')
  118. group_class_key = abtest_param.get('group_class_key')
  119. no_ad_mid_group_list = abtest_param.get('no_ad_mid_group_list', [])
  120. no_ad_group_with_video_mapping = abtest_param.get('no_ad_group_with_video_mapping', {})
  121. # 判断mid所属分组
  122. mid_group_key_name = f"{config_.KEY_NAME_PREFIX_MID_GROUP}{group_class_key}:{mid}"
  123. mid_group = redis_helper.get_data_from_redis(key_name=mid_group_key_name)
  124. if mid_group is None:
  125. mid_group = 'mean_group'
  126. # 判断用户是否在免广告用户组列表中
  127. if mid_group in no_ad_mid_group_list:
  128. # 在免广告用户组列表中,则不出广告
  129. ad_predict = 1
  130. result = {
  131. 'mid_group': mid_group,
  132. 'ad_predict': ad_predict,
  133. 'no_ad_strategy': 'no_ad_mid_group'
  134. }
  135. elif mid_group in no_ad_group_with_video_mapping:
  136. # 用户组在特定内容不出广告设置中
  137. # 获取对应的特定内容
  138. video_mapping_key_list = no_ad_group_with_video_mapping.get(mid_group, [])
  139. no_ad_videos = redis_helper.get_data_from_redis(key_name=f"{config_.KEY_NAME_PREFIX_NO_AD_VIDEOS}{app_type}")
  140. if no_ad_videos is not None:
  141. no_ad_videos = json.loads(no_ad_videos)
  142. else:
  143. no_ad_videos = {}
  144. no_ad_video_list = []
  145. for video_mapping_key in video_mapping_key_list:
  146. no_ad_video_list.extend(no_ad_videos.get(video_mapping_key, []))
  147. # 判断此次请求视频是否在免广告视频列表中
  148. if video_id in no_ad_video_list:
  149. # 在,则不出广告
  150. ad_predict = 1
  151. result = {
  152. 'mid_group': mid_group,
  153. 'ad_predict': ad_predict,
  154. 'no_ad_strategy': 'no_ad_mid_group_with_video'
  155. }
  156. else:
  157. result = predict_with_rate_process(
  158. now_date=now_date,
  159. video_id=video_id,
  160. abtest_param=abtest_param,
  161. abtest_id=abtest_id,
  162. abtest_config_tag=abtest_config_tag,
  163. ab_test_code=ab_test_code,
  164. care_model_status=care_model_status,
  165. mid_group=mid_group)
  166. else:
  167. result = predict_with_rate_process(
  168. now_date=now_date,
  169. video_id=video_id,
  170. abtest_param=abtest_param,
  171. abtest_id=abtest_id,
  172. abtest_config_tag=abtest_config_tag,
  173. ab_test_code=ab_test_code,
  174. care_model_status=care_model_status,
  175. mid_group=mid_group)
  176. return result
  177. def predict_mid_video_res_with_add(now_date, mid, video_id, abtest_param, abtest_id, abtest_config_tag, ab_test_code, care_model_status):
  178. now_dt = datetime.datetime.strftime(now_date, '%Y%m%d')
  179. # 判断mid所属分组
  180. group_class_key = abtest_param.get('group_class_key')
  181. mid_group_key_name = f"{config_.KEY_NAME_PREFIX_MID_GROUP}{group_class_key}:{mid}"
  182. mid_group = redis_helper.get_data_from_redis(key_name=mid_group_key_name)
  183. if mid_group is None:
  184. mid_group = 'mean_group'
  185. # 判断用户是否在免广告用户组列表中
  186. no_ad_mid_group_list = abtest_param.get('no_ad_mid_group_list', [])
  187. if mid_group in no_ad_mid_group_list:
  188. # 在免广告用户组列表中,则不出广告
  189. ad_predict = 1
  190. result = {
  191. 'mid_group': mid_group,
  192. 'ad_predict': ad_predict
  193. }
  194. else:
  195. # 获取用户组出广告后分享的概率
  196. share_user_data_key = abtest_param['share']['user'].get('data')
  197. share_user_rule_key = abtest_param['share']['user'].get('rule')
  198. group_share_rate_key = \
  199. f"{config_.KEY_NAME_PREFIX_AD_GROUP}{share_user_data_key}:{share_user_rule_key}:{now_dt}"
  200. if not redis_helper.key_exists(group_share_rate_key):
  201. redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
  202. group_share_rate_key = \
  203. f"{config_.KEY_NAME_PREFIX_AD_GROUP}{share_user_data_key}:{share_user_rule_key}:{redis_dt}"
  204. group_share_rate = redis_helper.get_score_with_value(key_name=group_share_rate_key, value=mid_group)
  205. # 获取视频出广告后分享的概率
  206. share_video_data_key = abtest_param['share']['video'].get('data')
  207. video_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_VIDEO}{share_video_data_key}:{now_dt}"
  208. if not redis_helper.key_exists(video_share_rate_key):
  209. redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
  210. video_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_VIDEO}{share_video_data_key}:{redis_dt}"
  211. video_share_rate = redis_helper.get_score_with_value(key_name=video_share_rate_key, value=int(video_id))
  212. if video_share_rate is None:
  213. video_share_rate = redis_helper.get_score_with_value(key_name=video_share_rate_key, value=-1)
  214. # 获取用户组出广告后不直接跳出的概率
  215. out_user_data_key = abtest_param['out']['user'].get('data')
  216. out_user_rule_key = abtest_param['out']['user'].get('rule')
  217. group_out_rate_key = \
  218. f"{config_.KEY_NAME_PREFIX_AD_GROUP}{out_user_data_key}:{out_user_rule_key}:{now_dt}"
  219. if not redis_helper.key_exists(group_out_rate_key):
  220. redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
  221. group_out_rate_key = \
  222. f"{config_.KEY_NAME_PREFIX_AD_GROUP}{out_user_data_key}:{out_user_rule_key}:{redis_dt}"
  223. group_out_rate = redis_helper.get_score_with_value(key_name=group_out_rate_key, value=mid_group)
  224. # 获取视频出广告后不直接跳出的概率
  225. out_video_data_key = abtest_param['out']['video'].get('data')
  226. video_out_rate_key = f"{config_.KEY_NAME_PREFIX_AD_VIDEO}{out_video_data_key}:{now_dt}"
  227. if not redis_helper.key_exists(video_out_rate_key):
  228. redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
  229. video_out_rate_key = f"{config_.KEY_NAME_PREFIX_AD_VIDEO}{out_video_data_key}:{redis_dt}"
  230. video_out_rate = redis_helper.get_score_with_value(key_name=video_out_rate_key, value=int(video_id))
  231. if video_out_rate is None:
  232. video_out_rate = redis_helper.get_score_with_value(key_name=video_out_rate_key, value=-1)
  233. # 计算 mid-video 预测值
  234. if group_share_rate is None or video_share_rate is None or group_out_rate is None or video_out_rate is None:
  235. return None
  236. # 加权融合
  237. share_weight = abtest_param['mix_param']['share_weight']
  238. out_weight = abtest_param['mix_param']['out_weight']
  239. group_rate = share_weight * float(group_share_rate) + out_weight * float(group_out_rate)
  240. video_rate = share_weight * float(video_share_rate) + out_weight * float(video_out_rate)
  241. mid_video_predict_res = group_rate * video_rate
  242. # 获取对应的阈值
  243. threshold = get_threshold(
  244. abtest_id=abtest_id,
  245. abtest_config_tag=abtest_config_tag,
  246. ab_test_code=ab_test_code,
  247. mid_group=mid_group,
  248. care_model_status=care_model_status,
  249. abtest_param=abtest_param
  250. )
  251. # 阈值判断
  252. if mid_video_predict_res > threshold:
  253. # 大于阈值,出广告
  254. ad_predict = 2
  255. else:
  256. # 否则,不出广告
  257. ad_predict = 1
  258. result = {
  259. 'mid_group': mid_group,
  260. 'group_share_rate': group_share_rate,
  261. 'video_share_rate': video_share_rate,
  262. 'group_out_rate': group_out_rate,
  263. 'video_out_rate': video_out_rate,
  264. 'group_rate': group_rate,
  265. 'video_rate': video_rate,
  266. 'mid_video_predict_res': mid_video_predict_res,
  267. 'threshold': threshold,
  268. 'ad_predict': ad_predict}
  269. return result
  270. def predict_mid_video_res_with_model(now_date, mid, video_id, abtest_param, abtest_id, abtest_config_tag, ab_test_code, care_model_status):
  271. model_key = abtest_param.get('model_key', 'ad_out_v1')
  272. mean_key = 'mean'
  273. user_key_name = f"{config_.KEY_NAME_PREFIX_AD_OUT_MODEL_SCORE_USER}{model_key}:{mid}"
  274. user_key_name_mean = f"{config_.KEY_NAME_PREFIX_AD_OUT_MODEL_SCORE_USER}{model_key}:{mean_key}"
  275. item_key_name = f"{config_.KEY_NAME_PREFIX_AD_OUT_MODEL_SCORE_ITEM}{model_key}:{video_id}"
  276. item_key_name_mean = f"{config_.KEY_NAME_PREFIX_AD_OUT_MODEL_SCORE_ITEM}{model_key}:{mean_key}"
  277. config_key_prefix = f"{config_.KEY_NAME_PREFIX_AD_OUT_MODEL_CONFIG}{model_key}:{abtest_id}:{abtest_config_tag}"
  278. threshold_key = f"{config_key_prefix}:threshold"
  279. use_mean_key = f"{config_key_prefix}:use_mean"
  280. use_mean = redis_helper.get_data_from_redis(key_name=use_mean_key)
  281. user_score = redis_helper.get_data_from_redis(key_name=user_key_name)
  282. item_score = redis_helper.get_data_from_redis(key_name=item_key_name)
  283. if user_score is None:
  284. if use_mean:
  285. user_score = redis_helper.get_data_from_redis(key_name=user_key_name_mean)
  286. else:
  287. user_score = 0.0
  288. if item_score is None:
  289. if use_mean:
  290. item_score = redis_helper.get_data_from_redis(key_name=item_key_name_mean)
  291. else:
  292. item_score = 0.0
  293. final_score = user_score + item_score
  294. # 获取对应的阈值
  295. threshold = redis_helper.get_data_from_redis(key_name=threshold_key)
  296. # 阈值判断
  297. if final_score > threshold:
  298. # 大于阈值,出广告
  299. ad_predict = 2
  300. else:
  301. # 否则,不出广告
  302. ad_predict = 1
  303. result = {
  304. 'use_mean_key': use_mean_key,
  305. 'threshold_key': threshold_key,
  306. 'user_score': user_score,
  307. 'item_score': item_score,
  308. 'final_score': final_score,
  309. 'threshold': threshold,
  310. 'ad_predict': ad_predict
  311. }
  312. return result
  313. def predict_mid_video_res_with_multiply(now_date, mid, video_id, abtest_param, abtest_id, abtest_config_tag, ab_test_code, care_model_status):
  314. now_dt = datetime.datetime.strftime(now_date, '%Y%m%d')
  315. # 判断mid所属分组
  316. group_class_key = abtest_param.get('group_class_key')
  317. mid_group_key_name = f"{config_.KEY_NAME_PREFIX_MID_GROUP}{group_class_key}:{mid}"
  318. mid_group = redis_helper.get_data_from_redis(key_name=mid_group_key_name)
  319. if mid_group is None:
  320. mid_group = 'mean_group'
  321. # 判断用户是否在免广告用户组列表中
  322. no_ad_mid_group_list = abtest_param.get('no_ad_mid_group_list', [])
  323. if mid_group in no_ad_mid_group_list:
  324. # 在免广告用户组列表中,则不出广告
  325. ad_predict = 1
  326. result = {
  327. 'mid_group': mid_group,
  328. 'ad_predict': ad_predict
  329. }
  330. else:
  331. # 获取用户组出广告后分享的概率
  332. share_user_data_key = abtest_param['share']['user'].get('data')
  333. share_user_rule_key = abtest_param['share']['user'].get('rule')
  334. group_share_rate_key = \
  335. f"{config_.KEY_NAME_PREFIX_AD_GROUP}{share_user_data_key}:{share_user_rule_key}:{now_dt}"
  336. if not redis_helper.key_exists(group_share_rate_key):
  337. redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
  338. group_share_rate_key = \
  339. f"{config_.KEY_NAME_PREFIX_AD_GROUP}{share_user_data_key}:{share_user_rule_key}:{redis_dt}"
  340. group_share_rate = redis_helper.get_score_with_value(key_name=group_share_rate_key, value=mid_group)
  341. # 获取视频出广告后分享的概率
  342. share_video_data_key = abtest_param['share']['video'].get('data')
  343. video_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_VIDEO}{share_video_data_key}:{now_dt}"
  344. if not redis_helper.key_exists(video_share_rate_key):
  345. redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
  346. video_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_VIDEO}{share_video_data_key}:{redis_dt}"
  347. video_share_rate = redis_helper.get_score_with_value(key_name=video_share_rate_key, value=int(video_id))
  348. if video_share_rate is None:
  349. video_share_rate = redis_helper.get_score_with_value(key_name=video_share_rate_key, value=-1)
  350. # 获取用户组出广告后不直接跳出的概率
  351. out_user_data_key = abtest_param['out']['user'].get('data')
  352. out_user_rule_key = abtest_param['out']['user'].get('rule')
  353. group_out_rate_key = \
  354. f"{config_.KEY_NAME_PREFIX_AD_GROUP}{out_user_data_key}:{out_user_rule_key}:{now_dt}"
  355. if not redis_helper.key_exists(group_out_rate_key):
  356. redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
  357. group_out_rate_key = \
  358. f"{config_.KEY_NAME_PREFIX_AD_GROUP}{out_user_data_key}:{out_user_rule_key}:{redis_dt}"
  359. group_out_rate = redis_helper.get_score_with_value(key_name=group_out_rate_key, value=mid_group)
  360. # 获取视频出广告后不直接跳出的概率
  361. out_video_data_key = abtest_param['out']['video'].get('data')
  362. video_out_rate_key = f"{config_.KEY_NAME_PREFIX_AD_VIDEO}{out_video_data_key}:{now_dt}"
  363. if not redis_helper.key_exists(video_out_rate_key):
  364. redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
  365. video_out_rate_key = f"{config_.KEY_NAME_PREFIX_AD_VIDEO}{out_video_data_key}:{redis_dt}"
  366. video_out_rate = redis_helper.get_score_with_value(key_name=video_out_rate_key, value=int(video_id))
  367. if video_out_rate is None:
  368. video_out_rate = redis_helper.get_score_with_value(key_name=video_out_rate_key, value=-1)
  369. # 计算 mid-video 预测值
  370. if group_share_rate is None or video_share_rate is None or group_out_rate is None or video_out_rate is None:
  371. return None
  372. # 乘积融合
  373. group_rate = float(group_share_rate) * float(group_out_rate)
  374. video_rate = float(video_share_rate) * float(video_out_rate)
  375. mid_video_predict_res = group_rate * video_rate
  376. # 获取对应的阈值
  377. threshold = get_threshold(
  378. abtest_id=abtest_id,
  379. abtest_config_tag=abtest_config_tag,
  380. ab_test_code=ab_test_code,
  381. mid_group=mid_group,
  382. care_model_status=care_model_status,
  383. abtest_param=abtest_param
  384. )
  385. # 阈值判断
  386. if mid_video_predict_res > threshold:
  387. # 大于阈值,出广告
  388. ad_predict = 2
  389. else:
  390. # 否则,不出广告
  391. ad_predict = 1
  392. result = {
  393. 'mid_group': mid_group,
  394. 'group_share_rate': group_share_rate,
  395. 'video_share_rate': video_share_rate,
  396. 'group_out_rate': group_out_rate,
  397. 'video_out_rate': video_out_rate,
  398. 'group_rate': group_rate,
  399. 'video_rate': video_rate,
  400. 'mid_video_predict_res': mid_video_predict_res,
  401. 'threshold': threshold,
  402. 'ad_predict': ad_predict}
  403. return result
  404. def ad_recommend_predict(app_type, mid, video_id, ab_exp_info, ab_test_code, care_model_status):
  405. """
  406. 广告推荐预测
  407. :param app_type: app_type
  408. :param mid: mid
  409. :param video_id: video_id
  410. :param ab_exp_info: AB实验组参数
  411. :param ab_test_code: 用户对应的ab组
  412. :param care_model_status: 用户关怀模式状态 1-未开启,2-开启
  413. :return: ad_predict, type-int, 1-不发放广告,2-发放广告
  414. """
  415. try:
  416. now_date = datetime.datetime.today()
  417. # now_dt = datetime.datetime.strftime(now_date, '%Y%m%d')
  418. now_h = datetime.datetime.now().hour
  419. if 0 <= now_h < 8:
  420. # 00:00 - 08:00 不出广告
  421. ad_predict = 1
  422. result = {
  423. 'now_h': now_h,
  424. 'ad_predict': ad_predict
  425. }
  426. return result
  427. # 获取实验参数
  428. abtest_id, abtest_config_tag = get_params(ab_exp_info=ab_exp_info, ab_test_code=ab_test_code)
  429. if abtest_id is None or abtest_config_tag is None:
  430. return None
  431. abtest_param = config_.AD_ABTEST_CONFIG.get(f'{abtest_id}-{abtest_config_tag}')
  432. if abtest_param is None:
  433. return None
  434. threshold_mix_func = abtest_param.get('threshold_mix_func', None)
  435. if threshold_mix_func == 'add':
  436. result = predict_mid_video_res_with_add(
  437. now_date=now_date,
  438. mid=mid,
  439. video_id=video_id,
  440. abtest_param=abtest_param,
  441. abtest_id=abtest_id,
  442. abtest_config_tag=abtest_config_tag,
  443. ab_test_code=ab_test_code,
  444. care_model_status=care_model_status
  445. )
  446. elif threshold_mix_func == 'multiply':
  447. result = predict_mid_video_res_with_multiply(
  448. now_date=now_date,
  449. mid=mid,
  450. video_id=video_id,
  451. abtest_param=abtest_param,
  452. abtest_id=abtest_id,
  453. abtest_config_tag=abtest_config_tag,
  454. ab_test_code=ab_test_code,
  455. care_model_status=care_model_status
  456. )
  457. elif threshold_mix_func == 'model':
  458. result = predict_mid_video_res_with_model(
  459. now_date=now_date,
  460. mid=mid,
  461. video_id=video_id,
  462. abtest_param=abtest_param,
  463. abtest_id=abtest_id,
  464. abtest_config_tag=abtest_config_tag,
  465. ab_test_code=ab_test_code,
  466. care_model_status=care_model_status
  467. )
  468. else:
  469. result = predict_mid_video_res(
  470. now_date=now_date,
  471. mid=mid,
  472. video_id=video_id,
  473. abtest_param=abtest_param,
  474. abtest_id=abtest_id,
  475. abtest_config_tag=abtest_config_tag,
  476. ab_test_code=ab_test_code,
  477. care_model_status=care_model_status,
  478. app_type=app_type
  479. )
  480. # user_data_key = abtest_param['user'].get('data')
  481. # user_rule_key = abtest_param['user'].get('rule')
  482. # video_data_key = abtest_param['video'].get('data')
  483. # group_class_key = abtest_param.get('group_class_key')
  484. # no_ad_mid_group_list = abtest_param.get('no_ad_mid_group_list', [])
  485. #
  486. # # 判断mid所属分组
  487. # mid_group_key_name = f"{config_.KEY_NAME_PREFIX_MID_GROUP}{group_class_key}:{mid}"
  488. # mid_group = redis_helper.get_data_from_redis(key_name=mid_group_key_name)
  489. # if mid_group is None:
  490. # mid_group = 'mean_group'
  491. #
  492. # # 判断用户是否在免广告用户组列表中
  493. # if mid_group in no_ad_mid_group_list:
  494. # # 在免广告用户组列表中,则不出广告
  495. # ad_predict = 1
  496. # result = {
  497. # 'mid_group': mid_group,
  498. # 'ad_predict': ad_predict
  499. # }
  500. # else:
  501. # # 获取用户组分享率
  502. # group_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_GROUP}{user_data_key}:{user_rule_key}:{now_dt}"
  503. # if not redis_helper.key_exists(group_share_rate_key):
  504. # redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
  505. # group_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_GROUP}{user_data_key}:{user_rule_key}:{redis_dt}"
  506. # group_share_rate = redis_helper.get_score_with_value(key_name=group_share_rate_key, value=mid_group)
  507. # # 获取视频分享率
  508. # video_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_VIDEO}{video_data_key}:{now_dt}"
  509. # if not redis_helper.key_exists(video_share_rate_key):
  510. # redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
  511. # video_share_rate_key = f"{config_.KEY_NAME_PREFIX_AD_VIDEO}{video_data_key}:{redis_dt}"
  512. # video_share_rate = redis_helper.get_score_with_value(key_name=video_share_rate_key, value=int(video_id))
  513. # if video_share_rate is None:
  514. # video_share_rate = redis_helper.get_score_with_value(key_name=video_share_rate_key, value=-1)
  515. #
  516. # # 计算 mid-video 分享率
  517. # if group_share_rate is None or video_share_rate is None:
  518. # return None
  519. # mid_video_share_rate = float(group_share_rate) * float(video_share_rate)
  520. #
  521. # # 获取对应的阈值
  522. # threshold = get_threshold(
  523. # abtest_id=abtest_id,
  524. # abtest_config_tag=abtest_config_tag,
  525. # ab_test_code=ab_test_code,
  526. # mid_group=mid_group,
  527. # care_model_status=care_model_status,
  528. # abtest_param=abtest_param
  529. # )
  530. # # 阈值判断
  531. # if mid_video_share_rate > threshold:
  532. # # 大于阈值,出广告
  533. # ad_predict = 2
  534. # else:
  535. # # 否则,不出广告
  536. # ad_predict = 1
  537. # result = {
  538. # 'mid_group': mid_group,
  539. # 'group_share_rate': group_share_rate,
  540. # 'video_share_rate': video_share_rate,
  541. # 'mid_video_share_rate': mid_video_share_rate,
  542. # 'threshold': threshold,
  543. # 'ad_predict': ad_predict}
  544. return result
  545. except Exception as e:
  546. log_.error(traceback.format_exc())
  547. return None
  548. def ad_recommend_predict_with_roi(app_type, mid, video_id, ads, arpu, roi_param):
  549. """
  550. 广告推荐预测
  551. :param app_type: app_type
  552. :param mid: mid
  553. :param video_id: video_id
  554. :param ads: 需要发放广告列表 list
  555. :param arpu: 上一周期arpu值
  556. :param roi_param: 计算roi使用参数
  557. :return: ad_predict, type-int, 1-不发放广告,2-发放广告
  558. """
  559. try:
  560. now_date = datetime.datetime.today()
  561. now_dt = datetime.datetime.strftime(now_date, '%Y%m%d')
  562. ad_info = ads[0]
  563. ad_id = ad_info['adId']
  564. ad_type = ad_info['adType']
  565. ecpm = float(ad_info['ecpm'])
  566. # 获取参数
  567. params = config_.PARAMS_NEW_STRATEGY[int(app_type)]
  568. # 判断mid所属分组
  569. group_class_key = params.get('group_class_key')
  570. mid_group_key_name = f"{config_.KEY_NAME_PREFIX_MID_GROUP}{group_class_key}:{mid}"
  571. mid_group = redis_helper.get_data_from_redis(key_name=mid_group_key_name)
  572. if mid_group is None:
  573. mid_group = 'mean_group'
  574. # 获取用户组出广告后分享的概率
  575. share_user_data_key = params['user'].get('data')
  576. share_user_rule_key = params['user'].get('rule')
  577. group_share_rate_key_with_ad = \
  578. f"{config_.KEY_NAME_PREFIX_GROUP_WITH_AD}{share_user_data_key}:{share_user_rule_key}:{now_dt}"
  579. if not redis_helper.key_exists(group_share_rate_key_with_ad):
  580. redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
  581. group_share_rate_key_with_ad = \
  582. f"{config_.KEY_NAME_PREFIX_GROUP_WITH_AD}{share_user_data_key}:{share_user_rule_key}:{redis_dt}"
  583. group_share_rate_with_ad = redis_helper.get_score_with_value(key_name=group_share_rate_key_with_ad,
  584. value=mid_group)
  585. # 获取视频出广告后分享的概率
  586. share_video_data_key = params['video'].get('data')
  587. video_share_rate_key_with_ad = f"{config_.KEY_NAME_PREFIX_VIDEO_WITH_AD}{share_video_data_key}:{now_dt}"
  588. if not redis_helper.key_exists(video_share_rate_key_with_ad):
  589. redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
  590. video_share_rate_key_with_ad = f"{config_.KEY_NAME_PREFIX_VIDEO_WITH_AD}{share_video_data_key}:{redis_dt}"
  591. video_share_rate_with_ad = redis_helper.get_score_with_value(key_name=video_share_rate_key_with_ad,
  592. value=int(video_id))
  593. if video_share_rate_with_ad is None:
  594. video_share_rate_with_ad = redis_helper.get_score_with_value(key_name=video_share_rate_key_with_ad,
  595. value=-1)
  596. # 获取用户组不出广告后分享的概率
  597. group_share_rate_key_no_ad = \
  598. f"{config_.KEY_NAME_PREFIX_GROUP_NO_AD}{share_user_data_key}:{share_user_rule_key}:{now_dt}"
  599. if not redis_helper.key_exists(group_share_rate_key_no_ad):
  600. redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
  601. group_share_rate_key_no_ad = \
  602. f"{config_.KEY_NAME_PREFIX_GROUP_NO_AD}{share_user_data_key}:{share_user_rule_key}:{redis_dt}"
  603. group_share_rate_no_ad = redis_helper.get_score_with_value(key_name=group_share_rate_key_no_ad, value=mid_group)
  604. # 获取视频不出广告后分享的概率
  605. video_share_rate_key_no_ad = f"{config_.KEY_NAME_PREFIX_VIDEO_NO_AD}{share_video_data_key}:{now_dt}"
  606. if not redis_helper.key_exists(video_share_rate_key_no_ad):
  607. redis_dt = datetime.datetime.strftime(now_date - datetime.timedelta(days=1), '%Y%m%d')
  608. video_share_rate_key_no_ad = f"{config_.KEY_NAME_PREFIX_VIDEO_NO_AD}{share_video_data_key}:{redis_dt}"
  609. video_share_rate_no_ad = redis_helper.get_score_with_value(key_name=video_share_rate_key_no_ad,
  610. value=int(video_id))
  611. if video_share_rate_no_ad is None:
  612. video_share_rate_no_ad = redis_helper.get_score_with_value(key_name=video_share_rate_key_no_ad, value=-1)
  613. if group_share_rate_with_ad is None or video_share_rate_with_ad is None \
  614. or group_share_rate_no_ad is None or video_share_rate_no_ad is None:
  615. return None
  616. # 计算此次请求出广告后分享的概率
  617. share_rate_with_ad = float(group_share_rate_with_ad) * float(video_share_rate_with_ad)
  618. # 计算此次请求不出广告分享的概率
  619. share_rate_no_ad = float(group_share_rate_no_ad) * float(video_share_rate_no_ad)
  620. # 计算此次请求出广告的收入增益
  621. roi_ad = ecpm / 1000 - float(roi_param) * float(arpu) * (share_rate_no_ad - share_rate_with_ad)
  622. # 收入增益判断
  623. if roi_ad > 0:
  624. # 大于0,出广告
  625. ad_predict = 2
  626. else:
  627. # 否则,不出广告
  628. ad_predict = 1
  629. result = {
  630. 'arpu': arpu,
  631. 'roi_param': roi_param,
  632. 'ad_id': ad_id,
  633. 'ad_type': ad_type,
  634. 'mid_group': mid_group,
  635. 'group_share_rate_with_ad': group_share_rate_with_ad,
  636. 'video_share_rate_with_ad': video_share_rate_with_ad,
  637. 'group_share_rate_no_ad': group_share_rate_no_ad,
  638. 'video_share_rate_no_ad': video_share_rate_no_ad,
  639. 'share_rate_with_ad': share_rate_with_ad,
  640. 'share_rate_no_ad': share_rate_no_ad,
  641. 'roi_ad': roi_ad,
  642. 'ad_predict': ad_predict
  643. }
  644. return result
  645. except Exception as e:
  646. log_.error(traceback.format_exc())
  647. return None