diff --git a/offline_tasks/scripts/debug_utils.py b/offline_tasks/scripts/debug_utils.py index fc7019b..c6968ae 100644 --- a/offline_tasks/scripts/debug_utils.py +++ b/offline_tasks/scripts/debug_utils.py @@ -21,8 +21,9 @@ def setup_debug_logger(script_name, debug=False): """ logger = logging.getLogger(script_name) - # 清除已有的handlers - logger.handlers.clear() + # 避免重复添加handler + if logger.handlers: + return logger # 设置日志级别 if debug: @@ -40,20 +41,20 @@ def setup_debug_logger(script_name, debug=False): console_handler.setFormatter(console_format) logger.addHandler(console_handler) - # 文件输出(如果开启debug) + # 文件输出(总是输出到logs目录) + log_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'logs') + os.makedirs(log_dir, exist_ok=True) + + log_file = os.path.join( + log_dir, + f"{script_name}_{datetime.now().strftime('%Y%m%d')}.log" + ) + file_handler = logging.FileHandler(log_file, encoding='utf-8') + file_handler.setLevel(logging.DEBUG) + file_handler.setFormatter(console_format) + logger.addHandler(file_handler) + if debug: - log_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'logs', 'debug') - os.makedirs(log_dir, exist_ok=True) - - log_file = os.path.join( - log_dir, - f"{script_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log" - ) - file_handler = logging.FileHandler(log_file, encoding='utf-8') - file_handler.setLevel(logging.DEBUG) - file_handler.setFormatter(console_format) - logger.addHandler(file_handler) - logger.debug(f"Debug log file: {log_file}") return logger diff --git a/offline_tasks/scripts/i2i_item_behavior.py b/offline_tasks/scripts/i2i_item_behavior.py index f1b0b2c..7a0af59 100644 --- a/offline_tasks/scripts/i2i_item_behavior.py +++ b/offline_tasks/scripts/i2i_item_behavior.py @@ -56,6 +56,9 @@ parser.add_argument('--top_n', type=int, default=50, help='每个商品保留的 parser.add_argument('--debug', action='store_true', help='开启debug模式') args = parser.parse_args() +# 初始化logger +logger = setup_logger() + # 数据库连接配置 host = 'selectdb-cn-wuf3vsokg05-public.selectdbfe.rds.aliyuncs.com' port = '9030' @@ -84,9 +87,14 @@ ORDER BY se.create_time; """ +logger.info("="*80) +logger.info("I2I商品行为相似度计算开始") +logger.info("="*80) +logger.info(f"参数配置: lookback_days={args.lookback_days}, top_n={args.top_n}") + if args.debug: - print(f"[DEBUG] 参数配置: lookback_days={args.lookback_days}, top_n={args.top_n}") - print(f"[DEBUG] 开始查询数据库...") + logger.debug(f"[DEBUG] 参数配置: lookback_days={args.lookback_days}, top_n={args.top_n}") + logger.debug(f"[DEBUG] 开始查询数据库...") # 执行 SQL 查询并将结果加载到 pandas DataFrame df = pd.read_sql(sql_query, engine) @@ -95,10 +103,14 @@ df = pd.read_sql(sql_query, engine) df['item_id'] = df['item_id'].astype(int) df['user_id'] = df['user_id'].astype(str) # user_id保持为字符串 +logger.info(f"数据库查询完成,共 {len(df)} 条记录") +logger.info(f"唯一用户数: {df['user_id'].nunique()}") +logger.info(f"唯一商品数: {df['item_id'].nunique()}") + if args.debug: - print(f"[DEBUG] 查询完成,共 {len(df)} 条记录") - print(f"[DEBUG] 唯一用户数: {df['user_id'].nunique()}") - print(f"[DEBUG] 唯一商品数: {df['item_id'].nunique()}") + logger.debug(f"[DEBUG] 查询完成,共 {len(df)} 条记录") + logger.debug(f"[DEBUG] 唯一用户数: {df['user_id'].nunique()}") + logger.debug(f"[DEBUG] 唯一商品数: {df['item_id'].nunique()}") # 处理点击序列,计算共现关系 cooccur = defaultdict(lambda: defaultdict(int)) @@ -122,8 +134,10 @@ for (user_id, date), group in df.groupby(['user_id', 'date']): cooccur[item2][item1] += 1 # 计算余弦相似度 +logger.info("开始计算商品相似度...") + if args.debug: - print(f"[DEBUG] 开始计算相似度...") + logger.debug(f"[DEBUG] 开始计算相似度...") result = {} for item1 in cooccur: @@ -138,8 +152,10 @@ for item1 in cooccur: # 只保留top_n个相似商品 result[item1] = sim_scores[:args.top_n] +logger.info(f"相似度计算完成,共 {len(result)} 个商品有相似推荐") + if args.debug: - print(f"[DEBUG] 相似度计算完成,共 {len(result)} 个商品有相似推荐") + logger.debug(f"[DEBUG] 相似度计算完成,共 {len(result)} 个商品有相似推荐") # 创建item_id到name的映射 item_name_map = dict(zip(df['item_id'], df['item_name'])) @@ -151,8 +167,10 @@ os.makedirs(output_dir, exist_ok=True) output_file = os.path.join(output_dir, f'i2i_item_behavior_{date_str}.txt') # 输出相似商品到文件 +logger.info(f"开始写入输出文件: {output_file}") + if args.debug: - print(f"[DEBUG] 开始写入文件: {output_file}") + logger.debug(f"[DEBUG] 开始写入文件: {output_file}") with open(output_file, 'w', encoding='utf-8') as f: for item_id, sims in sorted(result.items()): @@ -161,16 +179,32 @@ with open(output_file, 'w', encoding='utf-8') as f: sim_str = ','.join([f'{sim_id}:{score:.4f}' for sim_id, score in sims]) f.write(f'{item_id}\t{item_name}\t{sim_str}\n') -print(f"✓ Item相似度计算完成") -print(f" - 输出文件: {output_file}") -print(f" - 商品数: {len(result)}") -if result: - avg_sims = sum(len(sims) for sims in result.values()) / len(result) - print(f" - 平均相似商品数: {avg_sims:.1f}") +logger.info(f"输出文件写入完成: {output_file}") + +# 统计信息 +total_similarity_pairs = sum(len(sims) for sims in result.values()) +avg_sims = total_similarity_pairs / len(result) if result else 0 + +logger.info("="*80) +logger.info("I2I商品行为相似度计算 - 关键统计信息") +logger.info("="*80) +logger.info(f"📊 数据概览:") +logger.info(f" - 总行为记录数: {len(df):,}") +logger.info(f" - 唯一用户数: {df['user_id'].nunique():,}") +logger.info(f" - 唯一商品数: {df['item_id'].nunique():,}") +logger.info(f" - 有相似度的商品数: {len(result):,}") +logger.info(f" - 总相似度对数量: {total_similarity_pairs:,}") +logger.info(f" - 平均每商品相似数: {avg_sims:.1f}") + +logger.info(f"📁 输出文件:") +logger.info(f" - 输出文件: {output_file}") + +logger.info(f"✅ I2I商品行为相似度计算完成") +logger.info("="*80) # 如果启用debug模式,保存可读格式 if args.debug and result: - print("[DEBUG] 保存可读格式文件...") + logger.debug("[DEBUG] 保存可读格式文件...") # 准备name_mappings name_mappings = { diff --git a/offline_tasks/scripts/load_index_to_redis.py b/offline_tasks/scripts/load_index_to_redis.py index ed26f6d..9b46e05 100644 --- a/offline_tasks/scripts/load_index_to_redis.py +++ b/offline_tasks/scripts/load_index_to_redis.py @@ -10,11 +10,41 @@ import sys from datetime import datetime from config.offline_config import REDIS_CONFIG, OUTPUT_DIR -logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(levelname)s - %(message)s' -) -logger = logging.getLogger(__name__) +def setup_logger(): + """设置logger配置""" + # 创建logs目录 + logs_dir = 'logs' + os.makedirs(logs_dir, exist_ok=True) + + # 创建logger + logger = logging.getLogger('load_index_to_redis') + logger.setLevel(logging.INFO) + + # 避免重复添加handler + if logger.handlers: + return logger + + # 创建文件handler + log_file = os.path.join(logs_dir, f'load_index_to_redis_{datetime.now().strftime("%Y%m%d")}.log') + file_handler = logging.FileHandler(log_file, encoding='utf-8') + file_handler.setLevel(logging.INFO) + + # 创建控制台handler + console_handler = logging.StreamHandler() + console_handler.setLevel(logging.INFO) + + # 创建formatter + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + file_handler.setFormatter(formatter) + console_handler.setFormatter(formatter) + + # 添加handler到logger + logger.addHandler(file_handler) + logger.addHandler(console_handler) + + return logger + +logger = setup_logger() def load_index_file(file_path, redis_client, key_prefix, expire_seconds=None): -- libgit2 0.21.2