2.0.0 Beta 2: Fix docs folder
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
## basic、个人基础数据特征
|
||||
1. 平均Rating(每局)
|
||||
2. 平均KD值(每局)
|
||||
3. 平均KAST(每局)
|
||||
4. 平均RWS(每局)
|
||||
5. 每局爆头击杀数
|
||||
6. 爆头率(爆头击杀/总击杀)
|
||||
7. 每局首杀次数
|
||||
8. 每局首死次数
|
||||
9. 首杀率(首杀次数/首遇交火次数)
|
||||
10. 首死率(首死次数/首遇交火次数)
|
||||
11. 每局2+杀/3+杀/4+杀/5杀次数(多杀)
|
||||
12. 连续击杀累计次数(连杀)
|
||||
15. **(New) 助攻次数 (assisted_kill)**
|
||||
16. **(New) 完美击杀 (perfect_kill)**
|
||||
17. **(New) 复仇击杀 (revenge_kill)**
|
||||
18. **(New) AWP击杀数 (awp_kill)**
|
||||
19. **(New) 总跳跃次数 (jump_count)**
|
||||
|
||||
---
|
||||
|
||||
## 挖掘能力维度:
|
||||
### 1、时间稳定序列特征 STA
|
||||
1. 近30局平均Rating(长期Rating)
|
||||
2. 胜局平均Rating
|
||||
3. 败局平均Rating
|
||||
4. Rating波动系数(近10局Rating计算)
|
||||
5. 同一天内比赛时长与Rating相关性(每2小时Rating变化率)
|
||||
6. 连续比赛局数与表现衰减率(如第5局后vs前4局的KD变化)
|
||||
|
||||
### 2、局内对抗能力特征 BAT
|
||||
1. 对位最高Rating对手的KD差(自身击杀-被该对手击杀)
|
||||
2. 对位最低Rating对手的KD差(自身击杀-被该对手击杀)
|
||||
3. 对位所有对手的胜率(自身击杀>被击杀的对手占比)
|
||||
4. 平均对枪成功率(对所有对手的对枪成功率求平均)
|
||||
5. 与单个对手的交火次数(相遇频率)
|
||||
* ~~A. 对枪反应时间(遇敌到开火平均时长,需录像解析)~~ (Phase 5)
|
||||
* B. 近/中/远距对枪占比及各自胜率 (仅 Classic 可行)
|
||||
|
||||
|
||||
### 3、高压场景表现特征 HPS (High Pressure Scenario)
|
||||
1. 1v1/1v2/1v3+残局胜率
|
||||
2. 赛点(12-12、12-11等)残局胜率
|
||||
3. 人数劣势时的平均存活时间/击杀数(少打多能力)
|
||||
4. 队伍连续丢3+局后自身首杀率(压力下突破能力)
|
||||
5. 队伍连续赢3+局后自身2+杀率(顺境多杀能力)
|
||||
6. 受挫后状态下滑率(被刀/被虐泉后3回合内Rating下降值)
|
||||
7. 起势后状态提升率(关键残局/多杀后3回合内Rating上升值)
|
||||
8. 翻盘阶段KD提升值(同上场景下,自身KD与平均差值)
|
||||
9. 连续丢分抗压性(连续丢4+局时,自身KD与平均差值)
|
||||
|
||||
### 4、手枪局专项特征 PTL (Pistol Round)
|
||||
1. 手枪局首杀次数
|
||||
2. 手枪局2+杀次数(多杀)
|
||||
3. 手枪局连杀次数
|
||||
4. 参与的手枪局胜率(round1 round13)
|
||||
5. 手枪类武器KD
|
||||
6. 手枪局道具使用效率(烟雾/闪光帮助队友击杀数/投掷次数)
|
||||
|
||||
### 5、阵营倾向(T/CT)特征 T/CT
|
||||
1. CT方平均Rating
|
||||
2. T方平均Rating
|
||||
3. CT方首杀率
|
||||
4. T方首杀率
|
||||
5. CT方守点成功率(负责区域未被突破的回合占比)
|
||||
6. T方突破成功率(成功突破敌方首道防线的回合占比)
|
||||
7. CT/T方KD差值(CT KD - T KD)
|
||||
8. **(New) 下包次数 (planted_bomb)**
|
||||
9. **(New) 拆包次数 (defused_bomb)**
|
||||
|
||||
### 6、道具特征 UTIL
|
||||
1. 手雷伤害 (`throw_harm`)
|
||||
2. 闪光致盲时间 (`flash_time`, `flash_enemy_time`, `flash_team_time`)
|
||||
3. 闪光致盲人数 (`flash_enemy`, `flash_team`)
|
||||
4. 每局平均道具数量与使用率(烟雾、闪光、燃烧弹、手雷)
|
||||
|
||||
|
||||
### 手调1.、指挥手动调节因子(主观评价,0-10分)
|
||||
1. 沟通量(信息传递频率与有效性)
|
||||
2. 辅助决策能力(半区决策建议的合理性)
|
||||
3. 团队协作倾向(主动帮助队友的频率)
|
||||
4. 打法激进程度(进攻倾向,0为保守,10为激进)
|
||||
5. 执行力(对指挥战术的落实程度)
|
||||
6. 临场应变力(突发情况的自主处理能力)
|
||||
7. 氛围带动性(团队士气影响,正向/负向)
|
||||
@@ -0,0 +1,280 @@
|
||||
# 玩家Profile界面展示清单。
|
||||
|
||||
> **文档日期**: 2026-01-28
|
||||
> **适用范围**: YRTV Player Profile System
|
||||
> **版本**: v1.0
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
1. [完整数据清单](#1-完整数据清单)
|
||||
---
|
||||
|
||||
## 1. 完整数据清单
|
||||
|
||||
### 1.1 数据仪表板区域 (Dashboard - Top Section)
|
||||
|
||||
| 显示标签 | 指标键 | 计算方法 | L3列名 | L2来源表 | UI位置 |
|
||||
|---------|--------|---------|--------|---------|--------|
|
||||
| Rating (评分) | `basic_avg_rating` | `AVG(rating)` | `basic_avg_rating` | `fact_match_players.rating` | Dashboard Card 1 |
|
||||
| K/D Ratio (击杀比) | `basic_avg_kd` | `AVG(kd_ratio)` | `basic_avg_kd` | `fact_match_players.kd_ratio` | Dashboard Card 2 |
|
||||
| ADR (场均伤害) | `basic_avg_adr` | `AVG(adr)` | `basic_avg_adr` | `fact_match_players.adr` | Dashboard Card 3 |
|
||||
| KAST (贡献率) | `basic_avg_kast` | `AVG(kast)` | `basic_avg_kast` | `fact_match_players.kast` | Dashboard Card 4 |
|
||||
|
||||
### 1.2 图表区域 (Charts Section)
|
||||
|
||||
#### 1.2.1 六维雷达图 (Radar Chart)
|
||||
|
||||
| 维度名称 | 指标键 | 计算方法 | L3列名 | UI位置 |
|
||||
|---------|--------|---------|--------|--------|
|
||||
| Aim (BAT) | `score_bat` | 加权标准化: 25% Rating + 20% KD + 15% ADR + 10% DuelWin + 10% HighEloKD + 20% 3K | `score_bat` | Radar Axis 1 |
|
||||
| Clutch (HPS) | `score_hps` | 加权标准化: 25% 1v3+ + 20% MatchPtWin + 20% ComebackKD + 15% PressureEntry + 20% Rating | `score_hps` | Radar Axis 2 |
|
||||
| Pistol (PTL) | `score_ptl` | 加权标准化: 30% PistolKills + 30% PistolWin + 20% PistolKD + 20% PistolUtil | `score_ptl` | Radar Axis 3 |
|
||||
| Defense (SIDE) | `score_tct` | 加权标准化: 35% CT_Rating + 35% T_Rating + 15% CT_FK + 15% T_FK | `score_tct` | Radar Axis 4 |
|
||||
| Util (UTIL) | `score_util` | 加权标准化: 35% UsageRate + 25% NadeDmg + 20% FlashTime + 20% FlashEnemy | `score_util` | Radar Axis 5 |
|
||||
| Stability (STA) | `score_sta` | 加权标准化: 30% (100-Volatility) + 30% LossRating + 20% WinRating + 10% TimeCorr | `score_sta` | Radar Axis 6 |
|
||||
| Economy (ECO) | `score_eco` | 加权标准化: 50% Dmg/$1k + 50% EcoKPR | `score_eco` | Radar Axis 7 |
|
||||
| Pace (PACE) | `score_pace` | 加权标准化: 50% (100-FirstContactTime) + 50% TradeKillRate | `score_pace` | Radar Axis 8 |
|
||||
|
||||
#### 1.2.2 趋势图 (Trend Chart)
|
||||
|
||||
| 数据项 | 来源 | 计算方法 | UI位置 |
|
||||
|-------|------|---------|--------|
|
||||
| Rating走势 | L2: `fact_match_players` | 按时间排序的`rating`值(最近20场) | Line Chart - Main Data |
|
||||
| Carry线(1.5) | 静态基准线 | 固定值 1.5 | Line Chart - Reference |
|
||||
| Normal线(1.0) | 静态基准线 | 固定值 1.0 | Line Chart - Reference |
|
||||
| Poor线(0.6) | 静态基准线 | 固定值 0.6 | Line Chart - Reference |
|
||||
|
||||
### 1.3 详细数据面板 (Detailed Stats Panel)
|
||||
|
||||
#### 1.3.1 核心性能指标 (Core Performance)
|
||||
|
||||
| 显示标签 | 指标键 | 计算方法 | L3列名 | L2来源 | UI行位置 |
|
||||
|---------|--------|---------|--------|--------|---------|
|
||||
| Rating (评分) | `basic_avg_rating` | `AVG(rating)` | `basic_avg_rating` | `fact_match_players.rating` | Row 1, Col 1 |
|
||||
| KD Ratio (击杀比) | `basic_avg_kd` | `AVG(kd_ratio)` | `basic_avg_kd` | `fact_match_players.kd_ratio` | Row 1, Col 2 |
|
||||
| KAST (贡献率) | `basic_avg_kast` | `AVG(kast)` | `basic_avg_kast` | `fact_match_players.kast` | Row 1, Col 3 |
|
||||
| RWS (每局得分) | `basic_avg_rws` | `AVG(rws)` | `basic_avg_rws` | `fact_match_players.rws` | Row 1, Col 4 |
|
||||
| ADR (场均伤害) | `basic_avg_adr` | `AVG(adr)` | `basic_avg_adr` | `fact_match_players.adr` | Row 1, Col 5 |
|
||||
|
||||
#### 1.3.2 枪法与战斗能力 (Gunfight)
|
||||
|
||||
| 显示标签 | 指标键 | 计算方法 | L3列名 | L2来源 | UI行位置 |
|
||||
|---------|--------|---------|--------|--------|---------|
|
||||
| Avg HS (场均爆头) | `basic_avg_headshot_kills` | `SUM(headshot_count) / matches` | `basic_avg_headshot_kills` | `fact_match_players.headshot_count` | Row 2, Col 1 |
|
||||
| HS Rate (爆头率) | `basic_headshot_rate` | `SUM(headshot_count) / SUM(kills)` | `basic_headshot_rate` | `fact_match_players.headshot_count, kills` | Row 2, Col 2 |
|
||||
| Assists (场均助攻) | `basic_avg_assisted_kill` | `SUM(assisted_kill) / matches` | `basic_avg_assisted_kill` | `fact_match_players.assisted_kill` | Row 2, Col 3 |
|
||||
| AWP Kills (狙击击杀) | `basic_avg_awp_kill` | `SUM(awp_kill) / matches` | `basic_avg_awp_kill` | `fact_match_players.awp_kill` | Row 2, Col 4 |
|
||||
| Jumps (场均跳跃) | `basic_avg_jump_count` | `SUM(jump_count) / matches` | `basic_avg_jump_count` | `fact_match_players.jump_count` | Row 2, Col 5 |
|
||||
| Knife Kills (场均刀杀) | `basic_avg_knife_kill` | `COUNT(knife_kills) / matches` | `basic_avg_knife_kill` | `fact_round_events` (weapon=knife) | Row 2, Col 6 |
|
||||
| Zeus Kills (电击枪杀) | `basic_avg_zeus_kill` | `COUNT(zeus_kills) / matches` | `basic_avg_zeus_kill` | `fact_round_events` (weapon=zeus) | Row 2, Col 7 |
|
||||
| Zeus Buy% (起电击枪) | `basic_zeus_pick_rate` | `AVG(has_zeus)` | `basic_zeus_pick_rate` | `fact_round_player_economy.has_zeus` | Row 2, Col 8 |
|
||||
|
||||
#### 1.3.3 目标控制 (Objective)
|
||||
|
||||
| 显示标签 | 指标键 | 计算方法 | L3列名 | L2来源 | UI行位置 |
|
||||
|---------|--------|---------|--------|--------|---------|
|
||||
| MVP (最有价值) | `basic_avg_mvps` | `SUM(mvp_count) / matches` | `basic_avg_mvps` | `fact_match_players.mvp_count` | Row 3, Col 1 |
|
||||
| Plants (下包) | `basic_avg_plants` | `SUM(planted_bomb) / matches` | `basic_avg_plants` | `fact_match_players.planted_bomb` | Row 3, Col 2 |
|
||||
| Defuses (拆包) | `basic_avg_defuses` | `SUM(defused_bomb) / matches` | `basic_avg_defuses` | `fact_match_players.defused_bomb` | Row 3, Col 3 |
|
||||
| Flash Assist (闪光助攻) | `basic_avg_flash_assists` | `SUM(flash_assists) / matches` | `basic_avg_flash_assists` | `fact_match_players.flash_assists` | Row 3, Col 4 |
|
||||
|
||||
#### 1.3.4 开局能力 (Opening Impact)
|
||||
|
||||
| 显示标签 | 指标键 | 计算方法 | L3列名 | L2来源 | UI行位置 |
|
||||
|---------|--------|---------|--------|--------|---------|
|
||||
| First Kill (场均首杀) | `basic_avg_first_kill` | `SUM(first_kill) / matches` | `basic_avg_first_kill` | `fact_match_players.first_kill` | Row 4, Col 1 |
|
||||
| First Death (场均首死) | `basic_avg_first_death` | `SUM(first_death) / matches` | `basic_avg_first_death` | `fact_match_players.first_death` | Row 4, Col 2 |
|
||||
| FK Rate (首杀率) | `basic_first_kill_rate` | `FK / (FK + FD)` | `basic_first_kill_rate` | Calculated from FK/FD | Row 4, Col 3 |
|
||||
| FD Rate (首死率) | `basic_first_death_rate` | `FD / (FK + FD)` | `basic_first_death_rate` | Calculated from FK/FD | Row 4, Col 4 |
|
||||
|
||||
#### 1.3.5 多杀表现 (Multi-Frag Performance)
|
||||
|
||||
| 显示标签 | 指标键 | 计算方法 | L3列名 | L2来源 | UI行位置 |
|
||||
|---------|--------|---------|--------|--------|---------|
|
||||
| 2K Rounds (双杀) | `basic_avg_kill_2` | `SUM(kill_2) / matches` | `basic_avg_kill_2` | `fact_match_players.kill_2` | Row 5, Col 1 |
|
||||
| 3K Rounds (三杀) | `basic_avg_kill_3` | `SUM(kill_3) / matches` | `basic_avg_kill_3` | `fact_match_players.kill_3` | Row 5, Col 2 |
|
||||
| 4K Rounds (四杀) | `basic_avg_kill_4` | `SUM(kill_4) / matches` | `basic_avg_kill_4` | `fact_match_players.kill_4` | Row 5, Col 3 |
|
||||
| 5K Rounds (五杀) | `basic_avg_kill_5` | `SUM(kill_5) / matches` | `basic_avg_kill_5` | `fact_match_players.kill_5` | Row 5, Col 4 |
|
||||
|
||||
#### 1.3.6 特殊击杀 (Special Stats)
|
||||
|
||||
| 显示标签 | 指标键 | 计算方法 | L3列名 | L2来源 | UI行位置 |
|
||||
|---------|--------|---------|--------|--------|---------|
|
||||
| Perfect Kills (无伤杀) | `basic_avg_perfect_kill` | `SUM(perfect_kill) / matches` | `basic_avg_perfect_kill` | `fact_match_players.perfect_kill` | Row 6, Col 1 |
|
||||
| Revenge Kills (复仇杀) | `basic_avg_revenge_kill` | `SUM(revenge_kill) / matches` | `basic_avg_revenge_kill` | `fact_match_players.revenge_kill` | Row 6, Col 2 |
|
||||
| 交火补枪率 | `trade_kill_percentage` | `TradeKills / TotalKills * 100` | N/A (计算自L2) | `fact_round_events` (self-join) | Row 6, Col 3 |
|
||||
|
||||
### 1.4 特殊击杀与时机分析 (Special Kills & Timing)
|
||||
|
||||
#### 1.4.1 战术智商击杀 (Special Kill Scenarios)
|
||||
|
||||
| 显示标签 | 指标键 | 计算方法 | L3列名 | L2来源 | UI位置 |
|
||||
|---------|--------|---------|--------|--------|--------|
|
||||
| Wallbang Kills (穿墙) | `special_wallbang_kills` | `COUNT(is_wallbang=1)` | `special_wallbang_kills` | `fact_round_events.is_wallbang` | Special Grid 1 |
|
||||
| Wallbang Rate (穿墙率) | `special_wallbang_rate` | `WallbangKills / TotalKills` | `special_wallbang_rate` | Calculated | Special Grid 2 |
|
||||
| Smoke Kills (穿烟) | `special_smoke_kills` | `COUNT(is_through_smoke=1)` | `special_smoke_kills` | `fact_round_events.is_through_smoke` | Special Grid 3 |
|
||||
| Smoke Kill Rate (穿烟率) | `special_smoke_kill_rate` | `SmokeKills / TotalKills` | `special_smoke_kill_rate` | Calculated | Special Grid 4 |
|
||||
| Blind Kills (致盲击杀) | `special_blind_kills` | `COUNT(is_blind=1)` | `special_blind_kills` | `fact_round_events.is_blind` | Special Grid 5 |
|
||||
| Blind Kill Rate (致盲率) | `special_blind_kill_rate` | `BlindKills / TotalKills` | `special_blind_kill_rate` | Calculated | Special Grid 6 |
|
||||
| NoScope Kills (盲狙) | `special_noscope_kills` | `COUNT(is_noscope=1)` | `special_noscope_kills` | `fact_round_events.is_noscope` | Special Grid 7 |
|
||||
| NoScope Rate (盲狙率) | `special_noscope_rate` | `NoScopeKills / AWPKills` | `special_noscope_rate` | Calculated | Special Grid 8 |
|
||||
| High IQ Score (智商评分) | `special_high_iq_score` | 加权评分(0-100): Wallbang*3 + Smoke*2 + Blind*1.5 + NoScope*2 | `special_high_iq_score` | Calculated | Special Grid 9 |
|
||||
|
||||
#### 1.4.2 回合节奏分析 (Round Timing Analysis)
|
||||
|
||||
| 显示标签 | 指标键 | 计算方法 | L3列名 | L2来源 | UI位置 |
|
||||
|---------|--------|---------|--------|--------|--------|
|
||||
| Early Kills (前30s) | `timing_early_kills` | `COUNT(event_time < 30)` | `timing_early_kills` | `fact_round_events.event_time` | Timing Grid 1 |
|
||||
| Mid Kills (30-60s) | `timing_mid_kills` | `COUNT(30 <= event_time < 60)` | `timing_mid_kills` | `fact_round_events.event_time` | Timing Grid 2 |
|
||||
| Late Kills (60s+) | `timing_late_kills` | `COUNT(event_time >= 60)` | `timing_late_kills` | `fact_round_events.event_time` | Timing Grid 3 |
|
||||
| Avg Kill Time (平均击杀时间) | `timing_avg_kill_time` | `AVG(event_time)` for kills | `timing_avg_kill_time` | `fact_round_events.event_time` | Timing Grid 4 |
|
||||
| Early Aggression (前期进攻) | `timing_early_aggression_rate` | `EarlyKills / TotalKills` | `timing_early_aggression_rate` | Calculated | Timing Grid 5 |
|
||||
| Early Deaths (前30s死) | `timing_early_deaths` | `COUNT(death_time < 30)` | `timing_early_deaths` | `fact_round_events.event_time` | Timing Grid 6 |
|
||||
| Mid Deaths (30-60s死) | `timing_mid_deaths` | `COUNT(30 <= death_time < 60)` | `timing_mid_deaths` | `fact_round_events.event_time` | Timing Grid 7 |
|
||||
| Late Deaths (60s+死) | `timing_late_deaths` | `COUNT(death_time >= 60)` | `timing_late_deaths` | `fact_round_events.event_time` | Timing Grid 8 |
|
||||
| Avg Death Time (平均死亡时间) | `timing_avg_death_time` | `AVG(event_time)` for deaths | `timing_avg_death_time` | `fact_round_events.event_time` | Timing Grid 9 |
|
||||
| Early Death Rate (前期死亡) | `timing_early_death_rate` | `EarlyDeaths / TotalDeaths` | `timing_early_death_rate` | Calculated | Timing Grid 10 |
|
||||
|
||||
### 1.5 深层能力维度 (Deep Capabilities)
|
||||
|
||||
#### 1.5.1 稳定性与枪法 (STA & BAT)
|
||||
|
||||
| 显示标签 | 指标键 | 计算方法 | L3列名 | L2来源 | UI位置 |
|
||||
|---------|--------|---------|--------|--------|--------|
|
||||
| Last 30 Rating (近30场) | `sta_last_30_rating` | `AVG(rating)` for last 30 matches | `sta_last_30_rating` | `fact_match_players.rating` | Deep Section 1 |
|
||||
| Win Rating (胜局) | `sta_win_rating` | `AVG(rating WHERE is_win=1)` | `sta_win_rating` | `fact_match_players.rating, is_win` | Deep Section 2 |
|
||||
| Loss Rating (败局) | `sta_loss_rating` | `AVG(rating WHERE is_win=0)` | `sta_loss_rating` | `fact_match_players.rating, is_win` | Deep Section 3 |
|
||||
| Volatility (波动) | `sta_rating_volatility` | `STDDEV(rating)` for last 10 matches | `sta_rating_volatility` | `fact_match_players.rating` | Deep Section 4 |
|
||||
| Time Corr (耐力) | `sta_time_rating_corr` | `CORR(duration, rating)` | `sta_time_rating_corr` | `fact_matches.duration, rating` | Deep Section 5 |
|
||||
| High Elo KD Diff (高分抗压) | `bat_kd_diff_high_elo` | `AVG(kd WHERE elo > player_avg_elo)` | `bat_kd_diff_high_elo` | `fact_match_teams.group_origin_elo` | Deep Section 6 |
|
||||
| Duel Win% (对枪胜率) | `bat_avg_duel_win_rate` | `entry_kills / (entry_kills + entry_deaths)` | `bat_avg_duel_win_rate` | `fact_match_players.entry_kills/deaths` | Deep Section 7 |
|
||||
|
||||
#### 1.5.2 残局与手枪 (HPS & PTL)
|
||||
|
||||
| 显示标签 | 指标键 | 计算方法 | L3列名 | L2来源 | UI位置 |
|
||||
|---------|--------|---------|--------|--------|--------|
|
||||
| Avg 1v1 (场均1v1) | `hps_clutch_win_rate_1v1` | `SUM(clutch_1v1) / matches` | `hps_clutch_win_rate_1v1` | `fact_match_players.clutch_1v1` | Deep Section 8 |
|
||||
| Avg 1v3+ (场均1v3+) | `hps_clutch_win_rate_1v3_plus` | `SUM(clutch_1v3+1v4+1v5) / matches` | `hps_clutch_win_rate_1v3_plus` | `fact_match_players.clutch_1v3/4/5` | Deep Section 9 |
|
||||
| Match Pt Win% (赛点胜率) | `hps_match_point_win_rate` | Win rate when either team at 12 or 15 | `hps_match_point_win_rate` | `fact_rounds` (score calculation) | Deep Section 10 |
|
||||
| Pressure Entry (逆风首杀) | `hps_pressure_entry_rate` | `entry_kills / rounds` in losing matches | `hps_pressure_entry_rate` | `fact_match_players` (is_win=0) | Deep Section 11 |
|
||||
| Comeback KD (翻盘KD) | `hps_comeback_kd_diff` | KD差值当队伍落后4+回合 | `hps_comeback_kd_diff` | `fact_round_events + fact_rounds` | Deep Section 12 |
|
||||
| Loss Streak KD (连败KD) | `hps_losing_streak_kd_diff` | KD差值当连败3+回合 | `hps_losing_streak_kd_diff` | `fact_round_events + fact_rounds` | Deep Section 13 |
|
||||
| Pistol Kills (手枪击杀) | `ptl_pistol_kills` | `COUNT(kills WHERE round IN (1,13))` / matches | `ptl_pistol_kills` | `fact_round_events` (round 1,13) | Deep Section 14 |
|
||||
| Pistol Win% (手枪胜率) | `ptl_pistol_win_rate` | Win rate for pistol rounds | `ptl_pistol_win_rate` | `fact_rounds` (round 1,13) | Deep Section 15 |
|
||||
| Pistol KD (手枪KD) | `ptl_pistol_kd` | `pistol_kills / pistol_deaths` | `ptl_pistol_kd` | `fact_round_events` (round 1,13) | Deep Section 16 |
|
||||
| Pistol Util Eff (手枪道具) | `ptl_pistol_util_efficiency` | Headshot rate in pistol rounds | `ptl_pistol_util_efficiency` | `fact_round_events` (is_headshot) | Deep Section 17 |
|
||||
|
||||
#### 1.5.3 道具使用 (UTIL)
|
||||
|
||||
| 显示标签 | 指标键 | 计算方法 | L3列名 | L2来源 | UI位置 |
|
||||
|---------|--------|---------|--------|--------|--------|
|
||||
| Usage Rate (道具频率) | `util_usage_rate` | `(flash+smoke+molotov+he+decoy) / rounds * 100` | `util_usage_rate` | `fact_match_players.util_*_usage` | Deep Section 18 |
|
||||
| Nade Dmg (雷火伤) | `util_avg_nade_dmg` | `SUM(throw_harm) / matches` | `util_avg_nade_dmg` | `fact_match_players.throw_harm` | Deep Section 19 |
|
||||
| Flash Time (致盲时间) | `util_avg_flash_time` | `SUM(flash_time) / matches` | `util_avg_flash_time` | `fact_match_players.flash_time` | Deep Section 20 |
|
||||
| Flash Enemy (致盲人数) | `util_avg_flash_enemy` | `SUM(flash_enemy) / matches` | `util_avg_flash_enemy` | `fact_match_players.flash_enemy` | Deep Section 21 |
|
||||
|
||||
#### 1.5.4 经济与节奏 (ECO & PACE)
|
||||
|
||||
| 显示标签 | 指标键 | 计算方法 | L3列名 | L2来源 | UI位置 |
|
||||
|---------|--------|---------|--------|--------|--------|
|
||||
| Dmg/$1k (性价比) | `eco_avg_damage_per_1k` | `total_damage / (total_equipment / 1000)` | `eco_avg_damage_per_1k` | `fact_round_player_economy` | Deep Section 22 |
|
||||
| Eco KPR (经济局KPR) | `eco_rating_eco_rounds` | Kills per round when equipment < $2000 | `eco_rating_eco_rounds` | `fact_round_player_economy` | Deep Section 23 |
|
||||
| Eco KD (经济局KD) | `eco_kd_ratio` | KD in eco rounds | `eco_kd_ratio` | `fact_round_player_economy` | Deep Section 24 |
|
||||
| Eco Rounds (经济局数) | `eco_avg_rounds` | `COUNT(equipment < 2000) / matches` | `eco_avg_rounds` | `fact_round_player_economy` | Deep Section 25 |
|
||||
| First Contact (首肯时间) | `pace_avg_time_to_first_contact` | `AVG(MIN(event_time))` per round | `pace_avg_time_to_first_contact` | `fact_round_events.event_time` | Deep Section 26 |
|
||||
| Trade Kill% (补枪率) | `pace_trade_kill_rate` | `TradeKills / TotalKills` (5s window) | `pace_trade_kill_rate` | `fact_round_events` (self-join) | Deep Section 27 |
|
||||
| Opening Time (首杀时间) | `pace_opening_kill_time` | `AVG(first_kill_time)` per round | `pace_opening_kill_time` | `fact_round_events.event_time` | Deep Section 28 |
|
||||
| Avg Life (存活时间) | `pace_avg_life_time` | `AVG(death_time OR round_end)` | `pace_avg_life_time` | `fact_round_events + fact_rounds` | Deep Section 29 |
|
||||
|
||||
#### 1.5.5 回合动态 (ROUND Dynamics)
|
||||
|
||||
| 显示标签 | 指标键 | 计算方法 | L3列名 | L2来源 | UI位置 |
|
||||
|---------|--------|---------|--------|--------|--------|
|
||||
| Kill Early (前30秒击杀) | `rd_phase_kill_early_share` | Early kills / Total kills | `rd_phase_kill_early_share` | `fact_round_events.event_time` | Deep Section 30 |
|
||||
| Kill Mid (30-60秒击杀) | `rd_phase_kill_mid_share` | Mid kills / Total kills | `rd_phase_kill_mid_share` | `fact_round_events.event_time` | Deep Section 31 |
|
||||
| Kill Late (60秒后击杀) | `rd_phase_kill_late_share` | Late kills / Total kills | `rd_phase_kill_late_share` | `fact_round_events.event_time` | Deep Section 32 |
|
||||
| Death Early (前30秒死亡) | `rd_phase_death_early_share` | Early deaths / Total deaths | `rd_phase_death_early_share` | `fact_round_events.event_time` | Deep Section 33 |
|
||||
| Death Mid (30-60秒死亡) | `rd_phase_death_mid_share` | Mid deaths / Total deaths | `rd_phase_death_mid_share` | `fact_round_events.event_time` | Deep Section 34 |
|
||||
| Death Late (60秒后死亡) | `rd_phase_death_late_share` | Late deaths / Total deaths | `rd_phase_death_late_share` | `fact_round_events.event_time` | Deep Section 35 |
|
||||
| FirstDeath Win% (首死后胜率) | `rd_firstdeath_team_first_death_win_rate` | Win rate when team loses first blood | `rd_firstdeath_team_first_death_win_rate` | `fact_round_events + fact_rounds` | Deep Section 36 |
|
||||
| Invalid Death% (无效死亡) | `rd_invalid_death_rate` | Deaths with 0 kills & 0 flash assists | `rd_invalid_death_rate` | `fact_round_events` | Deep Section 37 |
|
||||
| Pressure KPR (落后≥3) | `rd_pressure_kpr_ratio` | KPR when down 3+ rounds / Normal KPR | `rd_pressure_kpr_ratio` | `fact_rounds + fact_round_events` | Deep Section 38 |
|
||||
| MatchPt KPR (赛点放大) | `rd_matchpoint_kpr_ratio` | KPR at match point / Normal KPR | `rd_matchpoint_kpr_ratio` | `fact_rounds + fact_round_events` | Deep Section 39 |
|
||||
| Trade Resp (10s响应) | `rd_trade_response_10s_rate` | Success rate trading teammate death in 10s | `rd_trade_response_10s_rate` | `fact_round_events` (self-join) | Deep Section 40 |
|
||||
| Pressure Perf (Leetify) | `rd_pressure_perf_ratio` | Leetify perf when down 3+ / Normal | `rd_pressure_perf_ratio` | `fact_round_player_economy` | Deep Section 41 |
|
||||
| MatchPt Perf (Leetify) | `rd_matchpoint_perf_ratio` | Leetify perf at match point / Normal | `rd_matchpoint_perf_ratio` | `fact_round_player_economy` | Deep Section 42 |
|
||||
| Comeback KillShare (追分) | `rd_comeback_kill_share` | Player's kills / Team kills in comeback rounds | `rd_comeback_kill_share` | `fact_round_events + fact_rounds` | Deep Section 43 |
|
||||
| Map Stability (地图稳定) | `map_stability_coef` | `AVG(|map_rating - player_avg|)` | `map_stability_coef` | `fact_match_players` (by map) | Deep Section 44 |
|
||||
|
||||
#### 1.5.6 残局与多杀 (SPECIAL - Clutch & Multi)
|
||||
|
||||
| 显示标签 | 指标键 | 计算方法 | L3列名 | L2来源 | UI位置 |
|
||||
|---------|--------|---------|--------|--------|--------|
|
||||
| 1v1 Win% (1v1胜率) | `clutch_rate_1v1` | `clutch_1v1 / attempts_1v1` | N/A (L2) | `fact_match_players.clutch_1v1, end_1v1` | Deep Section 45 |
|
||||
| 1v2 Win% (1v2胜率) | `clutch_rate_1v2` | `clutch_1v2 / attempts_1v2` | N/A (L2) | `fact_match_players.clutch_1v2, end_1v2` | Deep Section 46 |
|
||||
| 1v3 Win% (1v3胜率) | `clutch_rate_1v3` | `clutch_1v3 / attempts_1v3` | N/A (L2) | `fact_match_players.clutch_1v3, end_1v3` | Deep Section 47 |
|
||||
| 1v4 Win% (1v4胜率) | `clutch_rate_1v4` | `clutch_1v4 / attempts_1v4` | N/A (L2) | `fact_match_players.clutch_1v4, end_1v4` | Deep Section 48 |
|
||||
| 1v5 Win% (1v5胜率) | `clutch_rate_1v5` | `clutch_1v5 / attempts_1v5` | N/A (L2) | `fact_match_players.clutch_1v5, end_1v5` | Deep Section 49 |
|
||||
| Multi-K Rate (多杀率) | `total_multikill_rate` | `(2K+3K+4K+5K) / total_rounds` | N/A (L2) | `fact_match_players.kill_2/3/4/5` | Deep Section 50 |
|
||||
| Multi-A Rate (多助率) | `total_multiassist_rate` | `(many_assists_cnt2/3/4/5) / rounds` | N/A (L2) | `fact_match_players.many_assists_cnt*` | Deep Section 51 |
|
||||
|
||||
#### 1.5.7 阵营偏好 (SIDE Preference)
|
||||
|
||||
| 显示标签 | 指标键 | 计算方法 | L3列名 | L2来源 | UI位置 |
|
||||
|---------|--------|---------|--------|--------|--------|
|
||||
| Rating (T-Side) | `side_rating_t` | `AVG(rating2)` from T table | `side_rating_t` | `fact_match_players_t.rating2` | Deep Section 52 |
|
||||
| Rating (CT-Side) | `side_rating_ct` | `AVG(rating2)` from CT table | `side_rating_ct` | `fact_match_players_ct.rating2` | Deep Section 53 |
|
||||
| KD Ratio (T) | `side_kd_t` | `SUM(kills) / SUM(deaths)` T-side | `side_kd_t` | `fact_match_players_t.kills/deaths` | Deep Section 54 |
|
||||
| KD Ratio (CT) | `side_kd_ct` | `SUM(kills) / SUM(deaths)` CT-side | `side_kd_ct` | `fact_match_players_ct.kills/deaths` | Deep Section 55 |
|
||||
| Win Rate (T) | `side_win_rate_t` | `AVG(is_win)` T-side | `side_win_rate_t` | `fact_match_players_t.is_win` | Deep Section 56 |
|
||||
| Win Rate (CT) | `side_win_rate_ct` | `AVG(is_win)` CT-side | `side_win_rate_ct` | `fact_match_players_ct.is_win` | Deep Section 57 |
|
||||
| First Kill Rate (T) | `side_first_kill_rate_t` | `FK / rounds` T-side | `side_first_kill_rate_t` | `fact_match_players_t.first_kill` | Deep Section 58 |
|
||||
| First Kill Rate (CT) | `side_first_kill_rate_ct` | `FK / rounds` CT-side | `side_first_kill_rate_ct` | `fact_match_players_ct.first_kill` | Deep Section 59 |
|
||||
| First Death Rate (T) | `side_first_death_rate_t` | `FD / rounds` T-side | `side_first_death_rate_t` | `fact_match_players_t.first_death` | Deep Section 60 |
|
||||
| First Death Rate (CT) | `side_first_death_rate_ct` | `FD / rounds` CT-side | `side_first_death_rate_ct` | `fact_match_players_ct.first_death` | Deep Section 61 |
|
||||
| KAST (T) | `side_kast_t` | `AVG(kast)` T-side | `side_kast_t` | `fact_match_players_t.kast` | Deep Section 62 |
|
||||
| KAST (CT) | `side_kast_ct` | `AVG(kast)` CT-side | `side_kast_ct` | `fact_match_players_ct.kast` | Deep Section 63 |
|
||||
| RWS (T) | `side_rws_t` | `AVG(rws)` T-side | `side_rws_t` | `fact_match_players_t.rws` | Deep Section 64 |
|
||||
| RWS (CT) | `side_rws_ct` | `AVG(rws)` CT-side | `side_rws_ct` | `fact_match_players_ct.rws` | Deep Section 65 |
|
||||
| Headshot Rate (T) | `side_headshot_rate_t` | `HS / kills` T-side | `side_headshot_rate_t` | `fact_match_players_t.headshot_count/kills` | Deep Section 66 |
|
||||
| Headshot Rate (CT) | `side_headshot_rate_ct` | `HS / kills` CT-side | `side_headshot_rate_ct` | `fact_match_players_ct.headshot_count/kills` | Deep Section 67 |
|
||||
|
||||
#### 1.5.8 组排与分层 (Party & Stratification)
|
||||
|
||||
| 显示标签 | 指标键 | 计算方法 | L3列名 | L2来源 | UI位置 |
|
||||
|---------|--------|---------|--------|--------|--------|
|
||||
| Solo Win% (单排胜率) | `party_1_win_rate` | Win rate in solo queue | `party_1_win_rate` | `fact_match_players` (party_size=1) | Deep Section 68 |
|
||||
| Solo Rating (单排分) | `party_1_rating` | `AVG(rating)` in solo | `party_1_rating` | `fact_match_players` (party_size=1) | Deep Section 69 |
|
||||
| Solo ADR (单排伤) | `party_1_adr` | `AVG(adr)` in solo | `party_1_adr` | `fact_match_players` (party_size=1) | Deep Section 70 |
|
||||
| Duo Win% (双排胜率) | `party_2_win_rate` | Win rate in duo | `party_2_win_rate` | `fact_match_players` (party_size=2) | Deep Section 71 |
|
||||
| ... (party_2~5 follow same pattern) | ... | ... | ... | ... | Deep Section 72-79 |
|
||||
| Carry Rate (>1.5) | `rating_dist_carry_rate` | `COUNT(rating>1.5) / total` | `rating_dist_carry_rate` | `fact_match_players.rating` | Deep Section 80 |
|
||||
| Normal Rate (1.0-1.5) | `rating_dist_normal_rate` | `COUNT(1.0<=rating<1.5) / total` | `rating_dist_normal_rate` | `fact_match_players.rating` | Deep Section 81 |
|
||||
| Sacrifice Rate (0.6-1.0) | `rating_dist_sacrifice_rate` | `COUNT(0.6<=rating<1.0) / total` | `rating_dist_sacrifice_rate` | `fact_match_players.rating` | Deep Section 82 |
|
||||
| Sleeping Rate (<0.6) | `rating_dist_sleeping_rate` | `COUNT(rating<0.6) / total` | `rating_dist_sleeping_rate` | `fact_match_players.rating` | Deep Section 83 |
|
||||
| <1200 Rating | `elo_lt1200_rating` | `AVG(rating)` vs opponents <1200 ELO | `elo_lt1200_rating` | `fact_match_teams.group_origin_elo` | Deep Section 84 |
|
||||
| 1200-1400 Rating | `elo_1200_1400_rating` | `AVG(rating)` vs 1200-1400 ELO | `elo_1200_1400_rating` | `fact_match_teams.group_origin_elo` | Deep Section 85 |
|
||||
| ... (elo_* follow same pattern) | ... | ... | ... | ... | Deep Section 86-89 |
|
||||
|
||||
### 1.6 附加数据
|
||||
|
||||
#### 1.6.1 Phase Split (回合阶段分布)
|
||||
|
||||
- **数据来源**: `rd_phase_kill_*_share` 和 `rd_phase_death_*_share` 系列
|
||||
- **UI呈现**: 横条图展示 Total/T/CT 的击杀/死亡在 Early/Mid/Late 的分布
|
||||
- **计算**: 时间段划分(0-30s/30-60s/60s+),分T/CT/Overall统计
|
||||
|
||||
#### 1.6.2 Top Weapons (常用武器)
|
||||
|
||||
- **数据来源**: `rd_weapon_top_json` (JSON字段)
|
||||
- **包含信息**: weapon, kills, hs_rate, price, category, share
|
||||
- **UI呈现**: 表格展示前5常用武器及其数据
|
||||
|
||||
#### 1.6.3 Round Type Split (回合类型表现)
|
||||
|
||||
- **数据来源**: `rd_roundtype_split_json` (JSON字段)
|
||||
- **包含信息**: pistol/eco/rifle/fullbuy/overtime的KPR和Perf
|
||||
- **UI呈现**: 表格展示不同经济类型回合的表现
|
||||
|
||||
@@ -0,0 +1,784 @@
|
||||
# 三层数据库架构重构计划
|
||||
|
||||
## 一、项目背景与目标
|
||||
|
||||
### 现状分析
|
||||
- **已有三层架构**: L1A(原始JSON) → L2(结构化事实/维度表) → L3(特征集市)
|
||||
- **主要问题**:
|
||||
1. 数据库文件命名不统一(L1A.sqlite, L2_Main.sqlite, L3_Features.sqlite)
|
||||
2. JSON中存在两种Round数据格式(leetify含经济数据, classic含xyz坐标), 目前通过`data_source_type`标记但未完全统一Schema
|
||||
3. web/services层包含大量数据处理逻辑(feature_service.py 2257行, stats_service.py 1113行), 应下沉到数据库构建层
|
||||
4. L2_Builder.py单体文件1470行,缺乏模块化
|
||||
|
||||
### 重构目标
|
||||
1. **标准化命名**: 统一数据库文件为`L1.db`, `L2.db`, `L3.db`
|
||||
2. **Schema优化**: 设计统一Round数据表结构,支持多数据源差异化字段
|
||||
3. **逻辑下沉**: 将聚合计算从web/services迁移至database层的processor模块
|
||||
4. **模块化解耦**: 建立sub-processor模式,按功能域拆分处理器
|
||||
5. **预留L1B**: 为未来Demo直接解析管道预留目录结构
|
||||
|
||||
---
|
||||
|
||||
## 二、目录结构重构
|
||||
|
||||
### 2.1 标准化三层目录
|
||||
```
|
||||
database/
|
||||
├── L1/
|
||||
│ ├── L1.db # 标准化命名(原L1A.sqlite)
|
||||
│ ├── L1_Builder.py # 数据入库脚本(原L1A_Builder.py)
|
||||
│ └── README.md
|
||||
├── L1B/ # 预留未来Demo解析管道
|
||||
│ └── README.md # 说明此目录用途及预留原因
|
||||
├── L2/
|
||||
│ ├── L2.db # 标准化命名(原L2_Main.sqlite)
|
||||
│ ├── L2_Builder.py # 主构建器(重构,瘦身)
|
||||
│ ├── schema.sql # 优化后的统一Schema
|
||||
│ ├── processors/ # 新建:子处理器模块目录
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── match_processor.py # 比赛基础信息处理
|
||||
│ │ ├── player_processor.py # 玩家统计处理
|
||||
│ │ ├── round_processor.py # Round数据统一处理
|
||||
│ │ ├── economy_processor.py # 经济数据处理(leetify)
|
||||
│ │ ├── event_processor.py # 事件流处理(kill/bomb等)
|
||||
│ │ └── spatial_processor.py # 空间坐标处理(classic)
|
||||
│ └── README.md
|
||||
├── L3/
|
||||
│ ├── L3.db # 标准化命名(原L3_Features.sqlite)
|
||||
│ ├── L3_Builder.py # 主构建器(重构)
|
||||
│ ├── schema.sql # 保持现有L3 schema
|
||||
│ ├── processors/ # 新建:特征计算模块
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── basic_processor.py # 基础特征(avg rating/kd/kast)
|
||||
│ │ ├── sta_processor.py # 稳定性时间序列特征
|
||||
│ │ ├── bat_processor.py # 对抗能力特征
|
||||
│ │ ├── hps_processor.py # 高压场景特征
|
||||
│ │ ├── ptl_processor.py # 手枪局特征
|
||||
│ │ ├── side_processor.py # T/CT阵营特征
|
||||
│ │ ├── util_processor.py # 道具使用特征
|
||||
│ │ ├── eco_processor.py # 经济效率特征
|
||||
│ │ └── pace_processor.py # 节奏侵略性特征
|
||||
│ └── README.md
|
||||
├── original_json_schema/ # 保持不变
|
||||
└── Force_Rebuild.py # 更新引用新路径
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、L2层Schema优化
|
||||
|
||||
### 3.1 Round数据统一Schema设计
|
||||
|
||||
**核心思路**: 设计包含所有字段的统一表结构,根据`data_source_type`选择性填充
|
||||
|
||||
#### 3.1.1 fact_rounds表增强
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS fact_rounds (
|
||||
match_id TEXT,
|
||||
round_num INTEGER,
|
||||
|
||||
-- 公共字段(两种数据源均有)
|
||||
winner_side TEXT CHECK(winner_side IN ('CT', 'T', 'None')),
|
||||
win_reason INTEGER,
|
||||
win_reason_desc TEXT,
|
||||
duration REAL,
|
||||
ct_score INTEGER,
|
||||
t_score INTEGER,
|
||||
|
||||
-- Leetify专属字段
|
||||
ct_money_start INTEGER, -- 仅leetify
|
||||
t_money_start INTEGER, -- 仅leetify
|
||||
begin_ts TEXT, -- 仅leetify
|
||||
end_ts TEXT, -- 仅leetify
|
||||
|
||||
-- Classic专属字段
|
||||
end_time_stamp TEXT, -- 仅classic
|
||||
final_round_time INTEGER, -- 仅classic
|
||||
pasttime INTEGER, -- 仅classic
|
||||
|
||||
-- 数据源标记(继承自fact_matches)
|
||||
data_source_type TEXT CHECK(data_source_type IN ('leetify', 'classic', 'unknown')),
|
||||
|
||||
PRIMARY KEY (match_id, round_num),
|
||||
FOREIGN KEY (match_id) REFERENCES fact_matches(match_id) ON DELETE CASCADE
|
||||
);
|
||||
```
|
||||
|
||||
#### 3.1.2 fact_round_events表增强
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS fact_round_events (
|
||||
event_id TEXT PRIMARY KEY,
|
||||
match_id TEXT,
|
||||
round_num INTEGER,
|
||||
|
||||
event_type TEXT CHECK(event_type IN ('kill', 'bomb_plant', 'bomb_defuse', 'suicide', 'unknown')),
|
||||
event_time INTEGER,
|
||||
|
||||
-- Kill相关字段
|
||||
attacker_steam_id TEXT,
|
||||
victim_steam_id TEXT,
|
||||
assister_steam_id TEXT,
|
||||
flash_assist_steam_id TEXT,
|
||||
trade_killer_steam_id TEXT,
|
||||
|
||||
weapon TEXT,
|
||||
is_headshot BOOLEAN DEFAULT 0,
|
||||
is_wallbang BOOLEAN DEFAULT 0,
|
||||
is_blind BOOLEAN DEFAULT 0,
|
||||
is_through_smoke BOOLEAN DEFAULT 0,
|
||||
is_noscope BOOLEAN DEFAULT 0,
|
||||
|
||||
-- Classic空间数据(xyz坐标)
|
||||
attacker_pos_x INTEGER, -- 仅classic
|
||||
attacker_pos_y INTEGER, -- 仅classic
|
||||
attacker_pos_z INTEGER, -- 仅classic
|
||||
victim_pos_x INTEGER, -- 仅classic
|
||||
victim_pos_y INTEGER, -- 仅classic
|
||||
victim_pos_z INTEGER, -- 仅classic
|
||||
|
||||
-- Leetify评分影响
|
||||
score_change_attacker REAL, -- 仅leetify
|
||||
score_change_victim REAL, -- 仅leetify
|
||||
twin REAL, -- 仅leetify (team win probability)
|
||||
c_twin REAL, -- 仅leetify
|
||||
twin_change REAL, -- 仅leetify
|
||||
c_twin_change REAL, -- 仅leetify
|
||||
|
||||
-- 数据源标记
|
||||
data_source_type TEXT CHECK(data_source_type IN ('leetify', 'classic', 'unknown')),
|
||||
|
||||
FOREIGN KEY (match_id, round_num) REFERENCES fact_rounds(match_id, round_num) ON DELETE CASCADE
|
||||
);
|
||||
```
|
||||
|
||||
#### 3.1.3 fact_round_player_economy表增强
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS fact_round_player_economy (
|
||||
match_id TEXT,
|
||||
round_num INTEGER,
|
||||
steam_id_64 TEXT,
|
||||
|
||||
side TEXT CHECK(side IN ('CT', 'T')),
|
||||
|
||||
-- Leetify经济数据(仅leetify)
|
||||
start_money INTEGER,
|
||||
equipment_value INTEGER,
|
||||
main_weapon TEXT,
|
||||
has_helmet BOOLEAN,
|
||||
has_defuser BOOLEAN,
|
||||
has_zeus BOOLEAN,
|
||||
round_performance_score REAL,
|
||||
|
||||
-- Classic装备快照(仅classic, JSON存储)
|
||||
equipment_snapshot_json TEXT, -- Classic的equiped字段序列化
|
||||
|
||||
-- 数据源标记
|
||||
data_source_type TEXT CHECK(data_source_type IN ('leetify', 'classic', 'unknown')),
|
||||
|
||||
PRIMARY KEY (match_id, round_num, steam_id_64),
|
||||
FOREIGN KEY (match_id, round_num) REFERENCES fact_rounds(match_id, round_num) ON DELETE CASCADE
|
||||
);
|
||||
```
|
||||
|
||||
### 3.2 Force Buy修复
|
||||
|
||||
在`fact_round_player_economy`表中确保:
|
||||
- `start_money`和`equipment_value`字段类型为INTEGER
|
||||
- 处理器中正确解析leetify的`bron_equipment`和`player_bron_crash`
|
||||
|
||||
---
|
||||
|
||||
## 四、L2 Processor模块化设计
|
||||
|
||||
### 4.1 架构模式
|
||||
|
||||
```
|
||||
L2_Builder.py (主控制器, ~300行)
|
||||
↓ 调用
|
||||
processors/
|
||||
├── match_processor.py # 处理fact_matches, fact_match_teams
|
||||
├── player_processor.py # 处理dim_players, fact_match_players
|
||||
├── round_processor.py # 统一调度round数据处理
|
||||
│ ├── 内部调用 economy_processor
|
||||
│ ├── 内部调用 event_processor
|
||||
│ └── 内部调用 spatial_processor
|
||||
├── economy_processor.py # 专门处理leetify经济数据
|
||||
├── event_processor.py # 处理kill/bomb事件
|
||||
└── spatial_processor.py # 处理classic坐标数据
|
||||
```
|
||||
|
||||
### 4.2 Processor接口规范
|
||||
|
||||
每个processor模块提供标准接口:
|
||||
```python
|
||||
class XxxProcessor:
|
||||
@staticmethod
|
||||
def process(match_data: MatchData, conn: sqlite3.Connection) -> bool:
|
||||
"""
|
||||
Args:
|
||||
match_data: 统一的MatchData对象(包含所有原始数据)
|
||||
conn: L2数据库连接
|
||||
Returns:
|
||||
bool: 处理成功返回True
|
||||
"""
|
||||
pass
|
||||
```
|
||||
|
||||
### 4.3 核心Processor功能分配
|
||||
|
||||
#### match_processor.py
|
||||
- **职责**: 处理比赛主表和队伍信息
|
||||
- **输入**: `MatchData.data_match`的main字段
|
||||
- **输出**: 写入`fact_matches`, `fact_match_teams`
|
||||
- **关键逻辑**:
|
||||
- 提取main字段的40+基础信息
|
||||
- 解析group1/group2队伍信息
|
||||
- 存储treat_info_raw等原始JSON
|
||||
- 设置data_source_type标记
|
||||
|
||||
#### player_processor.py
|
||||
- **职责**: 处理玩家维度表和比赛统计
|
||||
- **输入**: `MatchData.data_match`的group_1/group_2玩家列表, data_vip
|
||||
- **输出**: 写入`dim_players`, `fact_match_players`, `fact_match_players_t`, `fact_match_players_ct`
|
||||
- **关键逻辑**:
|
||||
- 合并fight/fight_t/fight_ct三个字段
|
||||
- 处理VIP+高级统计(kast, awp_kill等)
|
||||
- 计算utility usage(从round details累加)
|
||||
- UPSERT dim_players(避免重复)
|
||||
|
||||
#### round_processor.py (调度器)
|
||||
- **职责**: 作为Round数据的统一入口,根据data_source_type分发
|
||||
- **输入**: `MatchData.data_leetify`或`MatchData.data_round_list`
|
||||
- **输出**: 调度其他processor处理
|
||||
- **关键逻辑**:
|
||||
```python
|
||||
if match_data.data_source_type == 'leetify':
|
||||
economy_processor.process_leetify(...)
|
||||
event_processor.process_leetify_events(...)
|
||||
elif match_data.data_source_type == 'classic':
|
||||
event_processor.process_classic_events(...)
|
||||
spatial_processor.process_positions(...)
|
||||
```
|
||||
|
||||
#### economy_processor.py
|
||||
- **职责**: 处理leetify的经济数据
|
||||
- **输入**: `data_leetify['leetify_data']['round_stat']`
|
||||
- **输出**: 写入`fact_round_player_economy`, `fact_rounds`的经济字段
|
||||
- **关键逻辑**:
|
||||
- 解析bron_equipment(装备列表)
|
||||
- 解析player_bron_crash(起始金钱)
|
||||
- 计算equipment_value
|
||||
|
||||
#### event_processor.py
|
||||
- **职责**: 处理击杀/炸弹事件
|
||||
- **输入**: leetify的show_event或classic的all_kill
|
||||
- **输出**: 写入`fact_round_events`
|
||||
- **关键逻辑**:
|
||||
- 生成event_id(UUID)
|
||||
- 区分event_type: kill/bomb_plant/bomb_defuse
|
||||
- leetify: 提取killer_score_change, victim_score_change, twin变化
|
||||
- classic: 提取attacker/victim的pos(x,y,z)
|
||||
|
||||
#### spatial_processor.py
|
||||
- **职责**: 处理classic的空间数据
|
||||
- **输入**: `data_round_list['round_list']`的pos字段
|
||||
- **输出**: 更新`fact_round_events`的坐标字段
|
||||
- **关键逻辑**:
|
||||
- 提取attacker.pos.x/y/z
|
||||
- 提取victim.pos.x/y/z
|
||||
- 为未来热力图/战术板分析做准备
|
||||
|
||||
---
|
||||
|
||||
## 五、L3 Processor模块化设计
|
||||
|
||||
### 5.1 现状与问题
|
||||
|
||||
**现状**:
|
||||
- L3_Builder.py目前委托给`web.services.feature_service.FeatureService.rebuild_all_features()`
|
||||
- feature_service.py包含2257行代码,混杂大量特征计算逻辑
|
||||
|
||||
**目标**:
|
||||
- 将特征计算逻辑完全迁移到`database/L3/processors/`
|
||||
- feature_service仅保留查询和缓存逻辑
|
||||
- 按FeatureRDD.md的6大维度+基础特征建立processor
|
||||
|
||||
### 5.2 Processor模块划分
|
||||
|
||||
#### basic_processor.py
|
||||
- **职责**: 计算基础统计特征(0-42个指标)
|
||||
- **数据源**: `fact_match_players`
|
||||
- **特征示例**:
|
||||
- `basic_avg_rating`: AVG(rating)
|
||||
- `basic_avg_kd`: AVG(kills/deaths)
|
||||
- `basic_headshot_rate`: SUM(headshot_count)/SUM(kills)
|
||||
- `basic_first_kill_rate`: SUM(first_kill)/(SUM(first_kill)+SUM(first_death))
|
||||
- **实现方式**: SQL聚合 + 简单Python计算
|
||||
|
||||
#### sta_processor.py (稳定性时间序列)
|
||||
- **职责**: 计算STA维度特征
|
||||
- **数据源**: `fact_match_players`, `fact_matches`(按start_time排序)
|
||||
- **特征示例**:
|
||||
- `sta_last_30_rating`: 近30局平均rating
|
||||
- `sta_win_rating`, `sta_loss_rating`: 胜/败局分组rating
|
||||
- `sta_rating_volatility`: STDDEV(last 10 ratings)
|
||||
- `sta_fatigue_decay`: 同日后期比赛vs前期比赛性能下降
|
||||
- **实现方式**: pandas时间序列分析
|
||||
|
||||
#### bat_processor.py (对抗能力)
|
||||
- **职责**: 计算BAT维度特征
|
||||
- **数据源**: `fact_round_events`(击杀关系网络), `fact_match_players`
|
||||
- **特征示例**:
|
||||
- `bat_kd_diff_high_elo`: 对最高elo对手的KD差
|
||||
- `bat_avg_duel_win_rate`: 1v1对决胜率
|
||||
- `bat_win_rate_close/mid/far`: 不同距离对枪胜率(需classic坐标)
|
||||
- **实现方式**: 对手关系矩阵构建 + 条件聚合
|
||||
|
||||
#### hps_processor.py (高压场景)
|
||||
- **职责**: 计算HPS维度特征
|
||||
- **数据源**: `fact_rounds`, `fact_round_events`, `fact_match_players`
|
||||
- **特征示例**:
|
||||
- `hps_clutch_win_rate_1v1/1v2/1v3_plus`: 残局胜率
|
||||
- `hps_match_point_win_rate`: 赛点表现
|
||||
- `hps_pressure_entry_rate`: 连败后首杀率
|
||||
- `hps_comeback_kd_diff`: 翻盘时KD提升
|
||||
- **实现方式**: 识别特殊场景(赛点/连败/残局) + 条件统计
|
||||
|
||||
#### ptl_processor.py (手枪局)
|
||||
- **职责**: 计算PTL维度特征
|
||||
- **数据源**: `fact_rounds`(round_num=1,13), `fact_round_events`
|
||||
- **特征示例**:
|
||||
- `ptl_pistol_win_rate`: 手枪局胜率
|
||||
- `ptl_pistol_kd`: 手枪局KD
|
||||
- `ptl_pistol_multikills`: 手枪局多杀次数
|
||||
- `ptl_pistol_util_efficiency`: 道具辅助击杀率
|
||||
- **实现方式**: 过滤round_num + 武器类型判断
|
||||
|
||||
#### side_processor.py (T/CT阵营)
|
||||
- **职责**: 计算T/CT维度特征
|
||||
- **数据源**: `fact_match_players_t`, `fact_match_players_ct`
|
||||
- **特征示例**:
|
||||
- `side_rating_t`, `side_rating_ct`: 分阵营rating
|
||||
- `side_kd_diff_ct_t`: CT-T的KD差
|
||||
- `side_first_kill_rate_t/ct`: 分阵营首杀率
|
||||
- `side_plants_t`, `side_defuses_ct`: 下包/拆包数
|
||||
- **实现方式**: 分表聚合 + 差值计算
|
||||
|
||||
#### util_processor.py (道具使用)
|
||||
- **职责**: 计算UTIL维度特征
|
||||
- **数据源**: `fact_match_players`(util_xxx_usage字段)
|
||||
- **特征示例**:
|
||||
- `util_avg_nade_dmg`: 平均手雷伤害
|
||||
- `util_avg_flash_time`: 平均致盲时长
|
||||
- `util_usage_rate`: 道具使用频率
|
||||
- **实现方式**: 简单聚合
|
||||
|
||||
#### eco_processor.py (经济效率)
|
||||
- **职责**: 计算ECO维度特征
|
||||
- **数据源**: `fact_round_player_economy`(仅leetify数据)
|
||||
- **特征示例**:
|
||||
- `eco_avg_damage_per_1k`: 每1000元造成的伤害
|
||||
- `eco_rating_eco_rounds`: ECO局rating
|
||||
- `eco_kd_ratio`: 经济局KD
|
||||
- **实现方式**: 经济分段 + 性能关联
|
||||
- **注意**: 仅leetify数据源可用
|
||||
|
||||
#### pace_processor.py (节奏侵略性)
|
||||
- **职责**: 计算PACE维度特征
|
||||
- **数据源**: `fact_round_events`(event_time)
|
||||
- **特征示例**:
|
||||
- `pace_avg_time_to_first_contact`: 平均首次交火时间
|
||||
- `pace_opening_kill_time`: 开局击杀速度
|
||||
- `pace_trade_kill_rate`: 补枪速率
|
||||
- `rd_phase_kill_early/mid/late_share`: 早/中/后期击杀占比
|
||||
- **实现方式**: 事件时间戳分析
|
||||
|
||||
### 5.3 L3_Builder重构结构
|
||||
|
||||
```python
|
||||
# L3_Builder.py (瘦身至~150行)
|
||||
from database.L3.processors import (
|
||||
basic_processor,
|
||||
sta_processor,
|
||||
bat_processor,
|
||||
hps_processor,
|
||||
ptl_processor,
|
||||
side_processor,
|
||||
util_processor,
|
||||
eco_processor,
|
||||
pace_processor
|
||||
)
|
||||
|
||||
def rebuild_all_features():
|
||||
conn_l2 = sqlite3.connect(L2_DB_PATH)
|
||||
conn_l3 = sqlite3.connect(L3_DB_PATH)
|
||||
|
||||
players = get_all_players(conn_l2)
|
||||
|
||||
for player in players:
|
||||
features = {}
|
||||
|
||||
# 调用各processor
|
||||
features.update(basic_processor.calculate(player, conn_l2))
|
||||
features.update(sta_processor.calculate(player, conn_l2))
|
||||
features.update(bat_processor.calculate(player, conn_l2))
|
||||
features.update(hps_processor.calculate(player, conn_l2))
|
||||
features.update(ptl_processor.calculate(player, conn_l2))
|
||||
features.update(side_processor.calculate(player, conn_l2))
|
||||
features.update(util_processor.calculate(player, conn_l2))
|
||||
features.update(eco_processor.calculate(player, conn_l2))
|
||||
features.update(pace_processor.calculate(player, conn_l2))
|
||||
|
||||
# 写入L3
|
||||
upsert_player_features(conn_l3, player['steam_id_64'], features)
|
||||
|
||||
conn_l2.close()
|
||||
conn_l3.close()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、Web Services解耦
|
||||
|
||||
### 6.1 迁移策略
|
||||
|
||||
**原则**: Web层只做查询和缓存,不做计算
|
||||
|
||||
#### feature_service.py重构
|
||||
- **保留功能**:
|
||||
- `get_player_features(steam_id)`: 从L3查询
|
||||
- `get_players_list()`: 分页查询
|
||||
- **移除功能**(迁移到L3 processors):
|
||||
- `rebuild_all_features()` → L3_Builder.py
|
||||
- 所有`_calculate_xxx()`方法 → L3/processors/xxx_processor.py
|
||||
|
||||
#### stats_service.py重构
|
||||
- **保留功能**:
|
||||
- `get_player_basic_stats()`: 简单查询L2
|
||||
- `get_match_details()`: 查询比赛详情
|
||||
- **优化功能**:
|
||||
- `get_team_stats_summary()`: 改为查询L2 VIEW(新建聚合视图)
|
||||
- 复杂聚合逻辑移至L2 processors或创建数据库VIEW
|
||||
|
||||
### 6.2 新建L2 VIEW
|
||||
|
||||
在`database/L2/schema.sql`中新增:
|
||||
|
||||
```sql
|
||||
-- 玩家全场景统计视图
|
||||
CREATE VIEW IF NOT EXISTS v_player_all_stats AS
|
||||
SELECT
|
||||
steam_id_64,
|
||||
COUNT(DISTINCT match_id) as total_matches,
|
||||
AVG(rating) as avg_rating,
|
||||
AVG(kd_ratio) as avg_kd,
|
||||
AVG(kast) as avg_kast,
|
||||
SUM(kills) as total_kills,
|
||||
SUM(deaths) as total_deaths,
|
||||
SUM(assists) as total_assists,
|
||||
SUM(mvp_count) as total_mvps
|
||||
FROM fact_match_players
|
||||
GROUP BY steam_id_64;
|
||||
|
||||
-- 地图维度统计视图
|
||||
CREATE VIEW IF NOT EXISTS v_map_performance AS
|
||||
SELECT
|
||||
fmp.steam_id_64,
|
||||
fm.map_name,
|
||||
COUNT(*) as matches_on_map,
|
||||
AVG(fmp.rating) as avg_rating,
|
||||
AVG(fmp.kd_ratio) as avg_kd,
|
||||
SUM(CASE WHEN fmp.is_win THEN 1 ELSE 0 END) * 1.0 / COUNT(*) as win_rate
|
||||
FROM fact_match_players fmp
|
||||
JOIN fact_matches fm ON fmp.match_id = fm.match_id
|
||||
GROUP BY fmp.steam_id_64, fm.map_name;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、数据流与交叉引用
|
||||
|
||||
### 7.1 数据流示意图
|
||||
|
||||
```
|
||||
原始数据(output_arena/*/iframe_network.json)
|
||||
↓
|
||||
【L1层】L1.db: raw_iframe_network (1张表)
|
||||
└─ match_id (PK)
|
||||
└─ content (JSON全文)
|
||||
↓
|
||||
【L2层】L2.db: 9张核心表
|
||||
├─ dim_players (玩家维度, 75个字段)
|
||||
├─ dim_maps (地图维度)
|
||||
├─ fact_matches (比赛主表, 50+字段)
|
||||
├─ fact_match_teams (队伍信息)
|
||||
├─ fact_match_players (玩家比赛统计, 100+字段)
|
||||
├─ fact_match_players_t/ct (分阵营统计)
|
||||
├─ fact_rounds (回合主表, 统一Schema)
|
||||
├─ fact_round_events (事件流, 统一Schema)
|
||||
└─ fact_round_player_economy (经济快照, 统一Schema)
|
||||
↓
|
||||
【L3层】L3.db: 特征集市
|
||||
├─ dm_player_features (玩家画像, 150+特征)
|
||||
└─ fact_match_features (单场特征快照, 可选)
|
||||
```
|
||||
|
||||
### 7.2 JSON→L2字段映射表
|
||||
|
||||
| JSON路径 | L2表 | L2字段 | 数据源 | 处理器 |
|
||||
|---------|------|--------|-------|--------|
|
||||
| `data.main.match_code` | fact_matches | match_code | 公共 | match_processor |
|
||||
| `data.main.map` | fact_matches | map_name | 公共 | match_processor |
|
||||
| `data.group_1[].fight.rating` | fact_match_players | rating | 公共 | player_processor |
|
||||
| `data.group_1[].fight_t.kill` | fact_match_players_t | kills | 公共 | player_processor |
|
||||
| `data.<steamid>.kast` | fact_match_players | kast | VIP | player_processor |
|
||||
| `leetify_data.round_stat[].t_money_group` | fact_rounds | t_money_start | leetify | economy_processor |
|
||||
| `leetify_data.round_stat[].bron_equipment` | fact_round_player_economy | equipment_value | leetify | economy_processor |
|
||||
| `leetify_data.round_stat[].show_event[].kill_event` | fact_round_events | weapon, is_headshot | leetify | event_processor |
|
||||
| `leetify_data.round_stat[].show_event[].killer_score_change` | fact_round_events | score_change_attacker | leetify | event_processor |
|
||||
| `round_list[].all_kill[].attacker.pos.x` | fact_round_events | attacker_pos_x | classic | spatial_processor |
|
||||
| `round_list[].c4_event[]` | fact_round_events | event_type='bomb_plant' | classic | event_processor |
|
||||
|
||||
### 7.3 L2→L3特征映射表
|
||||
|
||||
| L3特征字段 | 数据源(L2表) | 计算逻辑 | 处理器 |
|
||||
|-----------|-------------|---------|--------|
|
||||
| `basic_avg_rating` | fact_match_players.rating | AVG() | basic_processor |
|
||||
| `basic_headshot_rate` | fact_match_players | SUM(headshot_count)/SUM(kills) | basic_processor |
|
||||
| `sta_last_30_rating` | fact_match_players + fact_matches.start_time | ORDER BY start_time LIMIT 30 | sta_processor |
|
||||
| `sta_rating_volatility` | fact_match_players.rating | STDDEV(last_10_ratings) | sta_processor |
|
||||
| `bat_kd_diff_high_elo` | fact_match_players + fact_match_teams.group_origin_elo | 对最高elo对手的击杀-被杀 | bat_processor |
|
||||
| `hps_clutch_win_rate_1v1` | fact_round_events + fact_rounds.winner_side | 识别1v1场景+胜负统计 | hps_processor |
|
||||
| `ptl_pistol_win_rate` | fact_rounds(round_num=1,13) + fact_match_players | 手枪局胜率 | ptl_processor |
|
||||
| `side_kd_diff_ct_t` | fact_match_players_ct.kd_ratio - fact_match_players_t.kd_ratio | 阵营KD差 | side_processor |
|
||||
| `eco_avg_damage_per_1k` | fact_round_player_economy.equipment_value + fact_match_players.damage_total | damage/equipment_value*1000 | eco_processor |
|
||||
| `pace_opening_kill_time` | fact_round_events.event_time (first kill) | AVG(首次击杀时间) | pace_processor |
|
||||
|
||||
---
|
||||
|
||||
## 八、实施步骤
|
||||
|
||||
### Phase 1: 目录与命名标准化 (1-2小时)
|
||||
1. **重命名数据库文件**:
|
||||
- `database/L1A/L1A.sqlite` → `database/L1/L1.db`
|
||||
- `database/L2/L2_Main.sqlite` → `database/L2/L2.db`
|
||||
- `database/L3/L3_Features.sqlite` → `database/L3/L3.db`
|
||||
2. **重命名Builder脚本**:
|
||||
- `L1A_Builder.py` → `L1_Builder.py`
|
||||
3. **更新所有引用路径**:
|
||||
- `web/config.py`
|
||||
- `Force_Rebuild.py`
|
||||
- 各Builder脚本内部路径
|
||||
4. **创建processor目录结构**:
|
||||
```bash
|
||||
mkdir database/L2/processors
|
||||
mkdir database/L3/processors
|
||||
touch database/L2/processors/__init__.py
|
||||
touch database/L3/processors/__init__.py
|
||||
```
|
||||
5. **创建L1B预留目录**:
|
||||
- 创建`database/L1B/README.md`说明用途
|
||||
|
||||
### Phase 2: L2 Schema优化 (2-3小时)
|
||||
1. **修改`database/L2/schema.sql`**:
|
||||
- 更新`fact_rounds`增加leetify/classic差异字段
|
||||
- 更新`fact_round_events`增加坐标和评分字段
|
||||
- 更新`fact_round_player_economy`增加data_source_type和equipment_snapshot_json
|
||||
- 新增VIEW: `v_player_all_stats`, `v_map_performance`
|
||||
2. **验证Schema兼容性**:
|
||||
- 创建测试数据库执行新Schema
|
||||
- 确认外键约束和CHECK约束正常
|
||||
|
||||
### Phase 3: L2 Processor开发 (8-10小时)
|
||||
按依赖顺序开发:
|
||||
1. **match_processor.py** (1h):
|
||||
- 从L2_Builder.py提取`_parse_base_info()`逻辑
|
||||
- 实现`process(match_data, conn)`接口
|
||||
2. **player_processor.py** (2h):
|
||||
- 提取`_parse_players_base()`, `_parse_players_vip()`
|
||||
- 合并fight/fight_t/fight_ct
|
||||
- 处理dim_players UPSERT
|
||||
3. **round_processor.py** (0.5h):
|
||||
- 实现数据源分发逻辑
|
||||
4. **economy_processor.py** (2h):
|
||||
- 解析leetify bron_equipment
|
||||
- 计算equipment_value
|
||||
- 写入fact_round_player_economy
|
||||
5. **event_processor.py** (2h):
|
||||
- 统一处理leetify和classic的kill事件
|
||||
- 提取bomb_plant/defuse事件
|
||||
- 生成UUID event_id
|
||||
6. **spatial_processor.py** (1h):
|
||||
- 提取classic的xyz坐标
|
||||
- 关联到fact_round_events
|
||||
7. **L2_Builder.py重构** (1.5h):
|
||||
- 瘦身至~300行
|
||||
- 调用各processor
|
||||
- 实现错误处理和日志
|
||||
|
||||
### Phase 4: L3 Processor开发 (12-15小时)
|
||||
1. **basic_processor.py** (1.5h):
|
||||
- 实现42个基础特征计算
|
||||
- SQL聚合+pandas处理
|
||||
2. **sta_processor.py** (2h):
|
||||
- 时间序列分析
|
||||
- 滑动窗口计算
|
||||
3. **bat_processor.py** (2.5h):
|
||||
- 对手关系网络构建
|
||||
- 对决矩阵分析
|
||||
4. **hps_processor.py** (2.5h):
|
||||
- 场景识别(残局/赛点/连败)
|
||||
- 条件统计
|
||||
5. **ptl_processor.py** (1h):
|
||||
- 手枪局过滤
|
||||
- 武器类型判断
|
||||
6. **side_processor.py** (1.5h):
|
||||
- T/CT分表聚合
|
||||
- 差值计算
|
||||
7. **util_processor.py** (0.5h):
|
||||
- 简单聚合
|
||||
8. **eco_processor.py** (1h):
|
||||
- 经济分段逻辑
|
||||
- 性能关联
|
||||
9. **pace_processor.py** (1.5h):
|
||||
- 事件时间戳分析
|
||||
- 时间窗口划分
|
||||
10. **L3_Builder.py重构** (1h):
|
||||
- 调度各processor
|
||||
- 批量更新dm_player_features
|
||||
|
||||
### Phase 5: Web Services解耦 (4-5小时)
|
||||
1. **feature_service.py瘦身** (2h):
|
||||
- 移除所有计算逻辑
|
||||
- 保留查询功能
|
||||
- 更新单元测试
|
||||
2. **stats_service.py优化** (1.5h):
|
||||
- 改用L2 VIEW查询
|
||||
- 简化聚合逻辑
|
||||
3. **路由层适配** (1h):
|
||||
- 更新`web/routes/players.py`等
|
||||
- 确认profile页面正常渲染
|
||||
4. **缓存策略** (0.5h):
|
||||
- 考虑L3特征的缓存机制
|
||||
|
||||
### Phase 6: 测试与验证 (3-4小时)
|
||||
1. **单元测试**:
|
||||
- 为每个processor编写测试用例
|
||||
- Mock数据验证输出
|
||||
2. **集成测试**:
|
||||
- 完整运行L1→L2→L3 pipeline
|
||||
- 对比重构前后特征值
|
||||
3. **数据质量校验**:
|
||||
- 运行`verify_L2.py`
|
||||
- 检查字段覆盖率
|
||||
4. **性能测试**:
|
||||
- 测量pipeline耗时
|
||||
- 优化SQL查询
|
||||
|
||||
### Phase 7: 文档与交付 (2小时)
|
||||
1. **更新README.md**:
|
||||
- 新的目录结构
|
||||
- Processor模块说明
|
||||
2. **编写Processor README**:
|
||||
- `database/L2/processors/README.md`
|
||||
- `database/L3/processors/README.md`
|
||||
3. **API文档更新**:
|
||||
- web/services API变更说明
|
||||
4. **Schema映射表**:
|
||||
- 生成完整的JSON→L2→L3字段映射Excel
|
||||
|
||||
---
|
||||
|
||||
## 九、风险与注意事项
|
||||
|
||||
### 9.1 数据一致性
|
||||
- **风险**: 重构过程中Schema变化可能导致旧数据不兼容
|
||||
- **缓解**:
|
||||
- 使用`Force_Rebuild.py`全量重建
|
||||
- 保留L1原始数据,随时可回溯
|
||||
|
||||
### 9.2 性能影响
|
||||
- **风险**: Processor模块化可能增加函数调用开销
|
||||
- **缓解**:
|
||||
- 批量处理(一次处理多个match)
|
||||
- 使用executemany()优化INSERT
|
||||
- 关键路径使用SQL聚合而非Python循环
|
||||
|
||||
### 9.3 Leetify vs Classic覆盖率
|
||||
- **风险**: 部分特征(如eco, spatial)仅单数据源可用
|
||||
- **缓解**:
|
||||
- 在processor中判断data_source_type
|
||||
- 不可用特征标记为NULL
|
||||
- 文档中明确标注依赖
|
||||
|
||||
### 9.4 Web服务中断
|
||||
- **风险**: feature_service重构可能影响线上功能
|
||||
- **缓解**:
|
||||
- 先完成L2/L3 processor,再改web层
|
||||
- 使用特性开关(feature flag)
|
||||
- 灰度发布
|
||||
|
||||
---
|
||||
|
||||
## 十、预期成果
|
||||
|
||||
### 10.1 目录结构清晰
|
||||
```
|
||||
database/
|
||||
├── L1/ # 统一命名
|
||||
├── L1B/ # 预留清晰
|
||||
├── L2/ # 模块化processors
|
||||
├── L3/ # 模块化processors
|
||||
└── Force_Rebuild.py
|
||||
```
|
||||
|
||||
### 10.2 Schema完备性
|
||||
- Round数据统一Schema,支持leetify和classic差异字段
|
||||
- 清晰的data_source_type标记
|
||||
- 完整的外键和约束
|
||||
|
||||
### 10.3 代码可维护性
|
||||
- L2_Builder.py从1470行降至~300行
|
||||
- L3_Builder.py从委托web服务改为调度本地processors
|
||||
- web/services从4000+行降至~1000行
|
||||
|
||||
### 10.4 可扩展性
|
||||
- 新增特征只需添加processor模块
|
||||
- 新增数据源只需扩展Schema和processor
|
||||
- L1B预留未来Demo解析管道
|
||||
|
||||
### 10.5 文档完整性
|
||||
- JSON→L2→L3完整映射表
|
||||
- 每个processor的功能和依赖说明
|
||||
- 数据流示意图
|
||||
|
||||
---
|
||||
|
||||
## 十一、后续优化方向
|
||||
|
||||
### 11.1 性能优化
|
||||
- 考虑L2/L3的materialized view(SQLite不原生支持,可手动实现)
|
||||
- 增量更新机制(当前为全量重建)
|
||||
- 并行处理多个match
|
||||
|
||||
### 11.2 功能扩展
|
||||
- L1B层完整设计(Demo解析)
|
||||
- 更多L3特征(FeatureRDD.md中的Phase 5内容)
|
||||
- 实时特征更新API
|
||||
|
||||
### 11.3 工具增强
|
||||
- 可视化Schema关系图
|
||||
- Processor依赖图生成
|
||||
- 自动化数据质量报告
|
||||
|
||||
---
|
||||
|
||||
## 总结
|
||||
|
||||
本计划提供了从目录结构、Schema设计、代码重构到测试交付的完整路径。核心目标是:
|
||||
1. **标准化**: 统一命名和目录结构
|
||||
2. **模块化**: 按功能域拆分processor
|
||||
3. **解耦**: 将计算逻辑从web层下沉到database层
|
||||
4. **可扩展**: 为未来数据源和特征预留扩展点
|
||||
|
||||
预计总工时: **35-40小时**,可分阶段实施,每个Phase独立可验证。
|
||||
Reference in New Issue
Block a user