Commit 9eb36bd2798613e8435c9f03d43a50d8dab14e70
1 parent
789edb14
add logs
Showing
3 changed files
with
100 additions
and
35 deletions
Show diff stats
offline_tasks/scripts/debug_utils.py
| @@ -21,8 +21,9 @@ def setup_debug_logger(script_name, debug=False): | @@ -21,8 +21,9 @@ def setup_debug_logger(script_name, debug=False): | ||
| 21 | """ | 21 | """ |
| 22 | logger = logging.getLogger(script_name) | 22 | logger = logging.getLogger(script_name) |
| 23 | 23 | ||
| 24 | - # 清除已有的handlers | ||
| 25 | - logger.handlers.clear() | 24 | + # 避免重复添加handler |
| 25 | + if logger.handlers: | ||
| 26 | + return logger | ||
| 26 | 27 | ||
| 27 | # 设置日志级别 | 28 | # 设置日志级别 |
| 28 | if debug: | 29 | if debug: |
| @@ -40,20 +41,20 @@ def setup_debug_logger(script_name, debug=False): | @@ -40,20 +41,20 @@ def setup_debug_logger(script_name, debug=False): | ||
| 40 | console_handler.setFormatter(console_format) | 41 | console_handler.setFormatter(console_format) |
| 41 | logger.addHandler(console_handler) | 42 | logger.addHandler(console_handler) |
| 42 | 43 | ||
| 43 | - # 文件输出(如果开启debug) | 44 | + # 文件输出(总是输出到logs目录) |
| 45 | + log_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'logs') | ||
| 46 | + os.makedirs(log_dir, exist_ok=True) | ||
| 47 | + | ||
| 48 | + log_file = os.path.join( | ||
| 49 | + log_dir, | ||
| 50 | + f"{script_name}_{datetime.now().strftime('%Y%m%d')}.log" | ||
| 51 | + ) | ||
| 52 | + file_handler = logging.FileHandler(log_file, encoding='utf-8') | ||
| 53 | + file_handler.setLevel(logging.DEBUG) | ||
| 54 | + file_handler.setFormatter(console_format) | ||
| 55 | + logger.addHandler(file_handler) | ||
| 56 | + | ||
| 44 | if debug: | 57 | if debug: |
| 45 | - log_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'logs', 'debug') | ||
| 46 | - os.makedirs(log_dir, exist_ok=True) | ||
| 47 | - | ||
| 48 | - log_file = os.path.join( | ||
| 49 | - log_dir, | ||
| 50 | - f"{script_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log" | ||
| 51 | - ) | ||
| 52 | - file_handler = logging.FileHandler(log_file, encoding='utf-8') | ||
| 53 | - file_handler.setLevel(logging.DEBUG) | ||
| 54 | - file_handler.setFormatter(console_format) | ||
| 55 | - logger.addHandler(file_handler) | ||
| 56 | - | ||
| 57 | logger.debug(f"Debug log file: {log_file}") | 58 | logger.debug(f"Debug log file: {log_file}") |
| 58 | 59 | ||
| 59 | return logger | 60 | return logger |
offline_tasks/scripts/i2i_item_behavior.py
| @@ -56,6 +56,9 @@ parser.add_argument('--top_n', type=int, default=50, help='每个商品保留的 | @@ -56,6 +56,9 @@ parser.add_argument('--top_n', type=int, default=50, help='每个商品保留的 | ||
| 56 | parser.add_argument('--debug', action='store_true', help='开启debug模式') | 56 | parser.add_argument('--debug', action='store_true', help='开启debug模式') |
| 57 | args = parser.parse_args() | 57 | args = parser.parse_args() |
| 58 | 58 | ||
| 59 | +# 初始化logger | ||
| 60 | +logger = setup_logger() | ||
| 61 | + | ||
| 59 | # 数据库连接配置 | 62 | # 数据库连接配置 |
| 60 | host = 'selectdb-cn-wuf3vsokg05-public.selectdbfe.rds.aliyuncs.com' | 63 | host = 'selectdb-cn-wuf3vsokg05-public.selectdbfe.rds.aliyuncs.com' |
| 61 | port = '9030' | 64 | port = '9030' |
| @@ -84,9 +87,14 @@ ORDER BY | @@ -84,9 +87,14 @@ ORDER BY | ||
| 84 | se.create_time; | 87 | se.create_time; |
| 85 | """ | 88 | """ |
| 86 | 89 | ||
| 90 | +logger.info("="*80) | ||
| 91 | +logger.info("I2I商品行为相似度计算开始") | ||
| 92 | +logger.info("="*80) | ||
| 93 | +logger.info(f"参数配置: lookback_days={args.lookback_days}, top_n={args.top_n}") | ||
| 94 | + | ||
| 87 | if args.debug: | 95 | if args.debug: |
| 88 | - print(f"[DEBUG] 参数配置: lookback_days={args.lookback_days}, top_n={args.top_n}") | ||
| 89 | - print(f"[DEBUG] 开始查询数据库...") | 96 | + logger.debug(f"[DEBUG] 参数配置: lookback_days={args.lookback_days}, top_n={args.top_n}") |
| 97 | + logger.debug(f"[DEBUG] 开始查询数据库...") | ||
| 90 | 98 | ||
| 91 | # 执行 SQL 查询并将结果加载到 pandas DataFrame | 99 | # 执行 SQL 查询并将结果加载到 pandas DataFrame |
| 92 | df = pd.read_sql(sql_query, engine) | 100 | df = pd.read_sql(sql_query, engine) |
| @@ -95,10 +103,14 @@ df = pd.read_sql(sql_query, engine) | @@ -95,10 +103,14 @@ df = pd.read_sql(sql_query, engine) | ||
| 95 | df['item_id'] = df['item_id'].astype(int) | 103 | df['item_id'] = df['item_id'].astype(int) |
| 96 | df['user_id'] = df['user_id'].astype(str) # user_id保持为字符串 | 104 | df['user_id'] = df['user_id'].astype(str) # user_id保持为字符串 |
| 97 | 105 | ||
| 106 | +logger.info(f"数据库查询完成,共 {len(df)} 条记录") | ||
| 107 | +logger.info(f"唯一用户数: {df['user_id'].nunique()}") | ||
| 108 | +logger.info(f"唯一商品数: {df['item_id'].nunique()}") | ||
| 109 | + | ||
| 98 | if args.debug: | 110 | if args.debug: |
| 99 | - print(f"[DEBUG] 查询完成,共 {len(df)} 条记录") | ||
| 100 | - print(f"[DEBUG] 唯一用户数: {df['user_id'].nunique()}") | ||
| 101 | - print(f"[DEBUG] 唯一商品数: {df['item_id'].nunique()}") | 111 | + logger.debug(f"[DEBUG] 查询完成,共 {len(df)} 条记录") |
| 112 | + logger.debug(f"[DEBUG] 唯一用户数: {df['user_id'].nunique()}") | ||
| 113 | + logger.debug(f"[DEBUG] 唯一商品数: {df['item_id'].nunique()}") | ||
| 102 | 114 | ||
| 103 | # 处理点击序列,计算共现关系 | 115 | # 处理点击序列,计算共现关系 |
| 104 | cooccur = defaultdict(lambda: defaultdict(int)) | 116 | cooccur = defaultdict(lambda: defaultdict(int)) |
| @@ -122,8 +134,10 @@ for (user_id, date), group in df.groupby(['user_id', 'date']): | @@ -122,8 +134,10 @@ for (user_id, date), group in df.groupby(['user_id', 'date']): | ||
| 122 | cooccur[item2][item1] += 1 | 134 | cooccur[item2][item1] += 1 |
| 123 | 135 | ||
| 124 | # 计算余弦相似度 | 136 | # 计算余弦相似度 |
| 137 | +logger.info("开始计算商品相似度...") | ||
| 138 | + | ||
| 125 | if args.debug: | 139 | if args.debug: |
| 126 | - print(f"[DEBUG] 开始计算相似度...") | 140 | + logger.debug(f"[DEBUG] 开始计算相似度...") |
| 127 | 141 | ||
| 128 | result = {} | 142 | result = {} |
| 129 | for item1 in cooccur: | 143 | for item1 in cooccur: |
| @@ -138,8 +152,10 @@ for item1 in cooccur: | @@ -138,8 +152,10 @@ for item1 in cooccur: | ||
| 138 | # 只保留top_n个相似商品 | 152 | # 只保留top_n个相似商品 |
| 139 | result[item1] = sim_scores[:args.top_n] | 153 | result[item1] = sim_scores[:args.top_n] |
| 140 | 154 | ||
| 155 | +logger.info(f"相似度计算完成,共 {len(result)} 个商品有相似推荐") | ||
| 156 | + | ||
| 141 | if args.debug: | 157 | if args.debug: |
| 142 | - print(f"[DEBUG] 相似度计算完成,共 {len(result)} 个商品有相似推荐") | 158 | + logger.debug(f"[DEBUG] 相似度计算完成,共 {len(result)} 个商品有相似推荐") |
| 143 | 159 | ||
| 144 | # 创建item_id到name的映射 | 160 | # 创建item_id到name的映射 |
| 145 | item_name_map = dict(zip(df['item_id'], df['item_name'])) | 161 | item_name_map = dict(zip(df['item_id'], df['item_name'])) |
| @@ -151,8 +167,10 @@ os.makedirs(output_dir, exist_ok=True) | @@ -151,8 +167,10 @@ os.makedirs(output_dir, exist_ok=True) | ||
| 151 | output_file = os.path.join(output_dir, f'i2i_item_behavior_{date_str}.txt') | 167 | output_file = os.path.join(output_dir, f'i2i_item_behavior_{date_str}.txt') |
| 152 | 168 | ||
| 153 | # 输出相似商品到文件 | 169 | # 输出相似商品到文件 |
| 170 | +logger.info(f"开始写入输出文件: {output_file}") | ||
| 171 | + | ||
| 154 | if args.debug: | 172 | if args.debug: |
| 155 | - print(f"[DEBUG] 开始写入文件: {output_file}") | 173 | + logger.debug(f"[DEBUG] 开始写入文件: {output_file}") |
| 156 | 174 | ||
| 157 | with open(output_file, 'w', encoding='utf-8') as f: | 175 | with open(output_file, 'w', encoding='utf-8') as f: |
| 158 | for item_id, sims in sorted(result.items()): | 176 | for item_id, sims in sorted(result.items()): |
| @@ -161,16 +179,32 @@ with open(output_file, 'w', encoding='utf-8') as f: | @@ -161,16 +179,32 @@ with open(output_file, 'w', encoding='utf-8') as f: | ||
| 161 | sim_str = ','.join([f'{sim_id}:{score:.4f}' for sim_id, score in sims]) | 179 | sim_str = ','.join([f'{sim_id}:{score:.4f}' for sim_id, score in sims]) |
| 162 | f.write(f'{item_id}\t{item_name}\t{sim_str}\n') | 180 | f.write(f'{item_id}\t{item_name}\t{sim_str}\n') |
| 163 | 181 | ||
| 164 | -print(f"✓ Item相似度计算完成") | ||
| 165 | -print(f" - 输出文件: {output_file}") | ||
| 166 | -print(f" - 商品数: {len(result)}") | ||
| 167 | -if result: | ||
| 168 | - avg_sims = sum(len(sims) for sims in result.values()) / len(result) | ||
| 169 | - print(f" - 平均相似商品数: {avg_sims:.1f}") | 182 | +logger.info(f"输出文件写入完成: {output_file}") |
| 183 | + | ||
| 184 | +# 统计信息 | ||
| 185 | +total_similarity_pairs = sum(len(sims) for sims in result.values()) | ||
| 186 | +avg_sims = total_similarity_pairs / len(result) if result else 0 | ||
| 187 | + | ||
| 188 | +logger.info("="*80) | ||
| 189 | +logger.info("I2I商品行为相似度计算 - 关键统计信息") | ||
| 190 | +logger.info("="*80) | ||
| 191 | +logger.info(f"📊 数据概览:") | ||
| 192 | +logger.info(f" - 总行为记录数: {len(df):,}") | ||
| 193 | +logger.info(f" - 唯一用户数: {df['user_id'].nunique():,}") | ||
| 194 | +logger.info(f" - 唯一商品数: {df['item_id'].nunique():,}") | ||
| 195 | +logger.info(f" - 有相似度的商品数: {len(result):,}") | ||
| 196 | +logger.info(f" - 总相似度对数量: {total_similarity_pairs:,}") | ||
| 197 | +logger.info(f" - 平均每商品相似数: {avg_sims:.1f}") | ||
| 198 | + | ||
| 199 | +logger.info(f"📁 输出文件:") | ||
| 200 | +logger.info(f" - 输出文件: {output_file}") | ||
| 201 | + | ||
| 202 | +logger.info(f"✅ I2I商品行为相似度计算完成") | ||
| 203 | +logger.info("="*80) | ||
| 170 | 204 | ||
| 171 | # 如果启用debug模式,保存可读格式 | 205 | # 如果启用debug模式,保存可读格式 |
| 172 | if args.debug and result: | 206 | if args.debug and result: |
| 173 | - print("[DEBUG] 保存可读格式文件...") | 207 | + logger.debug("[DEBUG] 保存可读格式文件...") |
| 174 | 208 | ||
| 175 | # 准备name_mappings | 209 | # 准备name_mappings |
| 176 | name_mappings = { | 210 | name_mappings = { |
offline_tasks/scripts/load_index_to_redis.py
| @@ -10,11 +10,41 @@ import sys | @@ -10,11 +10,41 @@ import sys | ||
| 10 | from datetime import datetime | 10 | from datetime import datetime |
| 11 | from config.offline_config import REDIS_CONFIG, OUTPUT_DIR | 11 | from config.offline_config import REDIS_CONFIG, OUTPUT_DIR |
| 12 | 12 | ||
| 13 | -logging.basicConfig( | ||
| 14 | - level=logging.INFO, | ||
| 15 | - format='%(asctime)s - %(levelname)s - %(message)s' | ||
| 16 | -) | ||
| 17 | -logger = logging.getLogger(__name__) | 13 | +def setup_logger(): |
| 14 | + """设置logger配置""" | ||
| 15 | + # 创建logs目录 | ||
| 16 | + logs_dir = 'logs' | ||
| 17 | + os.makedirs(logs_dir, exist_ok=True) | ||
| 18 | + | ||
| 19 | + # 创建logger | ||
| 20 | + logger = logging.getLogger('load_index_to_redis') | ||
| 21 | + logger.setLevel(logging.INFO) | ||
| 22 | + | ||
| 23 | + # 避免重复添加handler | ||
| 24 | + if logger.handlers: | ||
| 25 | + return logger | ||
| 26 | + | ||
| 27 | + # 创建文件handler | ||
| 28 | + log_file = os.path.join(logs_dir, f'load_index_to_redis_{datetime.now().strftime("%Y%m%d")}.log') | ||
| 29 | + file_handler = logging.FileHandler(log_file, encoding='utf-8') | ||
| 30 | + file_handler.setLevel(logging.INFO) | ||
| 31 | + | ||
| 32 | + # 创建控制台handler | ||
| 33 | + console_handler = logging.StreamHandler() | ||
| 34 | + console_handler.setLevel(logging.INFO) | ||
| 35 | + | ||
| 36 | + # 创建formatter | ||
| 37 | + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') | ||
| 38 | + file_handler.setFormatter(formatter) | ||
| 39 | + console_handler.setFormatter(formatter) | ||
| 40 | + | ||
| 41 | + # 添加handler到logger | ||
| 42 | + logger.addHandler(file_handler) | ||
| 43 | + logger.addHandler(console_handler) | ||
| 44 | + | ||
| 45 | + return logger | ||
| 46 | + | ||
| 47 | +logger = setup_logger() | ||
| 18 | 48 | ||
| 19 | 49 | ||
| 20 | def load_index_file(file_path, redis_client, key_prefix, expire_seconds=None): | 50 | def load_index_file(file_path, redis_client, key_prefix, expire_seconds=None): |