videos_filter.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. import time
  2. import json
  3. import traceback
  4. from datetime import date, timedelta, datetime
  5. from utils import filter_video_status, send_msg_to_feishu
  6. from db_helper import RedisHelper
  7. from config import set_config
  8. from log import Log
  9. config_, env = set_config()
  10. log_ = Log()
  11. def filter_position_videos():
  12. """按位置排序视频过滤"""
  13. log_.info("position videos filter start...")
  14. position_key_list = [config_.RECALL_POSITION1_KEY_NAME, config_.RECALL_POSITION2_KEY_NAME]
  15. redis_helper = RedisHelper()
  16. for key_name in position_key_list:
  17. position = key_name.split('.')[-1]
  18. log_.info("position = {}".format(position))
  19. # 获取数据
  20. position_videos = redis_helper.get_data_from_redis(key_name=key_name)
  21. if position_videos is None:
  22. log_.info('position {} videos is None!'.format(position))
  23. continue
  24. else:
  25. # 过滤
  26. position_video_ids = [int(video_id) for video_id in json.loads(position_videos)]
  27. filter_video_ids = filter_video_status(video_ids=position_video_ids)
  28. # 重新写入redis
  29. redis_helper.set_data_to_redis(key_name=key_name,
  30. value=json.dumps(filter_video_ids),
  31. expire_time=30 * 3600)
  32. log_.info('position {} videos filter end!'.format(position))
  33. log_.info("position videos filter end!")
  34. def filter_relevant_videos():
  35. """运营强插相关推荐视频过滤"""
  36. log_.info("relevant videos with op filter filter start...")
  37. # 读取需要过滤的头部视频id
  38. redis_helper = RedisHelper()
  39. head_videos = redis_helper.get_data_from_set(key_name=config_.RELEVANT_TOP_VIDEOS_KEY_NAME)
  40. if head_videos is None or len(head_videos) == 0:
  41. log_.info("relevant videos with op filter end! head_videos = {}".format(head_videos))
  42. return
  43. # 过滤
  44. remove_head_vids = []
  45. for head_vid in head_videos:
  46. key_name = '{}{}'.format(config_.RELEVANT_VIDEOS_WITH_OP_KEY_NAME, head_vid)
  47. # 头部视频 对应的key不存在时,将head_vid移除对应redis
  48. if not redis_helper.key_exists(key_name=key_name):
  49. remove_head_vids.append(head_vid)
  50. log_.info('head_vid = {} relevant redis key not exist!'.format(head_vid))
  51. continue
  52. # 获取头部视频对应的相关视频
  53. relevant_videos = redis_helper.get_data_from_redis(key_name=key_name)
  54. # 该视频没有指定的相关性视频,将head_vid移除对应redis
  55. if relevant_videos is None:
  56. remove_head_vids.append(head_vid)
  57. log_.info('head_vid = {} not have relevant videos!'.format(head_vid))
  58. continue
  59. # 过滤
  60. relevant_videos = json.loads(relevant_videos)
  61. relevant_video_ids = [int(item['recommend_vid']) for item in relevant_videos]
  62. filtered_videos = filter_video_status(video_ids=relevant_video_ids)
  63. # 保留可推荐 且生效中 的视频
  64. relevant_videos_new = [
  65. item for item in relevant_videos
  66. if int(item['recommend_vid']) in filtered_videos and int(item['finish_time']) > int(time.time())
  67. ]
  68. # 过滤后没有符合的视频,将head_vid移除对应redis,删除对应的相关推荐的key
  69. if len(relevant_videos_new) == 0:
  70. remove_head_vids.append(head_vid)
  71. redis_helper.del_keys(key_name=key_name)
  72. log_.info('head_vid = {} filtered finished! new relevant videos count = {}'.format(
  73. head_vid, len(relevant_videos_new)))
  74. continue
  75. # 重新写入redis
  76. # 以最晚结束的视频的结束时间 - 当前时间 + 5s 作为key的过期时间
  77. finish_time_list = [item['finish_time'] for item in relevant_videos_new]
  78. expire_time = max(finish_time_list) - int(time.time()) + 5
  79. if expire_time <= 0:
  80. log_.info('head_vid = {} expire_time <= 0!'.format(head_vid))
  81. continue
  82. # 存入redis
  83. redis_helper.set_data_to_redis(key_name=key_name,
  84. value=json.dumps(relevant_videos_new),
  85. expire_time=expire_time)
  86. log_.info('head_vid = {} filtered finished! new relevant videos count = {}'.format(
  87. head_vid, len(relevant_videos_new)))
  88. # 将需要移除的头部视频id进行移除
  89. if len(remove_head_vids) == 0:
  90. log_.info('head videos remove finished! remove_head_vids = {}'.format(remove_head_vids))
  91. log_.info("relevant videos with op filter end!")
  92. return
  93. redis_helper.remove_value_from_set(key_name=config_.RELEVANT_TOP_VIDEOS_KEY_NAME, values=tuple(remove_head_vids))
  94. log_.info('head videos remove finished! remove_head_vids = {}'.format(remove_head_vids))
  95. log_.info("relevant videos with op filter end!")
  96. def filter_rov_pool(app_type=None):
  97. """ROV召回池视频过滤"""
  98. log_.info("rov recall pool filter start ...")
  99. # 拼接redis-key
  100. if app_type is None:
  101. key_name, _ = get_pool_redis_key(pool_type='rov')
  102. else:
  103. log_.info("appType = {}".format(app_type))
  104. key_name, _ = get_pool_redis_key(pool_type='rov', app_type=app_type)
  105. # 获取视频
  106. redis_helper = RedisHelper()
  107. data = redis_helper.get_data_zset_with_index(key_name=key_name, start=0, end=-1)
  108. if data is None:
  109. log_.info("data is None")
  110. log_.info("rov recall pool filter end!")
  111. return
  112. # 过滤
  113. video_ids = [int(video_id) for video_id in data]
  114. filtered_result = filter_video_status(video_ids=video_ids)
  115. # 求差集,获取需要过滤掉的视频,并从redis中移除
  116. filter_videos = set(video_ids) - set(filtered_result)
  117. log_.info("video_ids size = {}, filtered size = {}, filter sizer = {}".format(len(video_ids),
  118. len(filtered_result),
  119. len(filter_videos)))
  120. if len(filter_videos) == 0:
  121. log_.info("rov recall pool filter end!")
  122. return
  123. redis_helper.remove_value_from_zset(key_name=key_name, value=list(filter_videos))
  124. log_.info("rov recall pool filter end!")
  125. def filter_flow_pool():
  126. """流量池视频过滤"""
  127. log_.info("flow pool filter start ...")
  128. for _, app_type in config_.APP_TYPE.items():
  129. log_.info('app_type {} videos filter start...'.format(app_type))
  130. # 拼接redis-key
  131. key_name = get_pool_redis_key(pool_type='flow', app_type=app_type)
  132. # 获取视频
  133. redis_helper = RedisHelper()
  134. data = redis_helper.get_data_zset_with_index(key_name=key_name, start=0, end=-1)
  135. if data is None:
  136. log_.info("data is None")
  137. log_.info("app_type {} videos filter end!".format(app_type))
  138. continue
  139. # videoId与flowPool做mapping
  140. video_ids = []
  141. mapping = {}
  142. for video in data:
  143. video_id, flow_pool = video.split('-')
  144. video_id = int(video_id)
  145. if video_id not in video_ids:
  146. video_ids.append(video_id)
  147. mapping[video_id] = [flow_pool]
  148. else:
  149. mapping[video_id].append(flow_pool)
  150. # 过滤
  151. if len(video_ids) == 0:
  152. log_.info("data size = {}, video_ids size = {}, data = {}".format(len(data), len(video_ids), data))
  153. log_.info("app_type {} videos filter end!".format(app_type))
  154. continue
  155. filtered_result = filter_video_status(video_ids=video_ids)
  156. # 求差集,获取需要过滤掉的视频,并从redis中移除
  157. filter_videos = set(video_ids) - set(filtered_result)
  158. log_.info("data size = {}, video_ids size = {}, filtered size = {}, filter sizer = {}".format(
  159. len(data), len(video_ids), len(filtered_result), len(filter_videos)))
  160. # 移除
  161. if len(filter_videos) == 0:
  162. log_.info("app_type {} videos filter end!".format(app_type))
  163. continue
  164. remove_videos = ['{}-{}'.format(video_id, flow_pool)
  165. for video_id in filter_videos
  166. for flow_pool in mapping[video_id]]
  167. redis_helper.remove_value_from_zset(key_name=key_name, value=remove_videos)
  168. log_.info("app_type {} videos filter end!".format(app_type))
  169. log_.info("flow pool filter end!")
  170. def filter_bottom():
  171. """兜底视频过滤"""
  172. log_.info("bottom videos filter start ...")
  173. # 获取视频
  174. redis_helper = RedisHelper()
  175. data = redis_helper.get_data_zset_with_index(key_name=config_.BOTTOM_KEY_NAME, start=0, end=-1)
  176. if data is None:
  177. log_.info("data is None")
  178. log_.info("bottom videos filter end!")
  179. return
  180. # 过滤
  181. video_ids = [int(video_id) for video_id in data]
  182. filtered_result = filter_video_status(video_ids=video_ids)
  183. # 求差集,获取需要过滤掉的视频,并从redis中移除
  184. filter_videos = set(video_ids) - set(filtered_result)
  185. log_.info("video_ids size = {}, filtered size = {}, filter sizer = {}".format(len(video_ids),
  186. len(filtered_result),
  187. len(filter_videos)))
  188. if len(filter_videos) == 0:
  189. log_.info("bottom videos filter end!")
  190. return
  191. redis_helper.remove_value_from_zset(key_name=config_.BOTTOM_KEY_NAME, value=list(filter_videos))
  192. log_.info("bottom videos filter end!")
  193. def filter_rov_updated():
  194. """修改过ROV的视频过滤"""
  195. log_.info("update rov videos filter start ...")
  196. # 获取视频
  197. redis_helper = RedisHelper()
  198. data = redis_helper.get_data_zset_with_index(key_name=config_.UPDATE_ROV_KEY_NAME, start=0, end=-1)
  199. if data is None:
  200. log_.info("data is None")
  201. log_.info("update rov videos filter end!")
  202. return
  203. # 过滤
  204. video_ids = [int(video_id) for video_id in data]
  205. filtered_result = filter_video_status(video_ids=video_ids)
  206. # 求差集,获取需要过滤掉的视频,并从redis中移除
  207. filter_videos = set(video_ids) - set(filtered_result)
  208. log_.info("video_ids size = {}, filtered size = {}, filter sizer = {}".format(len(video_ids),
  209. len(filtered_result),
  210. len(filter_videos)))
  211. if len(filter_videos) == 0:
  212. log_.info("update rov videos filter end!")
  213. return
  214. redis_helper.remove_value_from_zset(key_name=config_.UPDATE_ROV_KEY_NAME, value=list(filter_videos))
  215. log_.info("update rov videos filter end!")
  216. def get_pool_redis_key(pool_type, app_type=None):
  217. """
  218. 拼接key
  219. :param pool_type: type-string {'rov': rov召回池, 'flow': 流量池}
  220. :param app_type: 产品标识
  221. :return: key_name
  222. """
  223. redis_helper = RedisHelper()
  224. if pool_type == 'rov':
  225. # appType = 6
  226. if app_type == config_.APP_TYPE['SHORT_VIDEO']:
  227. # 获取当前所在小时
  228. redis_date = datetime.now().hour
  229. # 判断热度列表是否更新,未更新则使用前一小时的热度列表
  230. key_name = '{}{}.{}'.format(config_.RECALL_KEY_NAME_PREFIX_APP_TYPE, app_type, redis_date)
  231. if redis_helper.key_exists(key_name):
  232. return key_name, redis_date
  233. else:
  234. if redis_date == 0:
  235. redis_date = 23
  236. else:
  237. redis_date = redis_date - 1
  238. key_name = '{}{}.{}'.format(config_.RECALL_KEY_NAME_PREFIX_APP_TYPE, app_type, redis_date)
  239. return key_name, redis_date
  240. # 其他
  241. else:
  242. # 判断热度列表是否更新,未更新则使用前一天的热度列表
  243. key_name = config_.RECALL_KEY_NAME_PREFIX + time.strftime('%Y%m%d')
  244. if redis_helper.key_exists(key_name):
  245. redis_date = date.today().strftime('%Y%m%d')
  246. else:
  247. redis_date = (date.today() - timedelta(days=1)).strftime('%Y%m%d')
  248. key_name = config_.RECALL_KEY_NAME_PREFIX + redis_date
  249. return key_name, redis_date
  250. elif pool_type == 'flow':
  251. # 流量池
  252. return config_.FLOWPOOL_KEY_NAME_PREFIX + str(app_type)
  253. else:
  254. log_.error('pool type error')
  255. return None, None
  256. def main():
  257. try:
  258. # ROV召回池视频过滤
  259. filter_rov_pool()
  260. # appType = 6,ROV召回池视频过滤
  261. filter_rov_pool(app_type=config_.APP_TYPE['SHORT_VIDEO'])
  262. # 流量池视频过滤
  263. filter_flow_pool()
  264. # 兜底视频过滤
  265. filter_bottom()
  266. # 修改过ROV的视频过滤
  267. filter_rov_updated()
  268. # 运营强插相关推荐视频过滤
  269. filter_relevant_videos()
  270. # 按位置排序视频过滤
  271. filter_position_videos()
  272. except Exception as e:
  273. log_.error(traceback.format_exc())
  274. send_msg_to_feishu('{} - 过滤失败 \n {}'.format(config_.ENV_TEXT, traceback.format_exc()))
  275. return
  276. if __name__ == '__main__':
  277. main()