Commit e9dd9ad5 by hejiangming

Merge branch 'developer' of http://47.106.101.75/abel_cjy/Amazon-Selection-Data into developer

parents 940661c9 ba592e42
...@@ -3,22 +3,13 @@ ...@@ -3,22 +3,13 @@
@Description : 月流量选品 Doris 落地脚本,同时关联产出年度流量选品数据 @Description : 月流量选品 Doris 落地脚本,同时关联产出年度流量选品数据
流程: 流程:
[Step 1] Doris 建表 selection.{site}_flow_asin_month_{yyyy_mm}[_test] [Step 1] Doris 建表 selection.{site}_flow_asin_month_{yyyy_mm}[_test]
[Step 2] 读 Hive dwt_flow_asin 月数据 + 字段规范化(与 dwt.us_flow_asin_30day [Step 2] 读 Hive dwt_flow_asin 月数据 + 字段规范化(与 dwt.us_flow_asin_30day DDL 对齐)
DDL 对齐),合并为一步 [Step 3] 写入 Doris dwt 月表 dwt.{site}_flow_asin_month
[Step 3] 写入 Doris dwt 主表 dwt.{site}_flow_asin_month [Step 4] 写入 Doris dwt 年表 dwt.{site}_flow_asin_365day,并删除近12月窗口之外的过期数据
[Step 4] 写入 Doris dwt 年表 dwt.{site}_flow_asin_365day:强制重写当月数据 + [Step 5] 同步年度聚合指标 dwt.{site}_flow_asin_365day_extra:从 Hive dwt_flow_asin_year 同步过来
补齐缺失月份,靠 UNIQUE KEY+MOW+sequence_col(date_info) 自动去重只 [Step 6] Doris INSERT OVERWRITE 到 selection 月物化表 selection.{site}_flow_asin_month_{yyyy_mm}[_test]
保留每个 asin 最新一条快照,并删除近12月窗口之外的过期数据 [Step 7] Doris INSERT 到 selection 年表 selection.{site}_flow_asin_365day[_test]
[Step 5] 同步年度聚合指标 dwt.{site}_flow_asin_365day_extra:从 Hive
dwt_flow_asin_year(由 dwt/dwt_flow_asin_year.py 算好写入)对应
site_name+date_info 分区同步过来,TRUNCATE 后全量重算
[Step 6] Doris INSERT OVERWRITE 到 selection 月物化表
selection.{site}_flow_asin_month_{yyyy_mm}[_test]
[Step 7] Doris INSERT 到 selection 年表
selection.{site}_flow_asin_365day[_test]
[Step 8] 更新 MySQL workflow_everyday 流程记录表(月/年各写一条,仅 formal 模式) [Step 8] 更新 MySQL workflow_everyday 流程记录表(月/年各写一条,仅 formal 模式)
依赖:dwt/dwt_flow_asin_year.py 必须已经跑完同一个 site_name+date_info,
Step 5 才能同步到有效的年度聚合数据
支持 us / uk / de 三站点 支持 us / uk / de 三站点
支持 formal / test 模式: 支持 formal / test 模式:
- formal:selection 表名无后缀,更新流程记录表 - formal:selection 表名无后缀,更新流程记录表
...@@ -1028,7 +1019,7 @@ WHERE f.date_info = '{date_info}' ...@@ -1028,7 +1019,7 @@ WHERE f.date_info = '{date_info}'
def build_year_create_table_sql(table_name): def build_year_create_table_sql(table_name):
"""构建 selection.{table_name} 建表语句:以 selection 月表(build_month_create_table_sql) """构建 selection.{table_name} 建表语句:以 selection 月表(build_month_create_table_sql)
为基准调整而来—— 为基准调整而来——
剔除月度专属字段:asin_bought_month / asin_source_flag / bsr_last_seen_at / 剔除月度专属字段:asin_source_flag / bsr_last_seen_at /
bsr_seen_count_30d / nsr_last_seen_at / nsr_seen_count_30d bsr_seen_count_30d / nsr_last_seen_at / nsr_seen_count_30d
末尾追加:latest_date_info + dwt.{site}_flow_asin_365day_extra 里的年度聚合字段 末尾追加:latest_date_info + dwt.{site}_flow_asin_365day_extra 里的年度聚合字段
旧表已手动清理,直接 CREATE 新表,不再需要 ALTER 兼容旧表结构""" 旧表已手动清理,直接 CREATE 新表,不再需要 ALTER 兼容旧表结构"""
...@@ -1059,6 +1050,7 @@ CREATE TABLE IF NOT EXISTS `selection`.`{table_name}` ...@@ -1059,6 +1050,7 @@ CREATE TABLE IF NOT EXISTS `selection`.`{table_name}`
`low_star` INT NULL, `low_star` INT NULL,
`bsr_orders` INT NULL, `bsr_orders` INT NULL,
`bsr_orders_sale` DECIMAL(20,2) NULL, `bsr_orders_sale` DECIMAL(20,2) NULL,
`asin_bought_month` INT NULL,
`ao_val` DECIMAL(20,4) NULL, `ao_val` DECIMAL(20,4) NULL,
`zr_counts` INT NULL, `zr_counts` INT NULL,
`sp_counts` INT NULL, `sp_counts` INT NULL,
...@@ -1236,6 +1228,7 @@ SELECT ...@@ -1236,6 +1228,7 @@ SELECT
f.one_star, f.two_star, f.three_star, f.four_star, f.five_star, f.low_star, f.one_star, f.two_star, f.three_star, f.four_star, f.five_star, f.low_star,
f.bsr_orders, f.bsr_orders,
f.bsr_orders_sale, f.bsr_orders_sale,
f.asin_bought_month,
f.ao_val, f.ao_val,
f.zr_counts, f.zr_counts,
f.sp_counts, f.sb_counts, f.vi_counts, f.bs_counts, f.sp_counts, f.sb_counts, f.vi_counts, f.bs_counts,
...@@ -1491,8 +1484,7 @@ def write_year_table_batched(site_name, live_table): ...@@ -1491,8 +1484,7 @@ def write_year_table_batched(site_name, live_table):
f"ALTER TABLE `selection`.`{live_table}` REPLACE WITH TABLE `{copy_table}` " f"ALTER TABLE `selection`.`{live_table}` REPLACE WITH TABLE `{copy_table}` "
f"PROPERTIES('swap' = 'false')" f"PROPERTIES('swap' = 'false')"
]) ])
print(f"[Step 7] selection.{live_table} 已切换为最新数据," print(f"[Step 7] selection.{live_table} 已切换为最新数据")
f"selection.{copy_table} 保留的是交换前的旧数据(可用于回滚)")
# ============================================================ # ============================================================
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
- 支持断点续算:latest_computed_month 作为水位线,跳过已算月份 - 支持断点续算:latest_computed_month 作为水位线,跳过已算月份
- Doris AGGREGATE KEY(filter_id, asin) + MIN(date_info) 自动保留首次入选月份 - Doris AGGREGATE KEY(filter_id, asin) + MIN(date_info) 自动保留首次入选月份
- 每月执行一次即可(只有新月表出现时才会产生缺口) - 每月执行一次即可(只有新月表出现时才会产生缺口)
- 新月数据计算成功后,标记 notify_status=0,通知后端可以推送给用户
(后端推送完成后自行改为1;每日刷新脚本不涉及新月数据,不修改此字段)
执行示例: python dwt_user_selection_pattern.py us 执行示例: python dwt_user_selection_pattern.py us
""" """
import os import os
...@@ -76,15 +78,18 @@ def _get_available_months(doris_cur, site): ...@@ -76,15 +78,18 @@ def _get_available_months(doris_cur, site):
return months return months
def _update_mysql_log(mysql_conn, filter_id, latest_month, status, msg): def _update_mysql_log(mysql_conn, filter_id, latest_month, status, msg, mark_notify=False):
"""mark_notify=True:新月数据计算成功,同时标记 notify_status=0,通知后端可以推送给用户
(仅在真正新增了月份数据时传 True,失败/无需计算的场景不会传,因此每日刷新等场景不会碰到这个字段)"""
now = datetime.now().strftime('%Y-%m-%d %H:%M:%S') now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
notify_set = ", notify_status = 0" if mark_notify else ""
if latest_month is not None: if latest_month is not None:
# 正常情况:同步更新水位线和状态 # 正常情况:同步更新水位线和状态
sql = f"""UPDATE `{MYSQL_FILTER_TABLE}` sql = f"""UPDATE `{MYSQL_FILTER_TABLE}`
SET latest_computed_month = %s, SET latest_computed_month = %s,
last_run_status = %s, last_run_status = %s,
last_run_at = %s, last_run_at = %s,
last_run_msg = %s last_run_msg = %s{notify_set}
WHERE filter_id = %s""" WHERE filter_id = %s"""
params = (latest_month, status, now, msg[:500], filter_id) params = (latest_month, status, now, msg[:500], filter_id)
else: else:
...@@ -92,7 +97,7 @@ def _update_mysql_log(mysql_conn, filter_id, latest_month, status, msg): ...@@ -92,7 +97,7 @@ def _update_mysql_log(mysql_conn, filter_id, latest_month, status, msg):
sql = f"""UPDATE `{MYSQL_FILTER_TABLE}` sql = f"""UPDATE `{MYSQL_FILTER_TABLE}`
SET last_run_status = %s, SET last_run_status = %s,
last_run_at = %s, last_run_at = %s,
last_run_msg = %s last_run_msg = %s{notify_set}
WHERE filter_id = %s""" WHERE filter_id = %s"""
params = (status, now, msg[:500], filter_id) params = (status, now, msg[:500], filter_id)
cur = mysql_conn.cursor() cur = mysql_conn.cursor()
...@@ -143,7 +148,8 @@ def _backfill_one_filter(row, site_name, available, doris_cur, mysql_conn): ...@@ -143,7 +148,8 @@ def _backfill_one_filter(row, site_name, available, doris_cur, mysql_conn):
_update_mysql_log( _update_mysql_log(
mysql_conn, filter_id, last_ok_month, 'success', mysql_conn, filter_id, last_ok_month, 'success',
f'完成:新增 {len(all_months)} 个月({all_months[0]} ~ {all_months[-1]})' f'完成:新增 {len(all_months)} 个月({all_months[0]} ~ {all_months[-1]})',
mark_notify=True
) )
......
...@@ -29,21 +29,34 @@ class KafkaFlowAsinDetail(Templates): ...@@ -29,21 +29,34 @@ class KafkaFlowAsinDetail(Templates):
self.date_info = date_info self.date_info = date_info
self.consumer_type = consumer_type self.consumer_type = consumer_type
self.test_flag = test_flag self.test_flag = test_flag
# day 模式 date_info 形如 2026-05-12,month 模式形如 2026-03;统一替换 - 为 _ 拼 topic # 用于父 ASIN 详情表 / ASIN 最新详情表的 date_info 字段写入
self.year_month = str(self.date_info).replace("-", "_") self.date_info_month = self.date_info[:7]
# date_info_month 统一月份维度(day 模式 '2026-05-01' → '2026-05',month 模式 '2026-05' 保留) # actual_last_month:环比实际基线月,兼容重跑历史数据——
# 用于父 ASIN 详情表 / ASIN 最新详情表的 date_info 字段写入,避免日级/月级混存 # day模式:从workflow_everyday取最新已产出月份(实时口径,始终对比最新完成的月);
self.date_info_month = self.date_info[:7] # month模式:直接取上一个月(按date_info推算),避免重跑历史月份时基线漂移到"当前最新月"
# date_info_last_month 取上个月(previous 基线);date_info_last_year 取去年同月(yoy 基线) if self.date_type == 'day':
self.date_info_last_month = CommonUtil.get_month_offset(self.date_info_month, -1) _engine_mysql = DBUtil.get_db_engine('mysql', 'us')
self.date_info_last_year = CommonUtil.get_month_offset(self.date_info_month, -12) _sql_latest = (
f"SELECT MAX(report_date) "
f"FROM workflow_everyday "
f"WHERE site_name='{self.site_name}' AND date_type='month' "
f"AND page='流量选品' AND status_val=14 AND is_end='是'"
)
self.actual_last_month = list(DBUtil.engine_exec_sql(_engine_mysql, _sql_latest))[0][0]
elif self.date_type == 'month':
self.actual_last_month = CommonUtil.get_month_offset(self.date_info, -1)
else:
print(f"不支持的date_type: {self.date_type},程序退出")
sys.exit(1)
self.actual_last_year = CommonUtil.get_month_offset(self.actual_last_month, -11)
print(f"环比基线月:{self.actual_last_month},同比基线月:{self.actual_last_year}")
# spark相关参数 # spark相关参数
self.app_name = self.get_app_name() self.app_name = self.get_app_name()
self.spark = SparkUtil.get_stream_spark(app_name=self.app_name) self.spark = SparkUtil.get_stream_spark(app_name=self.app_name)
self.processing_time = 900 if self.site_name == 'us' else 600 self.processing_time = 900 if self.site_name == 'us' else 600
self.repartition_num = 80 self.repartition_num = 80
# kafka相关参数(topic 按 date_type 动态:day → {site}_asin_detail_day_{yyyy_MM_dd},month → {site}_asin_detail_month_{yyyy_MM}) # kafka相关参数(topic 按 date_type 动态:day → {site}_asin_detail_day_{yyyy_MM_dd},month → {site}_asin_detail_month_{yyyy_MM})
self.topic_name = f"{self.site_name}_asin_detail_{self.date_type}_{self.year_month}" self.topic_name = f"{self.site_name}_asin_detail_{self.date_type}_{str(self.date_info).replace('-', '_')}"
self.batch_size = batch_size self.batch_size = batch_size
self.batch_size_history = 20000 self.batch_size_history = 20000
self.check_path = f"/home/big_data_selection/tmp/kafka_checkpoint/{self.topic_name}_{self.consumer_type}_test" if self.test_flag == 'test' else f"/home/big_data_selection/tmp/kafka_checkpoint/{self.topic_name}_{self.consumer_type}" self.check_path = f"/home/big_data_selection/tmp/kafka_checkpoint/{self.topic_name}_{self.consumer_type}_test" if self.test_flag == 'test' else f"/home/big_data_selection/tmp/kafka_checkpoint/{self.topic_name}_{self.consumer_type}"
...@@ -834,25 +847,11 @@ class KafkaFlowAsinDetail(Templates): ...@@ -834,25 +847,11 @@ class KafkaFlowAsinDetail(Templates):
F.col('asin_bought_month').alias(f'{alias_prefix}_asin_bought_month'), F.col('asin_bought_month').alias(f'{alias_prefix}_asin_bought_month'),
).persist(StorageLevel.DISK_ONLY) ).persist(StorageLevel.DISK_ONLY)
# 从MySQL流程记录表获取最新已产出月份,避免查Hive慢 print(f"1a. 读取上个月维度的flow_asin(date_type=month, date_info={self.actual_last_month})")
_engine_mysql = DBUtil.get_db_engine('mysql', 'us') self.df_previous_flow_asin = _load_baseline(self.actual_last_month, 'previous')
_sql_latest = (
f"SELECT MAX(report_date) "
f"FROM workflow_everyday "
f"WHERE site_name='{self.site_name}' AND date_type='month' "
f"AND page='流量选品' AND status_val=14 AND is_end='是'"
)
_result = list(DBUtil.engine_exec_sql(_engine_mysql, _sql_latest))
actual_last_month = (_result[0][0] if _result and _result[0][0]
else self.date_info_last_month)
actual_last_year = CommonUtil.get_month_offset(actual_last_month, -11)
print(f"环比基线月:{actual_last_month}(原始推算:{self.date_info_last_month}),同比基线月:{actual_last_year}")
print(f"1a. 读取上个月维度的flow_asin(date_type=month, date_info={actual_last_month})")
self.df_previous_flow_asin = _load_baseline(actual_last_month, 'previous')
self.df_previous_flow_asin.show(10, truncate=False) self.df_previous_flow_asin.show(10, truncate=False)
print(f"1b. 读取同比去年的flow_asin(date_type=month, date_info={actual_last_year})") print(f"1b. 读取同比去年的flow_asin(date_type=month, date_info={self.actual_last_year})")
self.df_previous_flow_asin_lastyear = _load_baseline(actual_last_year, 'lastyear') self.df_previous_flow_asin_lastyear = _load_baseline(self.actual_last_year, 'lastyear')
self.df_previous_flow_asin_lastyear.show(10, truncate=False) self.df_previous_flow_asin_lastyear.show(10, truncate=False)
print("2. 获取店铺相关信息") print("2. 获取店铺相关信息")
sql = f""" sql = f"""
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment