02_ad_model_update_test.sh 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. #!/bin/sh
  2. set -x
  3. export PATH=$SPARK_HOME/bin:$PATH
  4. export HADOOP_CONF_DIR=/etc/taihao-apps/hadoop-conf
  5. export JAVA_HOME=/usr/lib/jvm/java-1.8.0
  6. sh_path=$(cd $(dirname $0); pwd)
  7. source ${sh_path}/00_common.sh
  8. source /root/anaconda3/bin/activate py37
  9. # 全局常量
  10. HADOOP=/opt/apps/HADOOP-COMMON/hadoop-common-current/bin/hadoop
  11. TRAIN_PATH=/dw/recommend/model/31_ad_sample_data_v4
  12. BUCKET_FEATURE_PATH=/dw/recommend/model/33_ad_train_data_v4
  13. TABLE=alg_recsys_ad_sample_all
  14. # 特征文件名
  15. feature_file=20240703_ad_feature_name.txt
  16. # 模型本地临时保存路径
  17. model_local_home=/root/zhaohp/XGB/
  18. # 模型HDFS保存路径,测试时修改为其他路径,避免影响线上
  19. MODEL_PATH=/dw/recommend/model/35_ad_model
  20. # 预测结果保存路径,测试时修改为其他路径,避免影响线上
  21. PREDICT_RESULT_SAVE_PATH=/dw/recommend/model/34_ad_predict_data
  22. # 模型OSS保存路径,测试时修改为其他路径,避免影响线上
  23. MODEL_OSS_PATH=oss://art-recommend.oss-cn-hangzhou.aliyuncs.com/zhangbo/
  24. # 线上模型名,测试时修改为其他模型名,避免影响线上
  25. model_name=model_xgb_351_1000_v2
  26. # 线上校准文件名
  27. OSS_CALIBRATION_FILE_NAME=model_xgb_351_1000_v2_calibration
  28. # 本地保存HDFS模型路径文件,测试时修改为其他模型名,避免影响线上
  29. model_path_file=${model_local_home}/online_model_path.txt
  30. # 获取当前是星期几,1表示星期一
  31. current_day_of_week="$(date +"%u")"
  32. # 任务开始时间
  33. start_time=$(date +%s)
  34. # 前一天
  35. today_early_1="$(date -d '1 days ago' +%Y%m%d)"
  36. # 线上模型在HDFS中的路径
  37. online_model_path=`cat ${model_path_file}`
  38. # 训练用的数据路径
  39. train_data_path=""
  40. # 评估用的数据路径
  41. predict_date_path=""
  42. #评估结果保存路径
  43. new_model_predict_result_path=""
  44. # 模型保存路径
  45. model_save_path=""
  46. # 评测结果保存路径,后续需要根据此文件评估是否要更新模型
  47. predict_analyse_file_path=""
  48. # 校准文件保存路径
  49. calibration_file_path=""
  50. # 保存模型评估的分析结果
  51. old_incr_rate_avg=0
  52. new_incr_rate_avg=0
  53. top10_msg=""
  54. # 校验命令的退出码
  55. check_run_status() {
  56. local status=$1
  57. local step_start_time=$2
  58. local step_name=$3
  59. local msg=$4
  60. local step_end_time=$(date +%s)
  61. local step_elapsed=$(($step_end_time - $step_start_time))
  62. if [ $status -ne 0 ]; then
  63. echo "$LOG_PREFIX -- ${step_name}失败: 耗时 $step_elapsed"
  64. local elapsed=$(($step_end_time - $start_time))
  65. /root/anaconda3/bin/python ${sh_path}/ad_monitor_util.py --level error --msg "$msg" --start "$start_time" --elapsed "$elapsed" --top10 "${top10_msg}"
  66. exit 1
  67. else
  68. echo "$LOG_PREFIX -- ${step_name}成功: 耗时 $step_elapsed"
  69. fi
  70. }
  71. send_success_upload_msg(){
  72. # 发送更新成功通知
  73. local msg=" 广告模型文件更新完成"
  74. msg+="\n\t - 老模型Top10差异平均值: ${old_incr_rate_avg}"
  75. msg+="\n\t - 新模型Top10差异平均值: ${new_incr_rate_avg}"
  76. msg+="\n\t - 模型在HDFS中的路径: ${model_save_path}"
  77. msg+="\n\t - 模型上传OSS中的路径: ${MODEL_OSS_PATH}/${model_name}.tar.gz"
  78. local step_end_time=$(date +%s)
  79. local elapsed=$(($step_end_time - $start_time))
  80. /root/anaconda3/bin/python ${sh_path}/ad_monitor_util.py --level info --msg "${msg}" --start "${start_time}" --elapsed "${elapsed}" --top10 "${top10_msg}"
  81. }
  82. init() {
  83. declare -a date_keys=()
  84. local count=1
  85. local current_data="$(date -d '2 days ago' +%Y%m%d)"
  86. # 循环获取前 n 天的非节日日期
  87. while [[ $count -lt 7 ]]; do
  88. date_key=$(date -d "$current_data" +%Y%m%d)
  89. # 判断是否是节日,并拼接训练数据路径
  90. if [ $(is_not_holidays $date_key) -eq 1 ]; then
  91. # 将 date_key 放入数组
  92. date_keys+=("$date_key")
  93. if [[ -z ${train_data_path} ]]; then
  94. train_data_path="${BUCKET_FEATURE_PATH}/${date_key}"
  95. else
  96. train_data_path="${BUCKET_FEATURE_PATH}/${date_key},${train_data_path}"
  97. fi
  98. count=$((count + 1))
  99. else
  100. echo "日期: ${date_key}是节日,跳过"
  101. fi
  102. current_data=$(date -d "$current_data -1 day" +%Y%m%d)
  103. done
  104. last_index=$((${#date_keys[@]} - 1))
  105. train_first_day=${date_keys[$last_index]}
  106. train_last_day=${date_keys[0]}
  107. model_save_path=${MODEL_PATH}/${model_name}_${train_first_day: -4}_${train_last_day: -4}
  108. predict_date_path=${BUCKET_FEATURE_PATH}/${today_early_1}
  109. new_model_predict_result_path=/dw/recommend/model/34_ad_predict_data/20241104_351_1000_1028_1102
  110. online_model_predict_result_path=/dw/recommend/model/34_ad_predict_data/20241104_351_1000_1028_1102
  111. predict_analyse_file_path=${model_local_home}/predict_analyse_file/${today_early_1}_351_1000_analyse.txt
  112. calibration_file_path=${model_local_home}/${OSS_CALIBRATION_FILE_NAME}.txt
  113. echo "init param train_data_path: ${train_data_path}"
  114. echo "init param predict_date_path: ${predict_date_path}"
  115. echo "init param new_model_predict_result_path: ${new_model_predict_result_path}"
  116. echo "init param online_model_predict_result_path: ${online_model_predict_result_path}"
  117. echo "init param model_save_path: ${model_save_path}"
  118. echo "init param online_model_path: ${online_model_path}"
  119. echo "init param feature_file: ${feature_file}"
  120. echo "init param model_name: ${model_name}"
  121. echo "init param model_local_home: ${model_local_home}"
  122. echo "init param model_oss_path: ${MODEL_OSS_PATH}"
  123. echo "init param predict_analyse_file_path: ${predict_analyse_file_path}"
  124. echo "init param calibration_file_path: ${calibration_file_path}"
  125. echo "init param current_day_of_week: ${current_day_of_week}"
  126. echo "当前Python环境安装的Python版本: $(python --version)"
  127. echo "当前Python环境安装的三方包: $(python -m pip list)"
  128. }
  129. calc_model_predict() {
  130. local count=0
  131. local max_line=10
  132. local old_total_diff=0
  133. local new_total_diff=0
  134. local declare -A real_score_map
  135. local declare -A old_score_map
  136. local declare -A new_score_map
  137. top10_msg="| CID | 老模型相对真实CTCVR的变化 | 新模型相对真实CTCVR的变化 |"
  138. top10_msg+=" \n| ---- | --------- | -------- |"
  139. while read -r line && [ ${count} -lt ${max_line} ]; do
  140. # 使用 ! 取反判断,只有当行中不包含 "cid" 时才执行继续的逻辑
  141. if [[ "${line}" == *"cid"* ]]; then
  142. continue
  143. fi
  144. read -a numbers <<< "${line}"
  145. # 分数分别保存
  146. real_score_map[${numbers[0]}]=${numbers[3]}
  147. old_score_map[${numbers[0]}]=${numbers[6]}
  148. new_score_map[${numbers[0]}]=${numbers[7]}
  149. # 拼接Top10详情的飞书消息
  150. top10_msg="${top10_msg} \n| ${numbers[0]} | ${numbers[6]} | ${numbers[7]} | "
  151. old_abs_score=$( echo "if(${numbers[6]} < 0) -${numbers[6]} else ${numbers[6]}" | bc -l)
  152. new_abs_score=$( echo "if(${numbers[7]} < 0) -${numbers[7]} else ${numbers[7]}" | bc -l)
  153. old_total_diff=$( echo "${old_total_diff} + ${old_abs_score}" | bc -l )
  154. new_total_diff=$( echo "${new_total_diff} + ${new_abs_score}" | bc -l )
  155. count=$((${count} + 1))
  156. done < "${predict_analyse_file_path}"
  157. local return_code=$?
  158. check_run_status $return_code $step_start_time "计算Top10差异" "计算Top10差异异常"
  159. old_incr_rate_avg=$( echo "scale=6; ${old_total_diff} / ${count}" | bc -l )
  160. check_run_status $? $step_start_time "计算老模型Top10差异" "计算老模型Top10差异异常"
  161. new_incr_rate_avg=$( echo "scale=6; ${new_total_diff} / ${count}" | bc -l )
  162. check_run_status $? $step_start_time "计算新模型Top10差异" "计算新模型Top10差异异常"
  163. echo "老模型Top10差异平均值: ${old_incr_rate_avg}"
  164. echo "新模型Top10差异平均值: ${new_incr_rate_avg}"
  165. echo "新老模型分数对比: "
  166. for cid in "${!new_score_map[@]}"; do
  167. echo "\t CID: $cid, 老模型分数: ${old_score_map[$cid]}, 新模型分数: ${new_score_map[$cid]}"
  168. done
  169. }
  170. model_predict() {
  171. local return_code=$?
  172. check_run_status $return_code $step_start_time "线上模型评估${predict_date_path: -8}的数据" "线上模型评估${predict_date_path: -8}的数据失败"
  173. # 结果分析
  174. local python_return_code=$(python ${sh_path}/model_predict_analyse.py -op ${online_model_predict_result_path} -np ${new_model_predict_result_path} -af ${predict_analyse_file_path} -cf ${calibration_file_path})
  175. check_run_status $python_return_code $step_start_time "分析线上模型评估${predict_date_path: -8}的数据" "分析线上模型评估${predict_date_path: -8}的数据失败"
  176. calc_model_predict
  177. if (( $(echo "${new_incr_rate_avg} > 0.100000" | bc -l ) ));then
  178. echo "线上模型评估${predict_date_path: -8}的数据,绝对误差大于0.1,请检查"
  179. check_run_status 1 $step_start_time "${predict_date_path: -8}的数据,绝对误差大于0.1" "线上模型评估${predict_date_path: -8}的数据,绝对误差大于0.1,请检查"
  180. exit 1
  181. fi
  182. # 对比两个模型的差异
  183. score_diff=$( echo "${new_incr_rate_avg} - ${old_incr_rate_avg}" | bc -l )
  184. if (( $(echo "${score_diff} > 0.050000" | bc -l ) ));then
  185. echo "两个模型评估${predict_date_path: -8}的数据,两个模型分数差异为: ${score_diff}, 大于0.05, 请检查"
  186. check_run_status 1 $step_start_time "两个模型评估${predict_date_path: -8}的数据" "两个模型评估${predict_date_path: -8}的数据,两个模型分数差异为: ${score_diff}, 大于0.05"
  187. exit 1
  188. fi
  189. }
  190. # 主方法
  191. main() {
  192. init
  193. model_predict
  194. }
  195. main