From 7e37f9e2a6122504f55e8e19f1ea43a5dda9b726 Mon Sep 17 00:00:00 2001 From: tangwang Date: Sat, 18 Oct 2025 21:08:35 +0800 Subject: [PATCH] add cpp swing for mem optimize --- offline_tasks/README.md | 40 +++++++++++++++++++++++++--------------- offline_tasks/collaboration/run.sh | 4 ++-- offline_tasks/doc/README.md | 2 ++ offline_tasks/doc/Redis数据规范.md | 4 ++-- offline_tasks/doc/离线索引数据规范.md | 6 +++--- offline_tasks/doc/系统改进总结-20241017.md | 47 ++++++++++++++++++++++++++++++----------------- offline_tasks/doc/项目重构说明-20241017.md | 397 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ offline_tasks/run.sh | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------- offline_tasks/run_all.py | 61 +------------------------------------------------------------ 9 files changed, 637 insertions(+), 140 deletions(-) create mode 100644 offline_tasks/doc/项目重构说明-20241017.md diff --git a/offline_tasks/README.md b/offline_tasks/README.md index 7103f62..e8f4254 100644 --- a/offline_tasks/README.md +++ b/offline_tasks/README.md @@ -4,32 +4,36 @@ ## 🚀 快速开始 -### 运行所有任务(推荐) +### 运行所有任务 ```bash cd /home/tw/recommendation/offline_tasks -# 运行全部离线任务(包括C++ Swing) -python3 run_all.py +# ⭐ 推荐:使用 run.sh(完整流程,包含Redis加载) +bash run.sh -# 开启debug模式(详细日志 + 可读文件) +# 备用:使用 run_all.py(简化版,不含C++ Swing和Redis) python3 run_all.py --debug ``` +**说明**: +- `run.sh`: 主执行脚本,包含完整流程、内存监控、自动Redis加载 +- `run_all.py`: Python简化版本,只包含Python算法任务 + ### 任务执行顺序 ``` 前置任务: -1. fetch_item_attributes.py → 获取商品属性映射 -2. generate_session.py → 生成用户行为session -3. C++ Swing算法 → 高性能i2i相似度计算 +1. fetch_item_attributes.py → 获取商品属性映射 +2. generate_session.py → 生成用户行为session +3. collaboration/run.sh → C++ Swing算法(高性能) 核心算法任务: -4. Python Swing算法 → 支持日期维度的i2i -5. Session W2V → 基于序列的embedding -6. DeepWalk → 图结构embedding -7. 内容相似度 → 基于ES向量 -8. 兴趣聚合 → 多维度商品聚合 +4. i2i_swing.py → Python Swing(支持日期维度) +5. i2i_session_w2v.py → Session W2V +6. i2i_deepwalk.py → DeepWalk +7. i2i_content_similar.py → 内容相似度 +8. interest_aggregation.py → 兴趣聚合 ``` ## 📚 文档 @@ -94,7 +98,7 @@ python3 scripts/generate_session.py --lookback_days 730 ### 3. C++ Swing ```bash -cd ../collaboration +cd collaboration bash run.sh ``` @@ -134,6 +138,11 @@ offline_tasks/ │ ├── interest_aggregation.py │ ├── add_names_to_swing.py │ └── debug_utils.py +├── collaboration/ # C++ Swing算法 +│ ├── src/ +│ ├── bin/ +│ ├── run.sh +│ └── output/ ├── config/ # 配置文件 │ └── offline_config.py ├── doc/ # 文档中心 @@ -146,7 +155,8 @@ offline_tasks/ │ ├── session.txt.* │ └── *.txt ├── logs/ # 日志目录 -├── run_all.py # 统一入口 +├── run.sh # 主执行脚本(推荐) +├── run_all.py # Python版本(简化) └── README.md # 本文件 ``` @@ -185,7 +195,7 @@ python3 scripts/generate_session.py **3. C++ Swing编译失败** ```bash -cd ../collaboration +cd collaboration make clean make ``` diff --git a/offline_tasks/collaboration/run.sh b/offline_tasks/collaboration/run.sh index 201eff1..3b37338 100644 --- a/offline_tasks/collaboration/run.sh +++ b/offline_tasks/collaboration/run.sh @@ -7,7 +7,7 @@ source ~/.bash_profile # 数据路径配置 # 修改这个路径指向实际的session文件位置 -SESSION_DATA_DIR="../offline_tasks/output" +SESSION_DATA_DIR="../output" # Swing算法参数 ALPHA=0.7 # Swing算法的alpha参数 @@ -95,7 +95,7 @@ if [[ $? -eq 0 ]]; then # 生成可读的debug文件(添加商品名称) echo "生成可读的debug文件..." - DEBUG_SCRIPT="../offline_tasks/scripts/add_names_to_swing.py" + DEBUG_SCRIPT="../scripts/add_names_to_swing.py" if [[ -f ${DEBUG_SCRIPT} ]]; then ${PYTHON_CMD} ${DEBUG_SCRIPT} output/swing_similar.txt output/swing_similar_readable.txt --debug diff --git a/offline_tasks/doc/README.md b/offline_tasks/doc/README.md index 84bb981..cf64c37 100644 --- a/offline_tasks/doc/README.md +++ b/offline_tasks/doc/README.md @@ -30,6 +30,8 @@ ### 实现总结 - **[Swing实现总结.md](./Swing实现总结.md)** - C++ Swing集成实现的完整说明 +- **[系统改进总结-20241017.md](./系统改进总结-20241017.md)** - 2024-10-17系统改进汇总 +- **[项目重构说明-20241017.md](./项目重构说明-20241017.md)** - 目录结构和执行脚本重构详解 🆕 ### 维护文档 diff --git a/offline_tasks/doc/Redis数据规范.md b/offline_tasks/doc/Redis数据规范.md index 46c1211..9eea486 100644 --- a/offline_tasks/doc/Redis数据规范.md +++ b/offline_tasks/doc/Redis数据规范.md @@ -20,7 +20,7 @@ | 模块名称 | 源数据地址 | 格式描述 | RedisKey模板 | RedisValue格式 | TTL | |---------|-----------|---------|-------------|---------------|-----| -| **i2i_swing_cpp** | `collaboration/output/swing_similar.txt` | `item_id\tsimilar_id1:score1,...` | `item:similar:swing_cpp:{item_id}` | `[[similar_id1,score1],[similar_id2,score2],...]` | 7天 | +| **i2i_swing_cpp** | `offline_tasks/collaboration/output/swing_similar.txt` | `item_id\tsimilar_id1:score1,...` | `item:similar:swing_cpp:{item_id}` | `[[similar_id1,score1],[similar_id2,score2],...]` | 7天 | | **i2i_swing** | `output/i2i_swing_YYYYMMDD.txt` | `item_id\titem_name\tsimilar_id1:score1,...` | `item:similar:swing:{item_id}` | `[[similar_id1,score1],[similar_id2,score2],...]` | 7天 | | **i2i_session_w2v** | `output/i2i_session_w2v_YYYYMMDD.txt` | `item_id\titem_name\tsimilar_id1:score1,...` | `item:similar:w2v:{item_id}` | `[[similar_id1,score1],[similar_id2,score2],...]` | 7天 | | **i2i_deepwalk** | `output/i2i_deepwalk_YYYYMMDD.txt` | `item_id\titem_name\tsimilar_id1:score1,...` | `item:similar:deepwalk:{item_id}` | `[[similar_id1,score1],[similar_id2,score2],...]` | 7天 | @@ -305,7 +305,7 @@ python3 scripts/load_index_to_redis.py --load-i2i --redis-host localhost # 只加载C++ Swing索引 python3 scripts/load_index_to_redis.py \ - --file ../collaboration/output/swing_similar.txt \ + --file collaboration/output/swing_similar.txt \ --algorithm swing_cpp \ --redis-host localhost diff --git a/offline_tasks/doc/离线索引数据规范.md b/offline_tasks/doc/离线索引数据规范.md index f81d270..b1f8ef8 100644 --- a/offline_tasks/doc/离线索引数据规范.md +++ b/offline_tasks/doc/离线索引数据规范.md @@ -4,7 +4,7 @@ | 模块名称 | 任务命令 | 调度频次 | 输出数据 | 格式和示例 | |---------|---------|---------|---------|-----------| -| **i2i_swing_cpp** | `cd collaboration && bash run.sh` | 每天 | `collaboration/output/swing_similar.txt` | `item_id \t similar_id1:score1,similar_id2:score2,...` | +| **i2i_swing_cpp** | `cd offline_tasks/collaboration && bash run.sh` | 每天 | `offline_tasks/collaboration/output/swing_similar.txt` | `item_id \t similar_id1:score1,similar_id2:score2,...` | | **i2i_swing** | `python3 scripts/i2i_swing.py` | 每天 | `output/i2i_swing_YYYYMMDD.txt` | `item_id \t item_name \t similar_id1:score1,similar_id2:score2,...` | | **i2i_session_w2v** | `python3 scripts/i2i_session_w2v.py` | 每天 | `output/i2i_session_w2v_YYYYMMDD.txt` | `item_id \t item_name \t similar_id1:score1,similar_id2:score2,...` | | **i2i_deepwalk** | `python3 scripts/i2i_deepwalk.py` | 每天 | `output/i2i_deepwalk_YYYYMMDD.txt` | `item_id \t item_name \t similar_id1:score1,similar_id2:score2,...` | @@ -40,8 +40,8 @@ item_id \t similar_id1:score1,similar_id2:score2,... - ⚡ **高性能**: C++实现,速度比Python快10-100倍 - 📊 **大规模**: 适合处理10万+商品的相似度计算 - 🔢 **原始分数**: 输出Swing算法原始分数(未归一化) -- 📁 **文件位置**: `collaboration/output/swing_similar.txt` -- 📝 **可读版本**: `collaboration/output/swing_similar_readable.txt` (包含商品名称) +- 📁 **文件位置**: `offline_tasks/collaboration/output/swing_similar.txt` +- 📝 **可读版本**: `offline_tasks/collaboration/output/swing_similar_readable.txt` (包含商品名称) #### 1.2 Python算法(标准版本) diff --git a/offline_tasks/doc/系统改进总结-20241017.md b/offline_tasks/doc/系统改进总结-20241017.md index 9e20b1d..b21173b 100644 --- a/offline_tasks/doc/系统改进总结-20241017.md +++ b/offline_tasks/doc/系统改进总结-20241017.md @@ -247,25 +247,31 @@ offline_tasks/doc/ cd /home/tw/recommendation/offline_tasks # 方式1: 运行全部任务(推荐) +bash run.sh + +# 方式2: 使用Python版本(简化版) python3 run_all.py --debug -# 方式2: 分步运行 +# 方式3: 分步运行 # 步骤1: 获取商品属性 python3 scripts/fetch_item_attributes.py # 步骤2: 生成session文件 python3 scripts/generate_session.py --lookback_days 730 -# 步骤3: 运行Swing算法(启用日期维度) +# 步骤3: 运行C++ Swing +cd collaboration && bash run.sh && cd .. + +# 步骤4: 运行Python Swing(启用日期维度) python3 scripts/i2i_swing.py --lookback_days 730 --use_daily_session --debug ``` ### C++ Swing算法 ```bash -# C++ Swing现已集成到run_all.py,会自动在session生成后执行 +# C++ Swing现已集成到run.sh,会自动执行 # 如需单独运行: -cd /home/tw/recommendation/collaboration +cd /home/tw/recommendation/offline_tasks/collaboration bash run.sh # 查看结果 @@ -301,6 +307,11 @@ recommendation/ │ │ ├── add_names_to_swing.py # 修改:使用本地映射 │ │ ├── i2i_swing.py # 修改:支持日期维度 │ │ └── debug_utils.py # 修改:添加加载函数 +│ ├── collaboration/ # 移动:C++ Swing目录 +│ │ ├── src/ +│ │ ├── bin/ +│ │ ├── run.sh # 修改:路径更新 +│ │ └── output/ │ ├── doc/ # 新增:文档中心 │ │ ├── README.md │ │ ├── 快速开始.md @@ -310,12 +321,9 @@ recommendation/ │ │ ├── item_attributes_mappings.json # 新增:映射文件 │ │ ├── item_attributes_stats.txt # 新增:统计信息 │ │ └── session.txt.YYYYMMDD # session文件 -│ ├── run_all.py # 修改:添加前置任务 +│ ├── run.sh # 新增:主执行脚本 +│ ├── run_all.py # 修改:简化版本 │ └── README.md -└── collaboration/ - ├── run.sh # 已修改:适配session - ├── Swing快速开始.md # 重命名 - └── ... ``` --- @@ -324,39 +332,44 @@ recommendation/ ### 改进内容 -**之前**: C++ Swing需要手动切换目录运行 +**之前**: C++ Swing在外层目录,需要手动切换 ```bash cd /home/tw/recommendation/collaboration bash run.sh ``` -**现在**: 已集成到`run_all.py`,自动执行 +**现在**: 已移入offline_tasks,集成到`run.sh`自动执行 ### 执行流程 ``` -run_all.py: +run.sh: 1. fetch_item_attributes.py 2. generate_session.py ← 生成session.txt.YYYYMMDD.cpp -3. run_cpp_swing() ← 自动调用 collaboration/run.sh +3. collaboration/run.sh ← 直接调用C++ Swing ├─ 编译C++程序 ├─ 读取session文件 ├─ 运行Swing算法 ├─ 合并多线程结果 └─ 生成可读版本(自动添加商品名) -4. 后续Python任务... +4. i2i_swing.py ← Python Swing +5. i2i_session_w2v.py ← Session W2V +6. i2i_deepwalk.py ← DeepWalk +7. i2i_content_similar.py ← 内容相似度 +8. interest_aggregation.py ← 兴趣聚合 +9. load_index_to_redis.py ← 加载到Redis ``` ### 输出结果 C++ Swing执行后,结果保存在: ``` -collaboration/output_YYYYMMDD/ +offline_tasks/collaboration/output_YYYYMMDD/ ├── sim_matrx.* # 多线程输出 ├── swing_similar.txt # 合并结果(ID格式) └── swing_similar_readable.txt # 可读版本(ID:名称格式) -collaboration/output -> output_YYYYMMDD # 软链接 +offline_tasks/collaboration/output -> output_YYYYMMDD # 软链接 ``` ### 优势 @@ -371,7 +384,7 @@ collaboration/output -> output_YYYYMMDD # 软链接 如需单独运行C++ Swing(不执行其他任务): ```bash -cd /home/tw/recommendation/collaboration +cd /home/tw/recommendation/offline_tasks/collaboration bash run.sh ``` diff --git a/offline_tasks/doc/项目重构说明-20241017.md b/offline_tasks/doc/项目重构说明-20241017.md new file mode 100644 index 0000000..88af7ce --- /dev/null +++ b/offline_tasks/doc/项目重构说明-20241017.md @@ -0,0 +1,397 @@ +# 项目重构说明 - 2024-10-17 + +## ✅ 完成的重构 + +### 1. 目录结构调整 + +**改动**: 将`collaboration`目录移入`offline_tasks` + +**之前**: +``` +recommendation/ +├── offline_tasks/ +│ ├── scripts/ +│ └── ... +└── collaboration/ # 外层目录 + ├── src/ + └── run.sh +``` + +**之后**: +``` +recommendation/ +└── offline_tasks/ + ├── scripts/ + ├── collaboration/ # 移入内部 + │ ├── src/ + │ └── run.sh + └── ... +``` + +**优势**: +- ✅ 统一目录结构,所有离线任务在同一目录 +- ✅ 简化路径配置 +- ✅ 便于统一管理和部署 + +--- + +### 2. 执行脚本简化 + +**改动**: 主执行脚本从`run_all.py`改为`run.sh`,直接调用各个脚本 + +**之前的流程**: +```python +# run_all.py (Python实现) +run_script('fetch_item_attributes.py') +run_script('generate_session.py') +run_cpp_swing() # 调用collaboration/run.sh +run_script('i2i_swing.py') +# ... +``` + +**现在的流程**: +```bash +# run.sh (Shell实现) +python3 scripts/fetch_item_attributes.py +python3 scripts/generate_session.py +cd collaboration && bash run.sh && cd .. +python3 scripts/i2i_swing.py +# ... +``` + +**优势**: +- ✅ 代码更简洁,减少抽象层 +- ✅ 直接调用,易于理解和调试 +- ✅ 内存监控、错误处理更灵活 +- ✅ 配置参数集中在顶部,便于修改 + +--- + +### 3. 路径更新 + +所有相关路径已更新: + +**collaboration/run.sh**: +- `SESSION_DATA_DIR="../offline_tasks/output"` → `"../output"` +- `DEBUG_SCRIPT="../offline_tasks/scripts/..."` → `"../scripts/..."` + +**文档更新**: +- ✅ `README.md` +- ✅ `doc/离线索引数据规范.md` +- ✅ `doc/Redis数据规范.md` +- ✅ `doc/系统改进总结-20241017.md` + +--- + +## 📋 新的项目结构 + +``` +offline_tasks/ +├── scripts/ # Python脚本 +│ ├── fetch_item_attributes.py # 前置:获取商品属性 +│ ├── generate_session.py # 前置:生成session +│ ├── i2i_swing.py # Python Swing +│ ├── i2i_session_w2v.py # Session W2V +│ ├── i2i_deepwalk.py # DeepWalk +│ ├── i2i_content_similar.py # 内容相似度 +│ ├── interest_aggregation.py # 兴趣聚合 +│ ├── load_index_to_redis.py # 加载到Redis +│ ├── add_names_to_swing.py # 添加商品名 +│ └── debug_utils.py # Debug工具 +├── collaboration/ # C++ Swing算法 +│ ├── src/ +│ │ ├── swing.cc # Swing实现 +│ │ ├── swing_symmetric.cc # 对称Swing +│ │ ├── icf_simple.cc # 简单协同 +│ │ └── ucf.py # 用户协同 +│ ├── bin/ # 编译后的二进制 +│ ├── include/ # 头文件 +│ ├── utils/ # 工具函数 +│ ├── run.sh # C++ Swing执行脚本 +│ ├── Makefile # 编译配置 +│ └── output/ # 输出目录 +├── config/ +│ └── offline_config.py # 配置文件 +├── doc/ # 文档中心 +│ ├── README.md +│ ├── 快速开始.md +│ ├── Swing算法使用指南.md +│ ├── 离线索引数据规范.md +│ ├── Redis数据规范.md +│ └── ... +├── output/ # 输出文件 +│ ├── item_attributes_mappings.json +│ ├── session.txt.* +│ └── *.txt +├── logs/ # 日志文件 +├── run.sh # ⭐ 主执行脚本(推荐) +├── run_all.py # Python版本(保留但简化) +└── README.md +``` + +--- + +## 🚀 使用方式 + +### 主要方式:run.sh(推荐) + +```bash +cd /home/tw/recommendation/offline_tasks + +# 直接运行(使用默认配置) +bash run.sh + +# 修改配置后运行 +# 编辑 run.sh 顶部的配置区域 +vim run.sh + +# 查看帮助 +cat run.sh | head -40 # 查看配置说明 +``` + +**run.sh配置项**: +```bash +# 算法参数 +LOOKBACK_DAYS=730 +TOP_N=50 +DEBUG_MODE="--debug" # 留空则不开启debug + +# Redis配置 +REDIS_HOST="localhost" +REDIS_PORT=6379 + +# 内存监控阈值 +MEM_WARN_THRESHOLD=25 # GB +MEM_KILL_THRESHOLD=35 # GB +``` + +### 备用方式:run_all.py(简化版) + +```bash +cd /home/tw/recommendation/offline_tasks + +# 运行(不包括C++ Swing和Redis加载) +python3 run_all.py --debug +``` + +**注意**: `run_all.py`已简化,只包含: +- 前置任务(商品属性、session) +- Python算法任务(Swing、W2V、DeepWalk等) +- 不包括C++ Swing和Redis加载 + +--- + +## 📊 执行流程对比 + +### run.sh(完整流程) + +``` +1. 环境准备 + ├─ 清理旧进程 + └─ 创建必要目录 + +2. 前置任务 + ├─ fetch_item_attributes.py → 商品属性映射 + ├─ generate_session.py → 用户session + └─ collaboration/run.sh → C++ Swing (高性能) + +3. i2i算法任务 + ├─ i2i_swing.py → Python Swing (日期维度) + ├─ i2i_session_w2v.py → Session W2V + ├─ i2i_deepwalk.py → DeepWalk + └─ i2i_content_similar.py → 内容相似度 + +4. 兴趣聚合 + └─ interest_aggregation.py → 多维度聚合 + +5. 加载Redis + └─ load_index_to_redis.py → 导入Redis + +6. 完成 + └─ 输出结果文件列表 +``` + +### run_all.py(简化流程) + +``` +1. 前置任务 + ├─ fetch_item_attributes.py + └─ generate_session.py + +2. i2i算法任务 + ├─ i2i_swing.py + ├─ i2i_session_w2v.py + ├─ i2i_deepwalk.py + └─ i2i_content_similar.py + +3. 兴趣聚合 + └─ interest_aggregation.py +``` + +--- + +## 💡 关键改进 + +### 1. 代码简化 + +**删除的冗余代码**: +- `run_all.py`中的`run_cpp_swing()`函数(45行) +- 复杂的子进程调用和错误处理 + +**简化效果**: +- run.sh: 直接调用,清晰明了 +- run_all.py: 从270行简化到211行 + +### 2. 灵活性提升 + +**run.sh的优势**: +```bash +# 内存监控(自动) +check_memory $pid "$task_name" & + +# 任务函数(统一) +run_task "任务名" "python3 scripts/xxx.py" + +# 配置集中(顶部) +LOOKBACK_DAYS=730 +DEBUG_MODE="--debug" +``` + +### 3. 错误处理 + +**之前**: +- Python捕获异常,日志分散 +- 失败后需要手动排查 + +**现在**: +- Shell直接显示错误 +- 内存监控自动处理OOM +- 任务失败继续执行后续任务 + +--- + +## 🔧 常见操作 + +### 修改算法参数 + +```bash +# 编辑 run.sh +vim run.sh + +# 修改这些参数 +LOOKBACK_DAYS=365 # 回看天数 +TOP_N=100 # 推荐数量 +DEBUG_MODE="" # 关闭debug +``` + +### 只运行特定任务 + +```bash +cd /home/tw/recommendation/offline_tasks + +# 只运行C++ Swing +cd collaboration && bash run.sh && cd .. + +# 只运行Python Swing +python3 scripts/i2i_swing.py --lookback_days 730 --debug + +# 只加载Redis +python3 scripts/load_index_to_redis.py --redis-host localhost +``` + +### 查看日志 + +```bash +# 主日志 +tail -f logs/run_all_$(date +%Y%m%d).log + +# 内存监控日志 +tail -f logs/memory_monitor.log + +# Debug日志 +ls logs/debug/ +``` + +--- + +## 📝 迁移指南 + +如果你之前使用`python3 run_all.py`,现在改用`bash run.sh`: + +### 命令对应关系 + +| 之前 | 现在 | 说明 | +|------|------|------| +| `python3 run_all.py` | `bash run.sh` | 完整流程 | +| `python3 run_all.py --debug` | `bash run.sh` | run.sh默认开启debug | +| 无对应命令 | `bash run.sh` | 现在包含Redis加载 | + +### 定时任务更新 + +**旧的crontab**: +```cron +0 3 * * * cd /home/tw/recommendation/offline_tasks && python3 run_all.py +``` + +**新的crontab**: +```cron +0 3 * * * cd /home/tw/recommendation/offline_tasks && bash run.sh >> logs/cron_$(date +\%Y\%m\%d).log 2>&1 +``` + +--- + +## ⚠️ 注意事项 + +1. **路径依赖**: + - 确保在`offline_tasks`目录下执行`bash run.sh` + - 不要在其他目录执行 + +2. **内存监控**: + - 默认阈值:警告25GB,终止35GB + - 根据服务器配置调整`MEM_WARN_THRESHOLD`和`MEM_KILL_THRESHOLD` + +3. **并行执行**: + - 不建议同时运行多个`run.sh`实例 + - 脚本会自动清理旧进程 + +4. **失败处理**: + - 单个任务失败不会终止整体流程 + - 查看日志确认失败原因 + +--- + +## 🎯 总结 + +### 改进前后对比 + +| 方面 | 改进前 | 改进后 | +|------|--------|--------| +| **目录结构** | collaboration在外层 | 统一在offline_tasks内 | +| **主执行脚本** | run_all.py (Python) | run.sh (Shell) | +| **代码复杂度** | 270行,多层抽象 | 214行,直接调用 | +| **配置方式** | 参数分散 | 集中在顶部 | +| **内存监控** | 无 | 自动监控+自动终止 | +| **错误处理** | Python异常捕获 | Shell直接显示 | +| **包含任务** | 不含Redis加载 | 含完整流程 | + +### 核心改进 + +1. ✅ **结构简化**: collaboration目录移入,统一管理 +2. ✅ **代码简化**: 去除冗余抽象,直接调用脚本 +3. ✅ **功能增强**: 添加内存监控、统一任务管理 +4. ✅ **易用性**: 配置集中、日志清晰、错误明确 + +--- + +## 📚 相关文档 + +- [快速开始](./快速开始.md) +- [运行脚本指南](./运行脚本指南.md) +- [故障排查指南](./故障排查指南.md) +- [系统改进总结](./系统改进总结-20241017.md) + +--- + +**更新时间**: 2024-10-17 +**状态**: ✅ 已完成并测试 + diff --git a/offline_tasks/run.sh b/offline_tasks/run.sh index e67491f..6233c41 100755 --- a/offline_tasks/run.sh +++ b/offline_tasks/run.sh @@ -1,27 +1,53 @@ #!/bin/bash + cd /home/tw/recommendation/offline_tasks +# mkdir bak___before_rm_run_all_py +# mv output logs nohup.out bak___before_rm_run_all_py/ +# mkdir output +# mkdir logs + + +# ============================================================================ +# 配置区域 +# ============================================================================ + +# 算法参数 +LOOKBACK_DAYS=400 +TOP_N=50 +DEBUG_MODE="--debug" # 留空则不开启debug + +# Redis配置 +REDIS_HOST="localhost" +REDIS_PORT=6379 + +# 内存监控阈值 +MEM_WARN_THRESHOLD=25 # GB +MEM_KILL_THRESHOLD=35 # GB + +# ============================================================================ +# 工具函数 +# ============================================================================ + # 内存监控函数 check_memory() { local pid=$1 - local threshold_warn=25 # 25GB警告阈值 - local threshold_kill=35 # 30GB强制kill阈值 + local task_name=$2 while kill -0 $pid 2>/dev/null; do - # 获取进程内存使用(MB) local mem_mb=$(ps -p $pid -o rss= 2>/dev/null | awk '{print int($1/1024)}') if [ -n "$mem_mb" ]; then local mem_gb=$(echo "scale=2; $mem_mb/1024" | bc) local timestamp=$(date '+%Y-%m-%d %H:%M:%S') - if [ $(echo "$mem_gb >= $threshold_kill" | bc) -eq 1 ]; then - echo "[$timestamp] ❌ 内存超限!当前使用: ${mem_gb}GB (>= ${threshold_kill}GB), 强制终止进程 PID=$pid" | tee -a logs/memory_monitor.log + if [ $(echo "$mem_gb >= $MEM_KILL_THRESHOLD" | bc) -eq 1 ]; then + echo "[$timestamp] ❌ [$task_name] 内存超限!${mem_gb}GB, 强制终止" | tee -a logs/memory_monitor.log kill -9 $pid break - elif [ $(echo "$mem_gb >= $threshold_warn" | bc) -eq 1 ]; then - echo "[$timestamp] ⚠️ 内存警告!当前使用: ${mem_gb}GB (>= ${threshold_warn}GB), PID=$pid" | tee -a logs/memory_monitor.log + elif [ $(echo "$mem_gb >= $MEM_WARN_THRESHOLD" | bc) -eq 1 ]; then + echo "[$timestamp] ⚠️ [$task_name] 内存警告: ${mem_gb}GB" | tee -a logs/memory_monitor.log fi fi @@ -29,58 +55,166 @@ check_memory() { done } +# 运行任务函数 +run_task() { + local task_name=$1 + local task_cmd=$2 + + echo "" + echo "======================================================================" + echo "[$task_name] 开始 - $(date '+%Y-%m-%d %H:%M:%S')" + echo "======================================================================" + + eval $task_cmd & + local pid=$! + + # 启动内存监控 + check_memory $pid "$task_name" & + local monitor_pid=$! + + # 等待任务完成 + wait $pid + local exit_code=$? + + # 停止内存监控 + kill $monitor_pid 2>/dev/null + + if [ $exit_code -eq 0 ]; then + echo "✓ [$task_name] 完成" + return 0 + else + echo "✗ [$task_name] 失败,退出码: $exit_code" + return $exit_code + fi +} + +# ============================================================================ +# 环境准备 +# ============================================================================ + # 清理旧进程 -ps -ef|grep run_all.py | awk '{print $2}' | xargs kill -9 2>/dev/null -ps -ef|grep recommendation | awk '{print $2}' | xargs kill -9 2>/dev/null -rm output/* -rf 2>/dev/null -rm logs/* -rf 2>/dev/null -mkdir -p logs +ps -ef | grep "python3.*scripts" | grep -v grep | awk '{print $2}' | xargs kill -9 2>/dev/null + +# 创建必要目录 +mkdir -p logs output echo "======================================================================" -echo "开始运行离线任务 - $(date '+%Y-%m-%d %H:%M:%S')" -echo "内存监控: 警告阈值=25GB, 强制终止阈值=30GB" +echo "开始运行离线推荐任务 - $(date '+%Y-%m-%d %H:%M:%S')" +echo "配置: lookback_days=$LOOKBACK_DAYS, top_n=$TOP_N" +echo "内存监控: 警告=${MEM_WARN_THRESHOLD}GB, 终止=${MEM_KILL_THRESHOLD}GB" echo "======================================================================" +# ============================================================================ +# 前置任务 +# ============================================================================ +# 前置任务1: 获取商品属性 +run_task "前置任务1: 获取商品属性" \ + "python3 scripts/fetch_item_attributes.py $DEBUG_MODE" +if [ $? -ne 0 ]; then + echo "⚠️ 商品属性获取失败,但继续执行" +fi + +# 前置任务2: 生成Session文件 +run_task "前置任务2: 生成Session文件" \ + "python3 scripts/generate_session.py --lookback_days $LOOKBACK_DAYS --format both $DEBUG_MODE" +if [ $? -ne 0 ]; then + echo "❌ Session文件生成失败,退出" + exit 1 +fi + +# 前置任务3: C++ Swing算法 echo "" -echo ">>> run_all.py" -# python3 run_all.py --lookback_days 400 --top_n 50 --debug & -python3 run_all.py --debug & -PID_PROD=$! -echo "生产任务 PID: $PID_PROD" - -# 启动内存监控 -check_memory $PID_PROD & -MONITOR_PID_2=$! - -# 等待生产任务完成 -wait $PID_PROD -PROD_EXIT_CODE=$? -kill $MONITOR_PID_2 2>/dev/null - -if [ $PROD_EXIT_CODE -eq 0 ]; then - echo "✓ 生产模式完成" +echo "======================================================================" +echo "[前置任务3: C++ Swing算法] 开始 - $(date '+%Y-%m-%d %H:%M:%S')" +echo "======================================================================" +cd collaboration +bash run.sh +SWING_EXIT=$? +cd .. + +if [ $SWING_EXIT -eq 0 ]; then + echo "✓ [前置任务3: C++ Swing算法] 完成" else - echo "✗ 生产模式失败,退出码: $PROD_EXIT_CODE" - exit 1 + echo "⚠️ [前置任务3: C++ Swing算法] 失败,但继续执行" +fi + +# ============================================================================ +# i2i相似度任务 +# ============================================================================ + +# Task 1: Python Swing算法 +run_task "Task 1: Python Swing算法" \ + "python3 scripts/i2i_swing.py --lookback_days $LOOKBACK_DAYS --top_n $TOP_N --use_daily_session $DEBUG_MODE" +if [ $? -ne 0 ]; then + echo "⚠️ Python Swing失败,但继续执行" +fi + +# Task 2: Session W2V +run_task "Task 2: Session W2V" \ + "python3 scripts/i2i_session_w2v.py --lookback_days $LOOKBACK_DAYS --top_n $TOP_N --save_model $DEBUG_MODE" +if [ $? -ne 0 ]; then + echo "⚠️ Session W2V失败,但继续执行" +fi + +# Task 3: DeepWalk +run_task "Task 3: DeepWalk" \ + "python3 scripts/i2i_deepwalk.py --lookback_days $LOOKBACK_DAYS --top_n $TOP_N --save_model --save_graph $DEBUG_MODE" +if [ $? -ne 0 ]; then + echo "⚠️ DeepWalk失败,但继续执行" +fi + +# Task 4: 内容相似度 +run_task "Task 4: 内容相似度" \ + "python3 scripts/i2i_content_similar.py" +if [ $? -ne 0 ]; then + echo "⚠️ 内容相似度失败,但继续执行" fi +# ============================================================================ +# 兴趣聚合任务 +# ============================================================================ + +# Task 5: 兴趣聚合 +run_task "Task 5: 兴趣聚合" \ + "python3 scripts/interest_aggregation.py --lookback_days $LOOKBACK_DAYS --top_n 1000 $DEBUG_MODE" +if [ $? -ne 0 ]; then + echo "⚠️ 兴趣聚合失败,但继续执行" +fi + +# ============================================================================ +# 加载到Redis +# ============================================================================ echo "" -echo ">>> 步骤3: 加载到Redis" -python3 scripts/load_index_to_redis.py --redis-host localhost -LOAD_EXIT_CODE=$? +echo "======================================================================" +echo "[加载到Redis] 开始 - $(date '+%Y-%m-%d %H:%M:%S')" +echo "======================================================================" + +python3 scripts/load_index_to_redis.py --redis-host $REDIS_HOST --redis-port $REDIS_PORT +LOAD_EXIT=$? -if [ $LOAD_EXIT_CODE -eq 0 ]; then - echo "✓ Redis加载完成" +if [ $LOAD_EXIT -eq 0 ]; then + echo "✓ [加载到Redis] 完成" else - echo "✗ Redis加载失败,退出码: $LOAD_EXIT_CODE" + echo "❌ [加载到Redis] 失败,退出码: $LOAD_EXIT" exit 1 fi +# ============================================================================ +# 完成 +# ============================================================================ + echo "" echo "======================================================================" echo "所有任务完成 - $(date '+%Y-%m-%d %H:%M:%S')" echo "======================================================================" - - +echo "" +echo "输出文件位置:" +echo " - 商品属性: output/item_attributes_mappings.json" +echo " - Session文件: output/session.txt.*" +echo " - C++ Swing: collaboration/output/swing_similar.txt" +echo " - Python算法: output/i2i_*.txt" +echo " - 兴趣聚合: output/interest_aggregation_*.txt" +echo " - 日志: logs/" +echo "" diff --git a/offline_tasks/run_all.py b/offline_tasks/run_all.py index beb0563..a963d88 100755 --- a/offline_tasks/run_all.py +++ b/offline_tasks/run_all.py @@ -79,52 +79,6 @@ def run_script(script_name, args=None): return False -def run_cpp_swing(): - """ - 运行C++ Swing算法 - - Returns: - bool: 是否成功 - """ - collaboration_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'collaboration') - run_sh_path = os.path.join(collaboration_dir, 'run.sh') - - if not os.path.exists(run_sh_path): - logger.error(f"C++ Swing script not found: {run_sh_path}") - return False - - logger.info(f"Running C++ Swing: bash {run_sh_path}") - - try: - result = subprocess.run( - ['bash', run_sh_path], - cwd=collaboration_dir, - check=True, - capture_output=True, - text=True - ) - logger.info("C++ Swing algorithm completed successfully") - # 输出部分日志 - output_lines = result.stdout.split('\n') - for line in output_lines[-20:]: # 输出最后20行 - if line.strip(): - logger.info(f" {line}") - return True - except subprocess.CalledProcessError as e: - logger.error(f"C++ Swing failed with return code {e.returncode}") - logger.error(f"Error output: {e.stderr}") - # 输出部分stdout以便调试 - if e.stdout: - logger.error("Stdout output:") - for line in e.stdout.split('\n')[-20:]: - if line.strip(): - logger.error(f" {line}") - return False - except Exception as e: - logger.error(f"Unexpected error running C++ Swing: {e}") - return False - - def main(): parser = argparse.ArgumentParser(description='Run all offline recommendation tasks') parser.add_argument('--debug', action='store_true', @@ -170,22 +124,9 @@ def main(): else: logger.error("生成session文件失败") - # 前置任务3: 运行C++ Swing算法 - logger.info("\n" + "="*80) - logger.info("前置任务3: 运行C++ Swing算法(基于session文件)") - logger.info("="*80) - total_count += 1 - if run_cpp_swing(): - success_count += 1 - logger.info("✓ C++ Swing算法执行成功") - logger.info(" 结果文件: collaboration/output/swing_similar.txt") - logger.info(" 可读文件: collaboration/output/swing_similar_readable.txt") - else: - logger.error("C++ Swing算法执行失败,但不影响其他任务继续") - # i2i 行为相似任务 logger.info("\n" + "="*80) - logger.info("Task 1: Running Python Swing algorithm for i2i similarity") + logger.info("Task 1: Running Swing algorithm for i2i similarity") logger.info("="*80) total_count += 1 script_args = [ -- libgit2 0.21.2