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 ```bash 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 ```bash 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 ```bash 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 ```bash 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,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,6 +20,7 @@
20 20
21 | 模块名称 | 源数据地址 | 格式描述 | RedisKey模板 | RedisValue格式 | TTL | 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 | **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_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_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_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,12 +35,42 @@
34 35
35 ### 1. i2i相似度索引 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 12345 香蕉干 67890:0.8567,11223:0.7234,44556:0.6891 70 12345 香蕉干 67890:0.8567,11223:0.7234,44556:0.6891
40 ``` 71 ```
41 72
42 -#### Redis存储 73 +**Redis存储**
43 74
44 **Key**: `item:similar:swing:12345` 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,19 +86,35 @@ value = json.dumps([[67890, 0.8567], [11223, 0.7234], [44556, 0.6891]])
55 # 存储: "[[67890,0.8567],[11223,0.7234],[44556,0.6891]]" 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 ```python 96 ```python
60 import redis 97 import redis
61 import json 98 import json
62 99
63 r = redis.Redis(host='localhost', port=6379, db=0) 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 similar_items = json.loads(r.get('item:similar:swing:12345')) 107 similar_items = json.loads(r.get('item:similar:swing:12345'))
67 # 返回: [[67890, 0.8567], [11223, 0.7234], [44556, 0.6891]] 108 # 返回: [[67890, 0.8567], [11223, 0.7234], [44556, 0.6891]]
68 109
69 # 获取Top5相似商品 110 # 获取Top5相似商品
70 top_5 = similar_items[:5] 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 ### 2. 兴趣点聚合索引 120 ### 2. 兴趣点聚合索引
@@ -113,10 +160,55 @@ top_10 = hot_items[:10] @@ -113,10 +160,55 @@ top_10 = hot_items[:10]
113 160
114 ### 1. 加载i2i索引 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 ```python 208 ```python
117 def load_i2i_index(file_path, algorithm_name, redis_client, expire_seconds=604800): 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 Args: 213 Args:
122 file_path: 索引文件路径 214 file_path: 索引文件路径
@@ -134,6 +226,7 @@ def load_i2i_index(file_path, algorithm_name, redis_client, expire_seconds=60480 @@ -134,6 +226,7 @@ def load_i2i_index(file_path, algorithm_name, redis_client, expire_seconds=60480
134 continue 226 continue
135 227
136 item_id = parts[0] 228 item_id = parts[0]
  229 + # item_name = parts[1] # 可选:如果需要缓存商品名
137 similar_str = parts[2] # similar_id1:score1,similar_id2:score2,... 230 similar_str = parts[2] # similar_id1:score1,similar_id2:score2,...
138 231
139 # 解析相似商品 232 # 解析相似商品
offline_tasks/doc/离线索引数据规范.md
@@ -4,6 +4,7 @@ @@ -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 | **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 | **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 | **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 | **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 | **i2i_deepwalk** | `python3 scripts/i2i_deepwalk.py` | 每天 | `output/i2i_deepwalk_YYYYMMDD.txt` | `item_id \t item_name \t similar_id1:score1,similar_id2:score2,...` | 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,30 +18,79 @@
17 18
18 ### 1. i2i相似度索引 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 item_id \t item_name \t similar_id1:score1,similar_id2:score2,... 50 item_id \t item_name \t similar_id1:score1,similar_id2:score2,...
23 ``` 51 ```
24 52
25 -#### 示例 53 +**示例**
26 ``` 54 ```
27 12345 香蕉干 67890:0.8567,11223:0.7234,44556:0.6891 55 12345 香蕉干 67890:0.8567,11223:0.7234,44556:0.6891
28 67890 芒果干 12345:0.8567,22334:0.7123,55667:0.6543 56 67890 芒果干 12345:0.8567,22334:0.7123,55667:0.6543
29 ``` 57 ```
30 58
31 -#### 字段说明 59 +**字段说明**
32 - `item_id`: 商品SKU ID 60 - `item_id`: 商品SKU ID
33 - `item_name`: 商品名称 61 - `item_name`: 商品名称
34 - `similar_id`: 相似商品ID 62 - `similar_id`: 相似商品ID
35 - `score`: 相似度分数(0-1之间,越大越相似) 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 ### 2. 兴趣点聚合索引 95 ### 2. 兴趣点聚合索引
46 96
@@ -121,6 +171,7 @@ logs/debug/{algorithm_name}_{date}_{time}.log @@ -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 | i2i_swing | ~50,000 | ~500B | ~25MB | 每天 | 175 | i2i_swing | ~50,000 | ~500B | ~25MB | 每天 |
125 | i2i_session_w2v | ~50,000 | ~500B | ~25MB | 每天 | 176 | i2i_session_w2v | ~50,000 | ~500B | ~25MB | 每天 |
126 | i2i_deepwalk | ~50,000 | ~500B | ~25MB | 每天 | 177 | i2i_deepwalk | ~50,000 | ~500B | ~25MB | 每天 |
@@ -129,7 +180,11 @@ logs/debug/{algorithm_name}_{date}_{time}.log @@ -129,7 +180,11 @@ logs/debug/{algorithm_name}_{date}_{time}.log
129 | interest_cart | ~10,000 | ~1KB | ~10MB | 每天 | 180 | interest_cart | ~10,000 | ~1KB | ~10MB | 每天 |
130 | interest_new | ~5,000 | ~1KB | ~5MB | 每天 | 181 | interest_new | ~5,000 | ~1KB | ~5MB | 每天 |
131 | interest_global | ~10,000 | ~1KB | ~10MB | 每天 | 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,13 +58,17 @@ offline_tasks/run_all.py
58 **新增任务流程**: 58 **新增任务流程**:
59 ``` 59 ```
60 run_all.py 执行顺序: 60 run_all.py 执行顺序:
  61 +前置任务:
61 1. fetch_item_attributes.py → 获取商品属性 62 1. fetch_item_attributes.py → 获取商品属性
62 2. generate_session.py → 生成用户session文件 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,10 +263,14 @@ python3 scripts/i2i_swing.py --lookback_days 730 --use_daily_session --debug
259 ### C++ Swing算法 263 ### C++ Swing算法
260 264
261 ```bash 265 ```bash
  266 +# C++ Swing现已集成到run_all.py,会自动在session生成后执行
  267 +# 如需单独运行:
262 cd /home/tw/recommendation/collaboration 268 cd /home/tw/recommendation/collaboration
263 -  
264 -# session文件自动生成后,运行Swing  
265 bash run.sh 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,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 1. **✅ 性能优化**: 减少80-90%的数据库查询 382 1. **✅ 性能优化**: 减少80-90%的数据库查询
318 2. **✅ 架构优化**: 前置任务解耦,数据准备与算法分离 383 2. **✅ 架构优化**: 前置任务解耦,数据准备与算法分离
319 3. **✅ 功能增强**: Swing算法支持日期维度 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,6 +79,52 @@ def run_script(script_name, args=None):
79 return False 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 def main(): 128 def main():
83 parser = argparse.ArgumentParser(description='Run all offline recommendation tasks') 129 parser = argparse.ArgumentParser(description='Run all offline recommendation tasks')
84 parser.add_argument('--debug', action='store_true', 130 parser.add_argument('--debug', action='store_true',
@@ -124,9 +170,22 @@ def main(): @@ -124,9 +170,22 @@ def main():
124 else: 170 else:
125 logger.error("生成session文件失败") 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 # i2i 行为相似任务 186 # i2i 行为相似任务
128 logger.info("\n" + "="*80) 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 logger.info("="*80) 189 logger.info("="*80)
131 total_count += 1 190 total_count += 1
132 script_args = [ 191 script_args = [