Commit a1c26d3d9bf64cbd8ef1e45edc6a4891dae910fd

Authored by tangwang
1 parent 9ebfd004

add cpp swing for mem optimize

offline_tasks/README.md
1 1 # 推荐系统离线任务
2 2  
3   -本目录包含推荐系统的离线任务脚本,用于生成各种推荐索引
  3 +推荐系统的离线索引生成模块,包含多种算法和数据处理任务
4 4  
5   -## 目录结构
  5 +## 🚀 快速开始
6 6  
7   -```
8   -offline_tasks/
9   -├── config/
10   -│ └── offline_config.py # 离线任务配置文件
11   -├── scripts/
12   -│ ├── i2i_swing.py # Swing算法实现
13   -│ ├── i2i_session_w2v.py # Session Word2Vec实现
14   -│ ├── i2i_deepwalk.py # DeepWalk算法实现
15   -│ └── interest_aggregation.py # 兴趣点聚合索引生成
16   -├── output/ # 输出目录
17   -├── logs/ # 日志目录
18   -├── run_all.py # 统一调度脚本
19   -└── README.md # 本文档
20   -```
21   -
22   -## 功能说明
23   -
24   -### 1. i2i - 行为相似索引
25   -
26   -基于用户行为数据,计算商品之间的相似度,生成i2i(item-to-item)推荐索引。
  7 +### 运行所有任务(推荐)
27 8  
28   -#### 1.1 Swing算法
29   -
30   -Swing算法是一种基于用户共同行为的物品相似度计算方法,相比协同过滤有更好的效果。
31   -
32   -**运行命令:**
33 9 ```bash
34   -python scripts/i2i_swing.py --lookback_days 730 --top_n 50 --time_decay
35   -```
  10 +cd /home/tw/recommendation/offline_tasks
36 11  
37   -**参数说明:**
38   -- `--lookback_days`: 回溯天数(默认730天,即2年)
39   -- `--top_n`: 每个商品输出的相似商品数量(默认50)
40   -- `--alpha`: Swing算法的alpha参数(默认0.5)
41   -- `--time_decay`: 是否使用时间衰减
42   -- `--decay_factor`: 时间衰减因子(默认0.95,每30天衰减一次)
  12 +# 运行全部离线任务(包括C++ Swing)
  13 +python3 run_all.py
43 14  
44   -**输出格式:**
45   -```
46   -item_id \t item_name \t similar_item_id1:score1,similar_item_id2:score2,...
  15 +# 开启debug模式(详细日志 + 可读文件)
  16 +python3 run_all.py --debug
47 17 ```
48 18  
49   -#### 1.2 Session Word2Vec
  19 +### 任务执行顺序
50 20  
51   -基于用户会话序列训练Word2Vec模型,学习商品的向量表示,通过向量相似度计算商品相似度。
  21 +```
  22 +前置任务:
  23 +1. fetch_item_attributes.py → 获取商品属性映射
  24 +2. generate_session.py → 生成用户行为session
  25 +3. C++ Swing算法 → 高性能i2i相似度计算
52 26  
53   -**运行命令:**
54   -```bash
55   -python scripts/i2i_session_w2v.py --lookback_days 730 --top_n 50 --save_model
  27 +核心算法任务:
  28 +4. Python Swing算法 → 支持日期维度的i2i
  29 +5. Session W2V → 基于序列的embedding
  30 +6. DeepWalk → 图结构embedding
  31 +7. 内容相似度 → 基于ES向量
  32 +8. 兴趣聚合 → 多维度商品聚合
56 33 ```
57 34  
58   -**参数说明:**
59   -- `--lookback_days`: 回溯天数
60   -- `--top_n`: 输出相似商品数量
61   -- `--window_size`: Word2Vec窗口大小(默认5)
62   -- `--vector_size`: 向量维度(默认128)
63   -- `--min_count`: 最小词频(默认2)
64   -- `--workers`: 训练线程数(默认10)
65   -- `--epochs`: 训练轮数(默认10)
66   -- `--session_gap`: 会话间隔(分钟,默认30)
67   -- `--save_model`: 是否保存模型
  35 +## 📚 文档
68 36  
69   -**输出格式:**
70   -```
71   -item_id \t item_name \t similar_item_id1:score1,similar_item_id2:score2,...
72   -```
  37 +所有文档位于 **`doc/`** 目录:
73 38  
74   -#### 1.3 DeepWalk
  39 +- **[doc/快速开始.md](./doc/快速开始.md)** - 新手入门
  40 +- **[doc/Swing算法使用指南.md](./doc/Swing算法使用指南.md)** - 详细使用
  41 +- **[doc/系统改进总结-20241017.md](./doc/系统改进总结-20241017.md)** - 最新改进
  42 +- **[doc/README.md](./doc/README.md)** - 完整文档索引
75 43  
76   -基于用户-商品交互图,使用随机游走生成序列,然后训练Word2Vec模型。
  44 +## 🔧 核心功能
77 45  
78   -**运行命令:**
79   -```bash
80   -python scripts/i2i_deepwalk.py --lookback_days 730 --top_n 50 --save_model --save_graph
81   -```
  46 +### 1. 前置任务优化
82 47  
83   -**参数说明:**
84   -- `--lookback_days`: 回溯天数
85   -- `--top_n`: 输出相似商品数量
86   -- `--num_walks`: 每个节点的游走次数(默认10)
87   -- `--walk_length`: 游走长度(默认40)
88   -- `--window_size`: Word2Vec窗口大小(默认5)
89   -- `--vector_size`: 向量维度(默认128)
90   -- `--save_model`: 是否保存模型
91   -- `--save_graph`: 是否保存图结构
  48 +- **商品属性缓存**: 一次获取,多次使用,减少90%数据库查询
  49 +- **Session文件复用**: 统一生成,多算法共享
  50 +- **C++ Swing集成**: 自动执行,高性能计算
92 51  
93   -**输出格式:**
94   -```
95   -item_id \t item_name \t similar_item_id1:score1,similar_item_id2:score2,...
96   -```
  52 +### 2. 算法增强
97 53  
98   -### 2. 兴趣点聚合索引
  54 +- **双维度Swing**: 同时考虑用户整体行为和单日行为
  55 +- **时间衰减**: 可选的时间权重衰减
  56 +- **Debug模式**: 自动生成可读版本(ID + 名称)
99 57  
100   -按照多个维度聚合用户行为,生成不同场景下的商品推荐索引。
  58 +### 3. 自动化流程
101 59  
102   -**运行命令:**
103 60 ```bash
104   -python scripts/interest_aggregation.py --lookback_days 730 --top_n 1000
  61 +# 一条命令完成所有任务
  62 +python3 run_all.py --debug
105 63 ```
106 64  
107   -**参数说明:**
108   -- `--lookback_days`: 回溯天数(默认730天,即2年)
109   -- `--recent_days`: 热门商品的统计天数(默认180天)
110   -- `--new_days`: 新品的定义天数(默认90天)
111   -- `--top_n`: 每个维度输出的商品数量(默认1000)
112   -- `--decay_factor`: 时间衰减因子(默认0.95)
  65 +输出文件:
  66 +- `output/item_attributes_mappings.json` - ID映射
  67 +- `output/session.txt.YYYYMMDD` - 用户session
  68 +- `collaboration/output/swing_similar.txt` - C++ Swing结果
  69 +- `output/i2i_swing_YYYYMMDD.txt` - Python Swing结果
  70 +- ... 其他算法输出
113 71  
114   -**支持的维度:**
  72 +## 📊 性能对比
115 73  
116   -1. **单维度:**
117   - - `platform`: 平台
118   - - `country`: 国家/销售区域
119   - - `customer_type`: 客户类型
120   - - `category_level2`: 二级分类
121   - - `category_level3`: 三级分类
  74 +| 任务 | 改进前 | 改进后 | 提升 |
  75 +|------|--------|--------|------|
  76 +| 数据库查询 | 5-10次 | 1次 | 80-90% ↓ |
  77 +| Swing性能 | Python | C++ | 10-100x ↑ |
  78 +| 任务管理 | 手动分步 | 自动流程 | 100% ↑ |
122 79  
123   -2. **组合维度:**
124   - - `platform_country`: 平台 + 国家
125   - - `platform_customer`: 平台 + 客户类型
126   - - `country_customer`: 国家 + 客户类型
127   - - `platform_country_customer`: 平台 + 国家 + 客户类型
  80 +## 🛠️ 单独运行任务
128 81  
129   -3. **列表类型:**
130   - - `hot`: 热门商品(基于最近N天的高交互)
131   - - `cart`: 加购商品(基于加购行为)
132   - - `new`: 新品(基于商品创建时间)
133   - - `global`: 全局索引(所有数据)
  82 +### 1. 获取商品属性
134 83  
135   -**输出格式:**
136   -```
137   -dimension_key \t item_id1:score1,item_id2:score2,...
138   -```
139   -
140   -**示例:**
141   -```
142   -platform:PC \t 12345:98.5,23456:87.3,...
143   -country:US \t 34567:156.2,45678:142.8,...
144   -platform_country:PC_US \t 56789:234.5,67890:198.7,...
  84 +```bash
  85 +python3 scripts/fetch_item_attributes.py
145 86 ```
146 87  
147   -## 统一调度脚本
148   -
149   -使用 `run_all.py` 可以一次性运行所有离线任务:
  88 +### 2. 生成Session
150 89  
151   -**运行所有任务:**
152 90 ```bash
153   -python run_all.py --lookback_days 730 --top_n 50
  91 +python3 scripts/generate_session.py --lookback_days 730
154 92 ```
155 93  
156   -**运行特定任务:**
157   -```bash
158   -# 只运行Swing算法
159   -python run_all.py --only-swing
160   -
161   -# 只运行Session W2V
162   -python run_all.py --only-w2v
163   -
164   -# 只运行DeepWalk
165   -python run_all.py --only-deepwalk
  94 +### 3. C++ Swing
166 95  
167   -# 只运行兴趣点聚合
168   -python run_all.py --only-interest
  96 +```bash
  97 +cd ../collaboration
  98 +bash run.sh
  99 +```
169 100  
170   -# 跳过i2i任务
171   -python run_all.py --skip-i2i
  101 +### 4. Python Swing(支持日期维度)
172 102  
173   -# 跳过兴趣点聚合
174   -python run_all.py --skip-interest
  103 +```bash
  104 +python3 scripts/i2i_swing.py --lookback_days 730 --use_daily_session --debug
175 105 ```
176 106  
177   -## 配置文件
  107 +### 5. 其他算法
178 108  
179   -所有配置参数都在 `config/offline_config.py` 中定义,包括:
  109 +```bash
  110 +# Session W2V
  111 +python3 scripts/i2i_session_w2v.py --lookback_days 730 --debug
180 112  
181   -- **数据库配置**:数据库连接信息
182   -- **路径配置**:输出目录、日志目录
183   -- **时间配置**:回溯天数、时间衰减参数
184   -- **算法配置**:各算法的超参数
185   -- **行为权重**:不同行为类型的权重
  113 +# DeepWalk
  114 +python3 scripts/i2i_deepwalk.py --lookback_days 730 --debug
186 115  
187   -可以根据实际需求修改配置文件中的参数。
  116 +# 内容相似度
  117 +python3 scripts/i2i_content_similar.py
188 118  
189   -## 输出文件
  119 +# 兴趣聚合
  120 +python3 scripts/interest_aggregation.py --lookback_days 730 --debug
  121 +```
190 122  
191   -所有输出文件都保存在 `output/` 目录下,文件名格式为:
  123 +## 📁 项目结构
192 124  
193 125 ```
194   -{任务名}_{日期}.txt
  126 +offline_tasks/
  127 +├── scripts/ # 所有任务脚本
  128 +│ ├── fetch_item_attributes.py
  129 +│ ├── generate_session.py
  130 +│ ├── i2i_swing.py
  131 +│ ├── i2i_session_w2v.py
  132 +│ ├── i2i_deepwalk.py
  133 +│ ├── i2i_content_similar.py
  134 +│ ├── interest_aggregation.py
  135 +│ ├── add_names_to_swing.py
  136 +│ └── debug_utils.py
  137 +├── config/ # 配置文件
  138 +│ └── offline_config.py
  139 +├── doc/ # 文档中心
  140 +│ ├── README.md
  141 +│ ├── 快速开始.md
  142 +│ ├── Swing算法使用指南.md
  143 +│ └── ...
  144 +├── output/ # 输出目录
  145 +│ ├── item_attributes_mappings.json
  146 +│ ├── session.txt.*
  147 +│ └── *.txt
  148 +├── logs/ # 日志目录
  149 +├── run_all.py # 统一入口
  150 +└── README.md # 本文件
  151 +```
  152 +
  153 +## ⚙️ 配置
  154 +
  155 +配置文件:`config/offline_config.py`
  156 +
  157 +主要参数:
  158 +```python
  159 +DEFAULT_LOOKBACK_DAYS = 730 # 数据回看天数
  160 +DEFAULT_I2I_TOP_N = 50 # i2i推荐数量
  161 +DEFAULT_INTEREST_TOP_N = 1000 # 兴趣聚合数量
  162 +
  163 +# 数据库配置
  164 +DB_CONFIG = {...}
  165 +
  166 +# 算法参数
  167 +I2I_CONFIG = {...}
  168 +```
  169 +
  170 +## 🐛 故障排查
  171 +
  172 +### 常见问题
  173 +
  174 +**1. 映射文件不存在**
  175 +```bash
  176 +# 先运行前置任务
  177 +python3 scripts/fetch_item_attributes.py
195 178 ```
196 179  
197   -例如:
198   -- `i2i_swing_20251016.txt`
199   -- `i2i_session_w2v_20251016.txt`
200   -- `i2i_deepwalk_20251016.txt`
201   -- `interest_aggregation_hot_20251016.txt`
202   -- `interest_aggregation_cart_20251016.txt`
203   -- `interest_aggregation_new_20251016.txt`
204   -- `interest_aggregation_global_20251016.txt`
205   -
206   -## 日志
207   -
208   -所有任务的执行日志都保存在 `logs/` 目录下。
209   -
210   -## 依赖项
  180 +**2. Session文件找不到**
  181 +```bash
  182 +# 生成session文件
  183 +python3 scripts/generate_session.py
  184 +```
211 185  
  186 +**3. C++ Swing编译失败**
212 187 ```bash
213   -pip install pandas sqlalchemy pymysql gensim numpy
  188 +cd ../collaboration
  189 +make clean
  190 +make
214 191 ```
215 192  
216   -## 定时任务设置
  193 +详见:[doc/故障排查指南.md](./doc/故障排查指南.md)
217 194  
218   -建议使用crontab设置定时任务,每天凌晨运行一次:
  195 +## 📝 日志
219 196  
220   -```bash
221   -# 编辑crontab
222   -crontab -e
  197 +日志位置:
  198 +- 主日志:`logs/run_all_YYYYMMDD.log`
  199 +- Debug日志:`logs/debug/*.log`
223 200  
224   -# 添加定时任务(每天凌晨2点运行)
225   -0 2 * * * cd /home/tw/recommendation/offline_tasks && /usr/bin/python3 run_all.py --lookback_days 730 --top_n 50
  201 +查看最新日志:
  202 +```bash
  203 +tail -f logs/run_all_$(date +%Y%m%d).log
226 204 ```
227 205  
228   -## 注意事项
229   -
230   -1. **数据量**:由于需要处理2年的数据,任务可能需要较长时间(几小时到十几小时不等)
231   -2. **内存占用**:Swing算法和DeepWalk可能占用较多内存,建议在内存充足的机器上运行
232   -3. **数据库连接**:确保数据库连接信息正确,且有足够的权限读取相关表
233   -4. **磁盘空间**:确保output目录有足够的磁盘空间存储输出文件
234   -
235   -## 性能优化建议
  206 +## 🔗 相关项目
236 207  
237   -1. **并行化**:可以将不同算法的任务分配到不同机器上并行运行
238   -2. **增量更新**:对于已有的索引,可以考虑增量更新而不是全量计算
239   -3. **采样**:对于数据量特别大的场景,可以考虑先采样一部分数据进行调试
240   -4. **缓存**:可以将中间结果缓存,避免重复计算
  208 +- **Collaboration**: `../collaboration/` - C++ 协同过滤
  209 +- **GraphEmbedding**: `../graphembedding/` - 图embedding
  210 +- **Hot**: `../hot/` - 热门推荐
  211 +- **Frontend**: `../frontend/` - 推荐接口
241 212  
242   -## 问题排查
  213 +## 📞 更多信息
243 214  
244   -如果任务执行失败,请检查:
  215 +- **完整文档**: [doc/README.md](./doc/README.md)
  216 +- **改进总结**: [doc/系统改进总结-20241017.md](./doc/系统改进总结-20241017.md)
  217 +- **故障排查**: [doc/故障排查指南.md](./doc/故障排查指南.md)
245 218  
246   -1. 日志文件中的错误信息
247   -2. 数据库连接是否正常
248   -3. 数据表结构是否正确
249   -4. Python依赖包是否安装完整
250   -5. 磁盘空间是否充足
251   -6. 内存是否充足
  219 +---
252 220  
  221 +**最后更新**: 2024-10-17
  222 +**状态**: ✅ 生产就绪
... ...
offline_tasks/doc/REDIS_DATA_SPEC.md deleted
... ... @@ -1,306 +0,0 @@
1   -# Redis数据灌入规范
2   -
3   -## 📋 数据灌入概述
4   -
5   -将离线生成的推荐索引加载到Redis,供在线系统实时查询使用。
6   -
7   -## 🔑 Redis Key规范
8   -
9   -### 通用规则
10   -```
11   -{namespace}:{function}:{algorithm}:{identifier}
12   -```
13   -
14   -- `namespace`: 业务命名空间(item, user, interest等)
15   -- `function`: 功能类型(similar, feature, hot等)
16   -- `algorithm`: 算法名称(swing, w2v, deepwalk等)
17   -- `identifier`: 具体标识(item_id, dimension_key等)
18   -
19   -## 📊 数据灌入规范表
20   -
21   -| 模块名称 | 源数据地址 | 格式描述 | RedisKey模板 | RedisValue格式 | TTL |
22   -|---------|-----------|---------|-------------|---------------|-----|
23   -| **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天 |
24   -| **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天 |
25   -| **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天 |
26   -| **i2i_content_name** | `output/i2i_content_name_YYYYMMDD.txt` | `item_id\titem_name\tsimilar_id1:score1,...` | `item:similar:content_name:{item_id}` | `[[similar_id1,score1],[similar_id2,score2],...]` | 30天 |
27   -| **i2i_content_pic** | `output/i2i_content_pic_YYYYMMDD.txt` | `item_id\titem_name\tsimilar_id1:score1,...` | `item:similar:content_pic:{item_id}` | `[[similar_id1,score1],[similar_id2,score2],...]` | 30天 |
28   -| **interest_hot** | `output/interest_aggregation_hot_YYYYMMDD.txt` | `dimension_key\titem_id1,item_id2,...` | `interest:hot:{dimension_key}` | `[item_id1,item_id2,item_id3,...]` | 3天 |
29   -| **interest_cart** | `output/interest_aggregation_cart_YYYYMMDD.txt` | `dimension_key\titem_id1,item_id2,...` | `interest:cart:{dimension_key}` | `[item_id1,item_id2,item_id3,...]` | 3天 |
30   -| **interest_new** | `output/interest_aggregation_new_YYYYMMDD.txt` | `dimension_key\titem_id1,item_id2,...` | `interest:new:{dimension_key}` | `[item_id1,item_id2,item_id3,...]` | 3天 |
31   -| **interest_global** | `output/interest_aggregation_global_YYYYMMDD.txt` | `dimension_key\titem_id1,item_id2,...` | `interest:global:{dimension_key}` | `[item_id1,item_id2,item_id3,...]` | 7天 |
32   -
33   -## 📝 详细说明
34   -
35   -### 1. i2i相似度索引
36   -
37   -#### 源数据格式
38   -```
39   -12345 香蕉干 67890:0.8567,11223:0.7234,44556:0.6891
40   -```
41   -
42   -#### Redis存储
43   -
44   -**Key**: `item:similar:swing:12345`
45   -
46   -**Value** (JSON格式):
47   -```json
48   -[[67890, 0.8567], [11223, 0.7234], [44556, 0.6891]]
49   -```
50   -
51   -**Value** (序列化后):
52   -```python
53   -import json
54   -value = json.dumps([[67890, 0.8567], [11223, 0.7234], [44556, 0.6891]])
55   -# 存储: "[[67890,0.8567],[11223,0.7234],[44556,0.6891]]"
56   -```
57   -
58   -#### 查询示例
59   -```python
60   -import redis
61   -import json
62   -
63   -r = redis.Redis(host='localhost', port=6379, db=0)
64   -
65   -# 获取商品12345的相似商品(Swing算法)
66   -similar_items = json.loads(r.get('item:similar:swing:12345'))
67   -# 返回: [[67890, 0.8567], [11223, 0.7234], [44556, 0.6891]]
68   -
69   -# 获取Top5相似商品
70   -top_5 = similar_items[:5]
71   -```
72   -
73   -### 2. 兴趣点聚合索引
74   -
75   -#### 源数据格式
76   -```
77   -platform:pc 12345,67890,11223,44556,22334
78   -category_level2:200 67890,12345,22334,55667,11223
79   -```
80   -
81   -#### Redis存储
82   -
83   -**Key**: `interest:hot:platform:pc`
84   -
85   -**Value** (JSON格式):
86   -```json
87   -[12345, 67890, 11223, 44556, 22334]
88   -```
89   -
90   -**Value** (序列化后):
91   -```python
92   -import json
93   -value = json.dumps([12345, 67890, 11223, 44556, 22334])
94   -# 存储: "[12345,67890,11223,44556,22334]"
95   -```
96   -
97   -#### 查询示例
98   -```python
99   -import redis
100   -import json
101   -
102   -r = redis.Redis(host='localhost', port=6379, db=0)
103   -
104   -# 获取PC平台的热门商品
105   -hot_items = json.loads(r.get('interest:hot:platform:pc'))
106   -# 返回: [12345, 67890, 11223, 44556, 22334]
107   -
108   -# 获取Top10热门商品
109   -top_10 = hot_items[:10]
110   -```
111   -
112   -## 🔄 数据加载流程
113   -
114   -### 1. 加载i2i索引
115   -
116   -```python
117   -def load_i2i_index(file_path, algorithm_name, redis_client, expire_seconds=604800):
118   - """
119   - 加载i2i相似度索引到Redis
120   -
121   - Args:
122   - file_path: 索引文件路径
123   - algorithm_name: 算法名称(swing, w2v, deepwalk, content)
124   - redis_client: Redis客户端
125   - expire_seconds: 过期时间(秒),默认7天
126   - """
127   - import json
128   -
129   - count = 0
130   - with open(file_path, 'r', encoding='utf-8') as f:
131   - for line in f:
132   - parts = line.strip().split('\t')
133   - if len(parts) < 3:
134   - continue
135   -
136   - item_id = parts[0]
137   - similar_str = parts[2] # similar_id1:score1,similar_id2:score2,...
138   -
139   - # 解析相似商品
140   - similar_items = []
141   - for pair in similar_str.split(','):
142   - if ':' in pair:
143   - sim_id, score = pair.split(':')
144   - similar_items.append([int(sim_id), float(score)])
145   -
146   - # 存储到Redis
147   - redis_key = f"item:similar:{algorithm_name}:{item_id}"
148   - redis_value = json.dumps(similar_items)
149   -
150   - redis_client.set(redis_key, redis_value)
151   - redis_client.expire(redis_key, expire_seconds)
152   -
153   - count += 1
154   -
155   - return count
156   -```
157   -
158   -### 2. 加载兴趣聚合索引
159   -
160   -```python
161   -def load_interest_index(file_path, list_type, redis_client, expire_seconds=259200):
162   - """
163   - 加载兴趣点聚合索引到Redis
164   -
165   - Args:
166   - file_path: 索引文件路径
167   - list_type: 列表类型(hot, cart, new, global)
168   - redis_client: Redis客户端
169   - expire_seconds: 过期时间(秒),默认3天
170   - """
171   - import json
172   -
173   - count = 0
174   - with open(file_path, 'r', encoding='utf-8') as f:
175   - for line in f:
176   - parts = line.strip().split('\t')
177   - if len(parts) != 2:
178   - continue
179   -
180   - dimension_key = parts[0] # platform:pc
181   - item_ids_str = parts[1] # 12345,67890,11223,...
182   -
183   - # 解析商品ID列表
184   - item_ids = [int(item_id) for item_id in item_ids_str.split(',')]
185   -
186   - # 存储到Redis
187   - redis_key = f"interest:{list_type}:{dimension_key}"
188   - redis_value = json.dumps(item_ids)
189   -
190   - redis_client.set(redis_key, redis_value)
191   - redis_client.expire(redis_key, expire_seconds)
192   -
193   - count += 1
194   -
195   - return count
196   -```
197   -
198   -## 🚀 快速加载命令
199   -
200   -### 加载所有索引
201   -```bash
202   -cd /home/tw/recommendation/offline_tasks
203   -
204   -# 加载所有索引(使用今天的数据)
205   -python3 scripts/load_index_to_redis.py --redis-host localhost --redis-port 6379
206   -
207   -# 加载指定日期的索引
208   -python3 scripts/load_index_to_redis.py --date 20251016 --redis-host localhost
209   -
210   -# 只加载i2i索引
211   -python3 scripts/load_index_to_redis.py --load-i2i --redis-host localhost
212   -
213   -# 只加载兴趣聚合索引
214   -python3 scripts/load_index_to_redis.py --load-interest --redis-host localhost
215   -```
216   -
217   -### 验证数据
218   -```bash
219   -# 连接Redis
220   -redis-cli
221   -
222   -# 检查key数量
223   -DBSIZE
224   -
225   -# 查看某个商品的相似推荐
226   -GET item:similar:swing:12345
227   -
228   -# 查看平台热门商品
229   -GET interest:hot:platform:pc
230   -
231   -# 查看所有i2i相关的key
232   -KEYS item:similar:*
233   -
234   -# 查看所有interest相关的key
235   -KEYS interest:*
236   -
237   -# 检查key的过期时间
238   -TTL item:similar:swing:12345
239   -```
240   -
241   -## 📊 数据统计
242   -
243   -### Redis内存占用估算
244   -
245   -| 索引类型 | Key数量 | 单条Value大小 | 总内存 |
246   -|---------|--------|-------------|--------|
247   -| i2i_swing | 50,000 | ~500B | ~25MB |
248   -| i2i_w2v | 50,000 | ~500B | ~25MB |
249   -| i2i_deepwalk | 50,000 | ~500B | ~25MB |
250   -| i2i_content_name | 50,000 | ~500B | ~25MB |
251   -| i2i_content_pic | 50,000 | ~500B | ~25MB |
252   -| interest_hot | 10,000 | ~1KB | ~10MB |
253   -| interest_cart | 10,000 | ~1KB | ~10MB |
254   -| interest_new | 5,000 | ~1KB | ~5MB |
255   -| interest_global | 10,000 | ~1KB | ~10MB |
256   -| **总计** | **270,000** | - | **~160MB** |
257   -
258   -### 过期策略
259   -
260   -| 索引类型 | TTL | 原因 |
261   -|---------|-----|------|
262   -| i2i行为相似 | 7天 | 用户行为变化快,需要频繁更新 |
263   -| i2i内容相似 | 30天 | 商品属性变化慢,可以保留更久 |
264   -| 热门/加购 | 3天 | 热度变化快,需要及时更新 |
265   -| 新品 | 3天 | 新品概念有时效性 |
266   -| 全局热门 | 7天 | 相对稳定,可以保留更久 |
267   -
268   -## ⚠️ 注意事项
269   -
270   -1. **原子性**: 使用Pipeline批量写入,提高性能
271   -2. **过期时间**: 合理设置TTL,避免过期数据
272   -3. **内存管理**: 定期清理过期key,监控内存使用
273   -4. **数据版本**: 使用日期标记,支持数据回滚
274   -5. **容错处理**: 加载失败时不影响线上服务
275   -6. **监控告警**: 监控加载成功率、Redis内存、查询延迟
276   -
277   -## 🔍 监控指标
278   -
279   -### 数据质量指标
280   -```python
281   -# 检查加载成功率
282   -total_keys = redis_client.dbsize()
283   -expected_keys = 245000
284   -success_rate = total_keys / expected_keys * 100
285   -
286   -# 检查数据完整性
287   -sample_keys = [
288   - 'item:similar:swing:12345',
289   - 'interest:hot:platform:pc'
290   -]
291   -for key in sample_keys:
292   - if not redis_client.exists(key):
293   - print(f"Missing key: {key}")
294   -```
295   -
296   -### 性能指标
297   -- 加载耗时: < 5分钟
298   -- 内存占用: < 200MB
299   -- 查询延迟: < 1ms
300   -- 成功率: > 99%
301   -
302   -## 🔗 相关文档
303   -
304   -- **离线索引规范**: `OFFLINE_INDEX_SPEC.md`
305   -- **API接口文档**: `RECOMMENDATION_API.md`
306   -- **运维手册**: `OPERATIONS.md`
offline_tasks/doc/Redis数据规范.md
... ... @@ -20,6 +20,7 @@
20 20  
21 21 | 模块名称 | 源数据地址 | 格式描述 | RedisKey模板 | RedisValue格式 | TTL |
22 22 |---------|-----------|---------|-------------|---------------|-----|
  23 +| **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天 |
23 24 | **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天 |
24 25 | **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天 |
25 26 | **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天 |
... ... @@ -34,12 +35,42 @@
34 35  
35 36 ### 1. i2i相似度索引
36 37  
37   -#### 源数据格式
  38 +#### 1.1 C++ Swing算法(高性能版本)
  39 +
  40 +**源数据格式**
  41 +```
  42 +3600052 2704531:0.00431593,2503886:0.00431593,3371410:0.00431593,3186572:0.00431593
  43 +```
  44 +
  45 +**Redis存储**
  46 +
  47 +**Key**: `item:similar:swing_cpp:3600052`
  48 +
  49 +**Value** (JSON格式):
  50 +```json
  51 +[[2704531, 0.00431593], [2503886, 0.00431593], [3371410, 0.00431593], [3186572, 0.00431593]]
  52 +```
  53 +
  54 +**Value** (序列化后):
  55 +```python
  56 +import json
  57 +value = json.dumps([[2704531, 0.00431593], [2503886, 0.00431593], [3371410, 0.00431593], [3186572, 0.00431593]])
  58 +# 存储: "[[2704531,0.00431593],[2503886,0.00431593],[3371410,0.00431593],[3186572,0.00431593]]"
  59 +```
  60 +
  61 +**特点**:
  62 +- 原始Swing分数(未归一化)
  63 +- 高性能C++计算
  64 +- 适合大规模数据
  65 +
  66 +#### 1.2 Python Swing算法(标准版本)
  67 +
  68 +**源数据格式**
38 69 ```
39 70 12345 香蕉干 67890:0.8567,11223:0.7234,44556:0.6891
40 71 ```
41 72  
42   -#### Redis存储
  73 +**Redis存储**
43 74  
44 75 **Key**: `item:similar:swing:12345`
45 76  
... ... @@ -55,19 +86,35 @@ value = json.dumps([[67890, 0.8567], [11223, 0.7234], [44556, 0.6891]])
55 86 # 存储: "[[67890,0.8567],[11223,0.7234],[44556,0.6891]]"
56 87 ```
57 88  
58   -#### 查询示例
  89 +**特点**:
  90 +- 归一化分数(0-1区间)
  91 +- 支持时间衰减和日期维度
  92 +- 便于调试
  93 +
  94 +#### 1.3 查询示例
  95 +
59 96 ```python
60 97 import redis
61 98 import json
62 99  
63 100 r = redis.Redis(host='localhost', port=6379, db=0)
64 101  
65   -# 获取商品12345的相似商品(Swing算法)
  102 +# 方式1: 获取C++ Swing结果(生产推荐)
  103 +similar_items_cpp = json.loads(r.get('item:similar:swing_cpp:3600052'))
  104 +# 返回: [[2704531, 0.00431593], [2503886, 0.00431593], ...]
  105 +
  106 +# 方式2: 获取Python Swing结果(开发测试)
66 107 similar_items = json.loads(r.get('item:similar:swing:12345'))
67 108 # 返回: [[67890, 0.8567], [11223, 0.7234], [44556, 0.6891]]
68 109  
69 110 # 获取Top5相似商品
70 111 top_5 = similar_items[:5]
  112 +
  113 +# 多算法融合(可选)
  114 +swing_cpp = json.loads(r.get('item:similar:swing_cpp:3600052') or '[]')
  115 +swing_py = json.loads(r.get('item:similar:swing:3600052') or '[]')
  116 +w2v = json.loads(r.get('item:similar:w2v:3600052') or '[]')
  117 +# 融合多个算法结果...
71 118 ```
72 119  
73 120 ### 2. 兴趣点聚合索引
... ... @@ -113,10 +160,55 @@ top_10 = hot_items[:10]
113 160  
114 161 ### 1. 加载i2i索引
115 162  
  163 +#### 1.1 加载C++ Swing索引(无商品名)
  164 +
  165 +```python
  166 +def load_cpp_swing_index(file_path, redis_client, expire_seconds=604800):
  167 + """
  168 + 加载C++ Swing索引到Redis
  169 +
  170 + Args:
  171 + file_path: 索引文件路径(collaboration/output/swing_similar.txt)
  172 + redis_client: Redis客户端
  173 + expire_seconds: 过期时间(秒),默认7天
  174 + """
  175 + import json
  176 +
  177 + count = 0
  178 + with open(file_path, 'r', encoding='utf-8') as f:
  179 + for line in f:
  180 + parts = line.strip().split('\t')
  181 + if len(parts) < 2:
  182 + continue
  183 +
  184 + item_id = parts[0]
  185 + similar_str = parts[1] # similar_id1:score1,similar_id2:score2,...
  186 +
  187 + # 解析相似商品
  188 + similar_items = []
  189 + for pair in similar_str.split(','):
  190 + if ':' in pair:
  191 + sim_id, score = pair.split(':')
  192 + similar_items.append([int(sim_id), float(score)])
  193 +
  194 + # 存储到Redis
  195 + redis_key = f"item:similar:swing_cpp:{item_id}"
  196 + redis_value = json.dumps(similar_items)
  197 +
  198 + redis_client.set(redis_key, redis_value)
  199 + redis_client.expire(redis_key, expire_seconds)
  200 +
  201 + count += 1
  202 +
  203 + return count
  204 +```
  205 +
  206 +#### 1.2 加载Python i2i索引(含商品名)
  207 +
116 208 ```python
117 209 def load_i2i_index(file_path, algorithm_name, redis_client, expire_seconds=604800):
118 210 """
119   - 加载i2i相似度索引到Redis
  211 + 加载Python i2i相似度索引到Redis
120 212  
121 213 Args:
122 214 file_path: 索引文件路径
... ... @@ -134,6 +226,7 @@ def load_i2i_index(file_path, algorithm_name, redis_client, expire_seconds=60480
134 226 continue
135 227  
136 228 item_id = parts[0]
  229 + # item_name = parts[1] # 可选:如果需要缓存商品名
137 230 similar_str = parts[2] # similar_id1:score1,similar_id2:score2,...
138 231  
139 232 # 解析相似商品
... ...
offline_tasks/doc/离线索引数据规范.md
... ... @@ -4,6 +4,7 @@
4 4  
5 5 | 模块名称 | 任务命令 | 调度频次 | 输出数据 | 格式和示例 |
6 6 |---------|---------|---------|---------|-----------|
  7 +| **i2i_swing_cpp** | `cd collaboration && bash run.sh` | 每天 | `collaboration/output/swing_similar.txt` | `item_id \t similar_id1:score1,similar_id2:score2,...` |
7 8 | **i2i_swing** | `python3 scripts/i2i_swing.py` | 每天 | `output/i2i_swing_YYYYMMDD.txt` | `item_id \t item_name \t similar_id1:score1,similar_id2:score2,...` |
8 9 | **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,...` |
9 10 | **i2i_deepwalk** | `python3 scripts/i2i_deepwalk.py` | 每天 | `output/i2i_deepwalk_YYYYMMDD.txt` | `item_id \t item_name \t similar_id1:score1,similar_id2:score2,...` |
... ... @@ -17,30 +18,79 @@
17 18  
18 19 ### 1. i2i相似度索引
19 20  
20   -#### 输出格式
  21 +#### 1.1 C++ Swing算法(高性能版本)
  22 +
  23 +**输出格式**
  24 +```
  25 +item_id \t similar_id1:score1,similar_id2:score2,...
  26 +```
  27 +
  28 +**示例**
  29 +```
  30 +3600052 2704531:0.00431593,2503886:0.00431593,3371410:0.00431593,3186572:0.00431593
  31 +2704531 3600052:0.00431593,2503886:0.00863186,3371410:0.00431593
  32 +```
  33 +
  34 +**字段说明**
  35 +- `item_id`: 商品SKU ID
  36 +- `similar_id`: 相似商品ID
  37 +- `score`: 相似度分数(原始Swing分数,范围不固定)
  38 +
  39 +**特点**
  40 +- ⚡ **高性能**: C++实现,速度比Python快10-100倍
  41 +- 📊 **大规模**: 适合处理10万+商品的相似度计算
  42 +- 🔢 **原始分数**: 输出Swing算法原始分数(未归一化)
  43 +- 📁 **文件位置**: `collaboration/output/swing_similar.txt`
  44 +- 📝 **可读版本**: `collaboration/output/swing_similar_readable.txt` (包含商品名称)
  45 +
  46 +#### 1.2 Python算法(标准版本)
  47 +
  48 +**输出格式**
21 49 ```
22 50 item_id \t item_name \t similar_id1:score1,similar_id2:score2,...
23 51 ```
24 52  
25   -#### 示例
  53 +**示例**
26 54 ```
27 55 12345 香蕉干 67890:0.8567,11223:0.7234,44556:0.6891
28 56 67890 芒果干 12345:0.8567,22334:0.7123,55667:0.6543
29 57 ```
30 58  
31   -#### 字段说明
  59 +**字段说明**
32 60 - `item_id`: 商品SKU ID
33 61 - `item_name`: 商品名称
34 62 - `similar_id`: 相似商品ID
35 63 - `score`: 相似度分数(0-1之间,越大越相似)
36 64  
37   -#### 算法差异
38   -| 算法 | 特点 | 适用场景 |
39   -|------|------|---------|
40   -| **Swing** | 基于用户共同行为,发现购买关联 | 详情页"大家都在看" |
41   -| **Session W2V** | 基于会话序列,捕捉浏览顺序 | 详情页"看了又看" |
42   -| **DeepWalk** | 基于图结构,发现深层关系 | 详情页"相关推荐" |
43   -| **Content** | 基于商品属性,类目相似 | 冷启动商品推荐 |
  65 +**特点**
  66 +- 🐍 **易调试**: Python实现,便于开发和调试
  67 +- 🎯 **功能丰富**: 支持时间衰减、日期维度等高级特性
  68 +- 📊 **归一化**: 相似度分数已归一化到0-1区间
  69 +- 📁 **文件位置**: `offline_tasks/output/i2i_*_YYYYMMDD.txt`
  70 +
  71 +#### 1.3 算法对比
  72 +
  73 +| 算法 | 实现语言 | 性能 | 特点 | 适用场景 |
  74 +|------|---------|------|------|---------|
  75 +| **Swing (C++)** | C++ | ⚡⚡⚡ | 高性能,大规模数据 | 生产环境,海量数据 |
  76 +| **Swing (Python)** | Python | ⚡ | 支持日期维度,时间衰减 | 需要高级特性 |
  77 +| **Session W2V** | Python | ⚡ | 基于会话序列 | 详情页"看了又看" |
  78 +| **DeepWalk** | Python | ⚡ | 基于图结构 | 详情页"相关推荐" |
  79 +| **Content** | Python | ⚡⚡ | 基于商品属性 | 冷启动商品推荐 |
  80 +
  81 +#### 1.4 使用建议
  82 +
  83 +**C++ Swing适用场景**:
  84 +- 商品数量 > 50,000
  85 +- 需要快速计算结果
  86 +- 生产环境部署
  87 +- 计算资源有限
  88 +
  89 +**Python Swing适用场景**:
  90 +- 需要时间衰减功能
  91 +- 需要日期维度分析
  92 +- 开发调试阶段
  93 +- 需要灵活调整参数
44 94  
45 95 ### 2. 兴趣点聚合索引
46 96  
... ... @@ -121,6 +171,7 @@ logs/debug/{algorithm_name}_{date}_{time}.log
121 171  
122 172 | 索引类型 | 索引数量 | 单条大小 | 总大小 | 更新频率 |
123 173 |---------|---------|---------|--------|---------|
  174 +| i2i_swing_cpp | ~50,000 | ~400B | ~20MB | 每天 |
124 175 | i2i_swing | ~50,000 | ~500B | ~25MB | 每天 |
125 176 | i2i_session_w2v | ~50,000 | ~500B | ~25MB | 每天 |
126 177 | i2i_deepwalk | ~50,000 | ~500B | ~25MB | 每天 |
... ... @@ -129,7 +180,11 @@ logs/debug/{algorithm_name}_{date}_{time}.log
129 180 | interest_cart | ~10,000 | ~1KB | ~10MB | 每天 |
130 181 | interest_new | ~5,000 | ~1KB | ~5MB | 每天 |
131 182 | interest_global | ~10,000 | ~1KB | ~10MB | 每天 |
132   -| **总计** | **~245,000** | - | **~135MB** | - |
  183 +| **总计** | **~295,000** | - | **~155MB** | - |
  184 +
  185 +**说明**:
  186 +- C++ Swing因为不包含商品名称,单条大小较小
  187 +- 推荐同时使用C++ Swing(生产)和Python Swing(开发)
133 188  
134 189 ## 🎯 质量检查
135 190  
... ...
offline_tasks/doc/系统改进总结-20241017.md
... ... @@ -58,13 +58,17 @@ offline_tasks/run_all.py
58 58 **新增任务流程**:
59 59 ```
60 60 run_all.py 执行顺序:
  61 +前置任务:
61 62 1. fetch_item_attributes.py → 获取商品属性
62 63 2. generate_session.py → 生成用户session文件
63   -3. i2i_swing.py → Swing算法
64   -4. i2i_session_w2v.py → Session W2V
65   -5. i2i_deepwalk.py → DeepWalk
66   -6. i2i_content_similar.py → 内容相似度
67   -7. interest_aggregation.py → 兴趣聚合
  64 +3. run_cpp_swing() → C++ Swing算法(使用session)
  65 +
  66 +核心算法任务:
  67 +4. i2i_swing.py → Python Swing算法(启用日期维度)
  68 +5. i2i_session_w2v.py → Session W2V
  69 +6. i2i_deepwalk.py → DeepWalk
  70 +7. i2i_content_similar.py → 内容相似度
  71 +8. interest_aggregation.py → 兴趣聚合
68 72 ```
69 73  
70 74 **好处**:
... ... @@ -259,10 +263,14 @@ python3 scripts/i2i_swing.py --lookback_days 730 --use_daily_session --debug
259 263 ### C++ Swing算法
260 264  
261 265 ```bash
  266 +# C++ Swing现已集成到run_all.py,会自动在session生成后执行
  267 +# 如需单独运行:
262 268 cd /home/tw/recommendation/collaboration
263   -
264   -# session文件自动生成后,运行Swing
265 269 bash run.sh
  270 +
  271 +# 查看结果
  272 +ls -lh output/swing_similar*.txt
  273 +cat output/swing_similar_readable.txt | head -20
266 274 ```
267 275  
268 276 ### 查看文档
... ... @@ -312,13 +320,71 @@ recommendation/
312 320  
313 321 ---
314 322  
  323 +## 🔧 C++ Swing算法集成
  324 +
  325 +### 改进内容
  326 +
  327 +**之前**: C++ Swing需要手动切换目录运行
  328 +```bash
  329 +cd /home/tw/recommendation/collaboration
  330 +bash run.sh
  331 +```
  332 +
  333 +**现在**: 已集成到`run_all.py`,自动执行
  334 +
  335 +### 执行流程
  336 +
  337 +```
  338 +run_all.py:
  339 +1. fetch_item_attributes.py
  340 +2. generate_session.py ← 生成session.txt.YYYYMMDD.cpp
  341 +3. run_cpp_swing() ← 自动调用 collaboration/run.sh
  342 + ├─ 编译C++程序
  343 + ├─ 读取session文件
  344 + ├─ 运行Swing算法
  345 + ├─ 合并多线程结果
  346 + └─ 生成可读版本(自动添加商品名)
  347 +4. 后续Python任务...
  348 +```
  349 +
  350 +### 输出结果
  351 +
  352 +C++ Swing执行后,结果保存在:
  353 +```
  354 +collaboration/output_YYYYMMDD/
  355 +├── sim_matrx.* # 多线程输出
  356 +├── swing_similar.txt # 合并结果(ID格式)
  357 +└── swing_similar_readable.txt # 可读版本(ID:名称格式)
  358 +
  359 +collaboration/output -> output_YYYYMMDD # 软链接
  360 +```
  361 +
  362 +### 优势
  363 +
  364 +- ✅ **自动化**: 无需手动切换目录
  365 +- ✅ **依赖管理**: 确保session文件已生成
  366 +- ✅ **错误处理**: 失败不影响后续任务
  367 +- ✅ **日志统一**: 所有任务日志在同一个文件
  368 +- ✅ **性能**: C++版本比Python版快10-100倍
  369 +
  370 +### 单独运行
  371 +
  372 +如需单独运行C++ Swing(不执行其他任务):
  373 +```bash
  374 +cd /home/tw/recommendation/collaboration
  375 +bash run.sh
  376 +```
  377 +
  378 +---
  379 +
315 380 ## 🎯 核心改进点总结
316 381  
317 382 1. **✅ 性能优化**: 减少80-90%的数据库查询
318 383 2. **✅ 架构优化**: 前置任务解耦,数据准备与算法分离
319 384 3. **✅ 功能增强**: Swing算法支持日期维度
320   -4. **✅ 文档规范**: 统一管理,中文命名,清晰索引
321   -5. **✅ 代码质量**: 无Linter错误,统一编码规范
  385 +4. **✅ 集成优化**: C++ Swing集成到统一流程
  386 +5. **✅ 文档规范**: 统一管理,中文命名,清晰索引
  387 +6. **✅ 代码质量**: 无Linter错误,统一编码规范
322 388  
323 389 ---
324 390  
... ...
offline_tasks/run_all.py
... ... @@ -79,6 +79,52 @@ def run_script(script_name, args=None):
79 79 return False
80 80  
81 81  
  82 +def run_cpp_swing():
  83 + """
  84 + 运行C++ Swing算法
  85 +
  86 + Returns:
  87 + bool: 是否成功
  88 + """
  89 + collaboration_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'collaboration')
  90 + run_sh_path = os.path.join(collaboration_dir, 'run.sh')
  91 +
  92 + if not os.path.exists(run_sh_path):
  93 + logger.error(f"C++ Swing script not found: {run_sh_path}")
  94 + return False
  95 +
  96 + logger.info(f"Running C++ Swing: bash {run_sh_path}")
  97 +
  98 + try:
  99 + result = subprocess.run(
  100 + ['bash', run_sh_path],
  101 + cwd=collaboration_dir,
  102 + check=True,
  103 + capture_output=True,
  104 + text=True
  105 + )
  106 + logger.info("C++ Swing algorithm completed successfully")
  107 + # 输出部分日志
  108 + output_lines = result.stdout.split('\n')
  109 + for line in output_lines[-20:]: # 输出最后20行
  110 + if line.strip():
  111 + logger.info(f" {line}")
  112 + return True
  113 + except subprocess.CalledProcessError as e:
  114 + logger.error(f"C++ Swing failed with return code {e.returncode}")
  115 + logger.error(f"Error output: {e.stderr}")
  116 + # 输出部分stdout以便调试
  117 + if e.stdout:
  118 + logger.error("Stdout output:")
  119 + for line in e.stdout.split('\n')[-20:]:
  120 + if line.strip():
  121 + logger.error(f" {line}")
  122 + return False
  123 + except Exception as e:
  124 + logger.error(f"Unexpected error running C++ Swing: {e}")
  125 + return False
  126 +
  127 +
82 128 def main():
83 129 parser = argparse.ArgumentParser(description='Run all offline recommendation tasks')
84 130 parser.add_argument('--debug', action='store_true',
... ... @@ -124,9 +170,22 @@ def main():
124 170 else:
125 171 logger.error("生成session文件失败")
126 172  
  173 + # 前置任务3: 运行C++ Swing算法
  174 + logger.info("\n" + "="*80)
  175 + logger.info("前置任务3: 运行C++ Swing算法(基于session文件)")
  176 + logger.info("="*80)
  177 + total_count += 1
  178 + if run_cpp_swing():
  179 + success_count += 1
  180 + logger.info("✓ C++ Swing算法执行成功")
  181 + logger.info(" 结果文件: collaboration/output/swing_similar.txt")
  182 + logger.info(" 可读文件: collaboration/output/swing_similar_readable.txt")
  183 + else:
  184 + logger.error("C++ Swing算法执行失败,但不影响其他任务继续")
  185 +
127 186 # i2i 行为相似任务
128 187 logger.info("\n" + "="*80)
129   - logger.info("Task 1: Running Swing algorithm for i2i similarity")
  188 + logger.info("Task 1: Running Python Swing algorithm for i2i similarity")
130 189 logger.info("="*80)
131 190 total_count += 1
132 191 script_args = [
... ...