# L3 Feature Mart - Complete Architecture Plan > **Version**: 2.0 (Complete Redesign) > **Date**: 2026-01-28 > **Status**: Planning Phase --- ## Executive Summary 基于完整的L2 schema和Profile需求,重新设计L3特征层架构。核心原则: 1. **去除冗余**:消除Profile_summary.md中的重复指标 2. **深度挖掘**:利用L2的rounds/events数据进行深层次特征工程 3. **模块化计算**:按照功能域拆分processor,清晰的职责边界 4. **服务解耦**:web/services只做查询,不做计算 --- ## Part 1: 特征维度重构分析 ### 1.1 现有Profile问题诊断 **重复指标识别**: ``` - basic_avg_rating 在 Dashboard + Core Performance 重复 - basic_avg_kd 在 Dashboard + Core Performance 重复 - basic_avg_adr 在 Dashboard + Core Performance 重复 - basic_avg_kast 在 Dashboard + Core Performance 重复 - FK/FD 在 Opening Impact + SIDE Preference 重复 - Clutch 数据在 Multi-Frag + HPS + SPECIAL 重复 - 多个"率"类指标可从原始count计算,不需存储 ``` **缺失维度识别**: ``` ✗ 地图热力维度(基于xyz坐标) ✗ 武器偏好深度分析(不仅是top5) ✗ 对手强度分层表现(基于ELO差值) ✗ 时间序列波动分析(不仅是volatility) ✗ 队友协同效应(assist network) ✗ 经济效率分层(不同价位段表现) ✗ 回合贡献度评分(综合impact) ``` ### 1.2 重构后的特征分类体系 #### 🎯 Tier 1: 核心基础层 (CORE) **目标**:最常用的聚合统计,直接从fact_match_players计算 | 特征组 | 指标数量 | 典型指标 | L2来源表 | |--------|---------|---------|---------| | Basic Stats | 15 | rating, kd, adr, kast, rws, hs% | fact_match_players | | Match Stats | 8 | total_matches, win_rate, avg_duration | fact_matches + fact_match_players | | Weapon Stats | 12 | awp_kills, knife_kills, zeus_kills, top_weapon | fact_match_players + fact_round_events | | Objective Stats | 6 | plants, defuses, mvps, flash_assists | fact_match_players | **特点**: - 单表或简单JOIN即可计算 - 无复杂逻辑,纯聚合函数 - 用于Dashboard快速展示 #### 🔥 Tier 2: 战术能力层 (TACTICAL) **目标**:反映玩家战术素养的深度指标 | 特征组 | 指标数量 | 典型指标 | 计算复杂度 | |--------|---------|---------|-----------| | Opening Impact | 8 | fk_rate, fd_rate, fk_success_rate, entry_trade_rate | 中 | | Multi-Kill | 6 | 2k/3k/4k/5k rates, ace_count | 低 | | Clutch Performance | 10 | 1v1~1v5 win_rate, clutch_impact_score | 中 | | Utility Mastery | 12 | nade_dmg_per_round, flash_efficiency, smoke_timing | 高 | | Economy Efficiency | 8 | dmg_per_1k, eco_kd, force_buy_performance | 中 | **特点**: - 需要JOIN多表(players + events + economy) - 涉及条件筛选和比率计算 - 反映玩家决策质量 #### 🧠 Tier 3: 高级智能层 (INTELLIGENCE) **目标**:通过复杂计算提取隐藏模式 | 特征组 | 指标数量 | 典型指标 | 数据源 | |--------|---------|---------|--------| | High IQ Kills | 8 | wallbang_rate, smoke_kill_rate, blind_kill_rate, iq_score | fact_round_events (flags) | | Timing Analysis | 12 | kill_time_distribution, death_timing_pattern, aggression_index | fact_round_events (event_time) | | Pressure Performance | 10 | comeback_kd, losing_streak_kd, matchpoint_kpr | fact_rounds + fact_round_events | | Position Mastery | 15 | position_heatmap, site_control_rate, rotation_efficiency | fact_round_events (xyz) | | Trade Network | 8 | trade_kill_rate, trade_response_time, teamwork_score | fact_round_events (self-join) | **特点**: - 需要时间窗口计算(5s/10s trade window) - 涉及空间分析(xyz聚类) - 需要序列分析(连败/追分场景) #### 📊 Tier 4: 稳定性与元数据层 (META) **目标**:长期表现模式和元特征 | 特征组 | 指标数量 | 典型指标 | 计算方式 | |--------|---------|---------|---------| | Stability | 8 | rating_volatility, map_stability, recent_form | 时间序列STDDEV/滑动窗口 | | Side Preference | 14 | ct_rating, t_rating, side_kd_diff, side_win_diff | fact_match_players_ct/t | | Opponent Adaptation | 12 | performance_vs_elo_tiers, rank_diff_impact | fact_match_teams (elo) | | Map Specialization | 10 | map_rating_by_map, best_map, worst_map | GROUP BY map | | Session Pattern | 8 | daily_performance, streak_analysis, fatigue_index | 时间戳分组 | **特点**: - 跨match维度聚合 - 需要分层/分组分析 - 涉及时间序列特征 #### 🎨 Tier 5: 综合评分层 (COMPOSITE) **目标**:多维度加权综合评分,用于雷达图 | 评分维度 | 权重组成 | 输出范围 | 用途 | |---------|---------|---------|------| | AIM (枪法) | 25% Rating + 20% KD + 15% ADR + 10% DuelWin + 10% HighEloKD + 20% MultiKill | 0-100 | Radar Axis | | CLUTCH (残局) | 25% 1v3+ + 20% MatchPtWin + 20% ComebackKD + 15% PressureEntry + 20% Rating | 0-100 | Radar Axis | | PISTOL (手枪) | 30% PistolKills + 30% PistolWin + 20% PistolKD + 20% PistolHS% | 0-100 | Radar Axis | | DEFENSE (防守) | 35% CT_Rating + 35% T_Rating + 15% CT_FK + 15% T_FK | 0-100 | Radar Axis | | UTIL (道具) | 35% UsageRate + 25% NadeDmg + 20% FlashEff + 20% FlashEnemy | 0-100 | Radar Axis | | STABILITY (稳定) | 30% (100-Volatility) + 30% LossRating + 20% WinRating + 20% Consistency | 0-100 | Radar Axis | | ECONOMY (经济) | 50% Dmg/$1k + 30% EcoKPR + 20% SaveRoundKD | 0-100 | Radar Axis | | PACE (节奏) | 40% EntryTiming + 30% TradeSpeed + 30% AggressionIndex | 0-100 | Radar Axis | **特点**: - 依赖Tier 1-4的基础特征 - 标准化 + 加权 = 0-100评分 - 最后计算,存储为独立字段 --- ## Part 2: L3 Table Schema Design ### 2.1 主表:dm_player_features **设计原则**: - 一个player一行,steam_id_64为主键 - 包含所有聚合特征(200+列) - 按照Tier分组组织列 - 添加元数据列(matches_count, last_updated等) ```sql CREATE TABLE dm_player_features ( -- 主键与元数据 steam_id_64 TEXT PRIMARY KEY, total_matches INTEGER NOT NULL DEFAULT 0, total_rounds INTEGER NOT NULL DEFAULT 0, first_match_date INTEGER, -- Unix timestamp last_match_date INTEGER, last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- ========================================== -- Tier 1: CORE - Basic Stats (15 columns) -- ========================================== core_avg_rating REAL DEFAULT 0.0, core_avg_rating2 REAL DEFAULT 0.0, core_avg_kd REAL DEFAULT 0.0, core_avg_adr REAL DEFAULT 0.0, core_avg_kast REAL DEFAULT 0.0, core_avg_rws REAL DEFAULT 0.0, core_avg_hs_kills REAL DEFAULT 0.0, core_hs_rate REAL DEFAULT 0.0, -- hs/total_kills core_total_kills INTEGER DEFAULT 0, core_total_deaths INTEGER DEFAULT 0, core_total_assists INTEGER DEFAULT 0, core_avg_assists REAL DEFAULT 0.0, core_kpr REAL DEFAULT 0.0, -- kills per round core_dpr REAL DEFAULT 0.0, -- deaths per round core_survival_rate REAL DEFAULT 0.0, -- survived rounds / total rounds -- Match Stats (8 columns) core_win_rate REAL DEFAULT 0.0, core_wins INTEGER DEFAULT 0, core_losses INTEGER DEFAULT 0, core_avg_match_duration INTEGER DEFAULT 0, -- seconds core_avg_mvps REAL DEFAULT 0.0, core_mvp_rate REAL DEFAULT 0.0, -- mvps per match core_avg_elo_change REAL DEFAULT 0.0, core_total_elo_gained REAL DEFAULT 0.0, -- Weapon Stats (12 columns) core_avg_awp_kills REAL DEFAULT 0.0, core_awp_usage_rate REAL DEFAULT 0.0, -- rounds with AWP / total rounds core_avg_knife_kills REAL DEFAULT 0.0, core_avg_zeus_kills REAL DEFAULT 0.0, core_zeus_buy_rate REAL DEFAULT 0.0, core_top_weapon TEXT, -- Most used weapon name core_top_weapon_kills INTEGER DEFAULT 0, core_top_weapon_hs_rate REAL DEFAULT 0.0, core_weapon_diversity REAL DEFAULT 0.0, -- Shannon entropy of weapon usage core_rifle_hs_rate REAL DEFAULT 0.0, core_pistol_hs_rate REAL DEFAULT 0.0, core_smg_kills_total INTEGER DEFAULT 0, -- Objective Stats (6 columns) core_avg_plants REAL DEFAULT 0.0, core_avg_defuses REAL DEFAULT 0.0, core_avg_flash_assists REAL DEFAULT 0.0, core_plant_success_rate REAL DEFAULT 0.0, -- plants / T rounds core_defuse_success_rate REAL DEFAULT 0.0, -- defuses / (CT rounds with plant) core_objective_impact REAL DEFAULT 0.0, -- Weighted score: 2*plant + 3*defuse + 0.5*flash_assist -- ========================================== -- Tier 2: TACTICAL - Opening Impact (8) -- ========================================== tac_avg_fk REAL DEFAULT 0.0, -- first kills per match tac_avg_fd REAL DEFAULT 0.0, -- first deaths per match tac_fk_rate REAL DEFAULT 0.0, -- FK / (FK + FD) tac_fd_rate REAL DEFAULT 0.0, -- FD / (FK + FD) tac_fk_success_rate REAL DEFAULT 0.0, -- team win rate when player gets FK tac_entry_kill_rate REAL DEFAULT 0.0, -- entry_kills per T round tac_entry_death_rate REAL DEFAULT 0.0, tac_opening_duel_winrate REAL DEFAULT 0.0, -- entry_kills / (entry_kills + entry_deaths) -- Multi-Kill (6) tac_avg_2k REAL DEFAULT 0.0, tac_avg_3k REAL DEFAULT 0.0, tac_avg_4k REAL DEFAULT 0.0, tac_avg_5k REAL DEFAULT 0.0, tac_multikill_rate REAL DEFAULT 0.0, -- (2k+3k+4k+5k) / rounds tac_ace_count INTEGER DEFAULT 0, -- Clutch Performance (10) tac_clutch_1v1_attempts INTEGER DEFAULT 0, tac_clutch_1v1_wins INTEGER DEFAULT 0, tac_clutch_1v1_rate REAL DEFAULT 0.0, -- wins / attempts tac_clutch_1v2_attempts INTEGER DEFAULT 0, tac_clutch_1v2_wins INTEGER DEFAULT 0, tac_clutch_1v2_rate REAL DEFAULT 0.0, tac_clutch_1v3_plus_attempts INTEGER DEFAULT 0, -- 1v3+1v4+1v5 combined tac_clutch_1v3_plus_wins INTEGER DEFAULT 0, tac_clutch_1v3_plus_rate REAL DEFAULT 0.0, tac_clutch_impact_score REAL DEFAULT 0.0, -- Weighted: 1v1*1 + 1v2*3 + 1v3*7 + 1v4*15 + 1v5*30 -- Utility Mastery (12) tac_util_flash_per_round REAL DEFAULT 0.0, tac_util_smoke_per_round REAL DEFAULT 0.0, tac_util_molotov_per_round REAL DEFAULT 0.0, tac_util_he_per_round REAL DEFAULT 0.0, tac_util_usage_rate REAL DEFAULT 0.0, -- Total nades / rounds tac_util_nade_dmg_per_round REAL DEFAULT 0.0, tac_util_nade_dmg_per_nade REAL DEFAULT 0.0, tac_util_flash_time_per_round REAL DEFAULT 0.0, tac_util_flash_enemies_per_round REAL DEFAULT 0.0, tac_util_flash_efficiency REAL DEFAULT 0.0, -- flash_enemies / flash_usage tac_util_smoke_timing_score REAL DEFAULT 0.0, -- Based on smoke usage in execute (40-60s) tac_util_impact_score REAL DEFAULT 0.0, -- Composite utility impact -- Economy Efficiency (8) tac_eco_dmg_per_1k REAL DEFAULT 0.0, -- damage / (equipment_value / 1000) tac_eco_kpr_eco_rounds REAL DEFAULT 0.0, -- KPR when equipment < $2000 tac_eco_kd_eco_rounds REAL DEFAULT 0.0, tac_eco_kpr_force_rounds REAL DEFAULT 0.0, -- $2000-$4000 tac_eco_kpr_full_rounds REAL DEFAULT 0.0, -- $4000+ tac_eco_save_discipline REAL DEFAULT 0.0, -- % of eco rounds with proper save tac_eco_force_success_rate REAL DEFAULT 0.0, -- Win rate in force buy rounds tac_eco_efficiency_score REAL DEFAULT 0.0, -- Composite economic efficiency -- ========================================== -- Tier 3: INTELLIGENCE - High IQ Kills (8) -- ========================================== int_wallbang_kills INTEGER DEFAULT 0, int_wallbang_rate REAL DEFAULT 0.0, -- wallbang / total_kills int_smoke_kills INTEGER DEFAULT 0, int_smoke_kill_rate REAL DEFAULT 0.0, int_blind_kills INTEGER DEFAULT 0, int_blind_kill_rate REAL DEFAULT 0.0, int_noscope_kills INTEGER DEFAULT 0, int_noscope_rate REAL DEFAULT 0.0, -- noscope / awp_kills int_high_iq_score REAL DEFAULT 0.0, -- Weighted: wallbang*3 + smoke*2 + blind*1.5 + noscope*2 -- Timing Analysis (12) int_timing_early_kills INTEGER DEFAULT 0, -- 0-30s int_timing_mid_kills INTEGER DEFAULT 0, -- 30-60s int_timing_late_kills INTEGER DEFAULT 0, -- 60s+ int_timing_early_kill_share REAL DEFAULT 0.0, int_timing_mid_kill_share REAL DEFAULT 0.0, int_timing_late_kill_share REAL DEFAULT 0.0, int_timing_avg_kill_time REAL DEFAULT 0.0, -- Avg seconds from round start int_timing_early_deaths INTEGER DEFAULT 0, int_timing_early_death_rate REAL DEFAULT 0.0, int_timing_aggression_index REAL DEFAULT 0.0, -- early_kills / early_deaths int_timing_patience_score REAL DEFAULT 0.0, -- late_kills / total_kills int_timing_first_contact_time REAL DEFAULT 0.0, -- Avg time to first engagement -- Pressure Performance (10) int_pressure_comeback_kd REAL DEFAULT 0.0, -- KD when down 4+ rounds int_pressure_comeback_rating REAL DEFAULT 0.0, int_pressure_losing_streak_kd REAL DEFAULT 0.0, -- KD during 3+ round loss streak int_pressure_matchpoint_kpr REAL DEFAULT 0.0, -- KPR at match point (15-X or 12-X) int_pressure_matchpoint_rating REAL DEFAULT 0.0, int_pressure_clutch_composure REAL DEFAULT 0.0, -- Clutch rate in must-win situations int_pressure_entry_in_loss REAL DEFAULT 0.0, -- FK rate in losing matches int_pressure_performance_index REAL DEFAULT 0.0, -- Composite pressure metric int_pressure_big_moment_score REAL DEFAULT 0.0, -- Weighted matchpoint + comeback performance int_pressure_tilt_resistance REAL DEFAULT 0.0, -- rating_in_loss / rating_in_win -- Position Mastery (15) - Based on xyz clustering int_pos_site_a_control_rate REAL DEFAULT 0.0, -- % of rounds controlling A site int_pos_site_b_control_rate REAL DEFAULT 0.0, int_pos_mid_control_rate REAL DEFAULT 0.0, int_pos_favorite_position TEXT, -- Most common position cluster int_pos_position_diversity REAL DEFAULT 0.0, -- Entropy of position usage int_pos_rotation_speed REAL DEFAULT 0.0, -- Avg distance traveled between kills int_pos_map_coverage REAL DEFAULT 0.0, -- % of map areas visited int_pos_defensive_positioning REAL DEFAULT 0.0, -- CT: avg distance from site int_pos_aggressive_positioning REAL DEFAULT 0.0, -- T: avg distance pushed int_pos_lurk_tendency REAL DEFAULT 0.0, -- % of rounds alone vs teammates int_pos_site_anchor_score REAL DEFAULT 0.0, -- Consistency holding site int_pos_entry_route_diversity REAL DEFAULT 0.0, -- Different entry paths used int_pos_retake_positioning REAL DEFAULT 0.0, -- Performance in retake scenarios int_pos_postplant_positioning REAL DEFAULT 0.0, -- Position quality after plant int_pos_spatial_iq_score REAL DEFAULT 0.0, -- Composite positioning intelligence -- Trade Network (8) int_trade_kill_count INTEGER DEFAULT 0, -- Kills within 5s of teammate death int_trade_kill_rate REAL DEFAULT 0.0, -- trade_kills / total_kills int_trade_response_time REAL DEFAULT 0.0, -- Avg seconds to trade teammate int_trade_given_count INTEGER DEFAULT 0, -- Deaths traded by teammate int_trade_given_rate REAL DEFAULT 0.0, -- traded_deaths / total_deaths int_trade_balance REAL DEFAULT 0.0, -- trades_given - trades_made int_trade_efficiency REAL DEFAULT 0.0, -- (trade_kills + traded_deaths) / (total_kills + deaths) int_teamwork_score REAL DEFAULT 0.0, -- Composite teamwork metric -- ========================================== -- Tier 4: META - Stability (8) -- ========================================== meta_rating_volatility REAL DEFAULT 0.0, -- STDDEV of last 20 matches meta_recent_form_rating REAL DEFAULT 0.0, -- AVG of last 10 matches meta_win_rating REAL DEFAULT 0.0, -- AVG rating in wins meta_loss_rating REAL DEFAULT 0.0, -- AVG rating in losses meta_rating_consistency REAL DEFAULT 0.0, -- 100 - volatility_normalized meta_time_rating_correlation REAL DEFAULT 0.0, -- Correlation(match_time, rating) meta_map_stability REAL DEFAULT 0.0, -- STDDEV of rating across maps meta_elo_tier_stability REAL DEFAULT 0.0, -- STDDEV of rating across opponent ELO tiers -- Side Preference (14) meta_side_ct_rating REAL DEFAULT 0.0, meta_side_t_rating REAL DEFAULT 0.0, meta_side_ct_kd REAL DEFAULT 0.0, meta_side_t_kd REAL DEFAULT 0.0, meta_side_ct_win_rate REAL DEFAULT 0.0, meta_side_t_win_rate REAL DEFAULT 0.0, meta_side_ct_fk_rate REAL DEFAULT 0.0, -- FK per CT round meta_side_t_fk_rate REAL DEFAULT 0.0, meta_side_ct_kast REAL DEFAULT 0.0, meta_side_t_kast REAL DEFAULT 0.0, meta_side_rating_diff REAL DEFAULT 0.0, -- CT - T meta_side_kd_diff REAL DEFAULT 0.0, meta_side_preference TEXT, -- 'CT', 'T', or 'Balanced' meta_side_balance_score REAL DEFAULT 0.0, -- 100 - ABS(CT_rating - T_rating)*50 -- Opponent Adaptation (12) meta_opp_vs_lower_elo_rating REAL DEFAULT 0.0, -- vs opponents -200 ELO meta_opp_vs_similar_elo_rating REAL DEFAULT 0.0, -- vs ±200 ELO meta_opp_vs_higher_elo_rating REAL DEFAULT 0.0, -- vs +200 ELO meta_opp_vs_lower_elo_kd REAL DEFAULT 0.0, meta_opp_vs_similar_elo_kd REAL DEFAULT 0.0, meta_opp_vs_higher_elo_kd REAL DEFAULT 0.0, meta_opp_elo_adaptation REAL DEFAULT 0.0, -- higher_elo_rating / lower_elo_rating meta_opp_stomping_score REAL DEFAULT 0.0, -- Performance vs weaker opponents meta_opp_upset_score REAL DEFAULT 0.0, -- Performance vs stronger opponents meta_opp_consistency_across_elos REAL DEFAULT 0.0, -- 100 - STDDEV(rating by elo tier) meta_opp_rank_resistance REAL DEFAULT 0.0, -- Win rate vs higher ELO meta_opp_smurf_detection REAL DEFAULT 0.0, -- Abnormally high performance vs lower ELO -- Map Specialization (10) meta_map_best_map TEXT, meta_map_best_rating REAL DEFAULT 0.0, meta_map_worst_map TEXT, meta_map_worst_rating REAL DEFAULT 0.0, meta_map_diversity REAL DEFAULT 0.0, -- Entropy of map ratings meta_map_pool_size INTEGER DEFAULT 0, -- Number of maps with 5+ matches meta_map_specialist_score REAL DEFAULT 0.0, -- (best - worst) rating meta_map_versatility REAL DEFAULT 0.0, -- 100 - map_stability meta_map_comfort_zone_rate REAL DEFAULT 0.0, -- % of matches on top 3 maps meta_map_adaptation REAL DEFAULT 0.0, -- Avg rating on non-favorite maps -- Session Pattern (8) meta_session_avg_matches_per_day REAL DEFAULT 0.0, meta_session_longest_streak INTEGER DEFAULT 0, -- Days played consecutively meta_session_weekend_rating REAL DEFAULT 0.0, meta_session_weekday_rating REAL DEFAULT 0.0, meta_session_morning_rating REAL DEFAULT 0.0, -- 6-12h meta_session_afternoon_rating REAL DEFAULT 0.0, -- 12-18h meta_session_evening_rating REAL DEFAULT 0.0, -- 18-24h meta_session_night_rating REAL DEFAULT 0.0, -- 0-6h -- ========================================== -- Tier 5: COMPOSITE - Radar Scores (8) -- ========================================== score_aim REAL DEFAULT 0.0, -- 0-100 normalized score_clutch REAL DEFAULT 0.0, score_pistol REAL DEFAULT 0.0, score_defense REAL DEFAULT 0.0, score_utility REAL DEFAULT 0.0, score_stability REAL DEFAULT 0.0, score_economy REAL DEFAULT 0.0, score_pace REAL DEFAULT 0.0, -- Overall composite score_overall REAL DEFAULT 0.0, -- AVG of all 8 scores -- Performance tier classification tier_classification TEXT, -- 'Elite', 'Advanced', 'Intermediate', 'Beginner' tier_percentile REAL DEFAULT 0.0, -- Overall percentile rank -- Index for queries FOREIGN KEY (steam_id_64) REFERENCES dim_players(steam_id_64) ); CREATE INDEX idx_dm_player_features_rating ON dm_player_features(core_avg_rating DESC); CREATE INDEX idx_dm_player_features_matches ON dm_player_features(total_matches DESC); CREATE INDEX idx_dm_player_features_tier ON dm_player_features(tier_classification); ``` **列统计**: - Tier 1 CORE: 41 columns - Tier 2 TACTICAL: 44 columns - Tier 3 INTELLIGENCE: 53 columns - Tier 4 META: 52 columns - Tier 5 COMPOSITE: 11 columns - Meta + Keys: 6 columns - **Total: ~207 columns** ### 2.2 辅助表:dm_player_match_history **用途**:支持时间序列分析和趋势图 ```sql CREATE TABLE dm_player_match_history ( steam_id_64 TEXT, match_id TEXT, match_date INTEGER, -- Unix timestamp match_sequence INTEGER, -- Player's N-th match -- Core performance rating REAL, kd_ratio REAL, adr REAL, kast REAL, is_win BOOLEAN, -- Match context map_name TEXT, opponent_avg_elo REAL, teammate_avg_rating REAL, -- Cumulative stats (for moving averages) cumulative_rating REAL, -- AVG up to this match rolling_10_rating REAL, -- Last 10 matches AVG PRIMARY KEY (steam_id_64, match_id), FOREIGN KEY (steam_id_64) REFERENCES dm_players(steam_id_64), FOREIGN KEY (match_id) REFERENCES fact_matches(match_id) ); CREATE INDEX idx_player_history_player_date ON dm_player_match_history(steam_id_64, match_date DESC); ``` ### 2.3 辅助表:dm_player_map_stats **用途**:地图级别细分统计 ```sql CREATE TABLE dm_player_map_stats ( steam_id_64 TEXT, map_name TEXT, matches INTEGER DEFAULT 0, wins INTEGER DEFAULT 0, win_rate REAL DEFAULT 0.0, avg_rating REAL DEFAULT 0.0, avg_kd REAL DEFAULT 0.0, avg_adr REAL DEFAULT 0.0, avg_kast REAL DEFAULT 0.0, best_rating REAL DEFAULT 0.0, worst_rating REAL DEFAULT 0.0, PRIMARY KEY (steam_id_64, map_name), FOREIGN KEY (steam_id_64) REFERENCES dm_players(steam_id_64) ); ``` ### 2.4 辅助表:dm_player_weapon_stats **用途**:武器使用统计(Top 10) ```sql CREATE TABLE dm_player_weapon_stats ( steam_id_64 TEXT, weapon_name TEXT, total_kills INTEGER DEFAULT 0, total_headshots INTEGER DEFAULT 0, hs_rate REAL DEFAULT 0.0, usage_rounds INTEGER DEFAULT 0, -- Rounds used this weapon usage_rate REAL DEFAULT 0.0, -- % of all rounds avg_kills_per_round REAL DEFAULT 0.0, -- When used effectiveness_score REAL DEFAULT 0.0, -- Composite weapon skill PRIMARY KEY (steam_id_64, weapon_name), FOREIGN KEY (steam_id_64) REFERENCES dm_players(steam_id_64) ); ``` --- ## Part 3: Processor Architecture ### 3.1 Processor职责划分 ``` L3_Builder.py (主控) ├── BasicProcessor (Tier 1: CORE) │ ├── calculate_basic_stats() │ ├── calculate_match_stats() │ ├── calculate_weapon_stats() │ └── calculate_objective_stats() │ ├── TacticalProcessor (Tier 2: TACTICAL) │ ├── calculate_opening_impact() │ ├── calculate_multikill() │ ├── calculate_clutch() │ ├── calculate_utility() │ └── calculate_economy() │ ├── IntelligenceProcessor (Tier 3: INTELLIGENCE) │ ├── calculate_high_iq_kills() │ ├── calculate_timing_analysis() │ ├── calculate_pressure_performance() │ ├── calculate_position_mastery() # Uses xyz │ └── calculate_trade_network() │ ├── MetaProcessor (Tier 4: META) │ ├── calculate_stability() │ ├── calculate_side_preference() │ ├── calculate_opponent_adaptation() │ ├── calculate_map_specialization() │ └── calculate_session_pattern() │ └── CompositeProcessor (Tier 5: COMPOSITE) ├── normalize_and_standardize() # Z-score normalization ├── calculate_radar_scores() # 8 dimensions └── classify_tier() # Elite/Advanced/Intermediate/Beginner ``` ### 3.2 Processor接口标准 每个processor实现统一接口: ```python class BaseFeatureProcessor: @staticmethod def calculate(steam_id: str, conn_l2: sqlite3.Connection) -> dict: """ 计算该processor负责的所有特征 Args: steam_id: 玩家Steam ID conn_l2: L2数据库连接 Returns: dict: {column_name: value, ...} """ pass ``` ### 3.3 依赖关系 ``` Tier 1 (CORE) → 无依赖,直接从L2计算 Tier 2 (TACTICAL) → 可能依赖Tier 1的total_rounds等基础值 Tier 3 (INTELLIGENCE) → 独立计算,从L2 events表 Tier 4 (META) → 依赖Tier 1的rating等基础统计 Tier 5 (COMPOSITE) → 依赖Tier 1-4的所有特征,最后计算 ``` **计算顺序**: 1. BasicProcessor (CORE) 2. TacticalProcessor + IntelligenceProcessor (并行,无依赖) 3. MetaProcessor (需要CORE的rating) 4. CompositeProcessor (需要所有前置特征) --- ## Part 4: Web Services 架构 ### 4.1 Service层重构 **原则**: - **Services只做查询,不做计算** - 复杂聚合逻辑在L3 Processor完成 - Service提供便捷的数据访问接口 ```python # web/services/player_service.py (新建) class PlayerService: """玩家特征查询服务""" @staticmethod def get_player_features(steam_id: str) -> dict: """获取玩家完整特征(dm_player_features一行)""" pass @staticmethod def get_player_radar_data(steam_id: str) -> dict: """获取雷达图数据(8个维度)""" pass @staticmethod def get_player_core_stats(steam_id: str) -> dict: """获取核心统计(Dashboard用)""" pass @staticmethod def get_player_history(steam_id: str, limit: int = 20) -> list: """获取最近N场历史(趋势图用)""" pass @staticmethod def get_player_map_stats(steam_id: str) -> list: """获取各地图统计""" pass @staticmethod def get_player_weapon_stats(steam_id: str, top_n: int = 10) -> list: """获取Top N武器统计""" pass @staticmethod def get_players_ranking( order_by: str = 'core_avg_rating', limit: int = 100, offset: int = 0 ) -> list: """获取玩家排行榜""" pass @staticmethod def compare_players(steam_ids: list) -> dict: """对比多个玩家的特征""" pass ``` ```python # web/services/stats_service.py (重构) class StatsService: """统计分析服务(保留现有L2查询方法)""" # 保留原有方法,用于match detail等非profile页面 @staticmethod def get_match_stats(match_id: str) -> dict: """获取比赛统计(从L2 fact_matches)""" pass @staticmethod def get_round_events(match_id: str, round_num: int) -> list: """获取回合事件(从L2 fact_round_events)""" pass # 新增:全局统计查询 @staticmethod def get_global_stats() -> dict: """全局统计:总场次、总玩家、平均rating等""" pass ``` ### 4.2 Routes层适配 ```python # web/routes/players.py (重构) from web.services.player_service import PlayerService @bp.route('/profile/') def player_profile(steam_id): """玩家Profile页面""" # 1. 获取玩家基本信息(dim_players) player_info = PlayerService.get_player_info(steam_id) # 2. 获取特征数据(dm_player_features) features = PlayerService.get_player_features(steam_id) # 3. 获取历史趋势(dm_player_match_history) history = PlayerService.get_player_history(steam_id, limit=20) # 4. 获取地图统计(dm_player_map_stats) map_stats = PlayerService.get_player_map_stats(steam_id) # 5. 获取武器统计(dm_player_weapon_stats) weapon_stats = PlayerService.get_player_weapon_stats(steam_id, top_n=10) return render_template('players/profile.html', player=player_info, features=features, history=history, map_stats=map_stats, weapon_stats=weapon_stats) @bp.route('/api/players//features') def api_player_features(steam_id): """API: 获取玩家特征(JSON)""" features = PlayerService.get_player_features(steam_id) return jsonify(features) @bp.route('/api/players/ranking') def api_ranking(): """API: 玩家排行榜""" order_by = request.args.get('order_by', 'core_avg_rating') limit = int(request.args.get('limit', 100)) offset = int(request.args.get('offset', 0)) players = PlayerService.get_players_ranking( order_by=order_by, limit=limit, offset=offset ) return jsonify(players) ``` ### 4.3 Template数据映射 **profile.html结构**: ```jinja2 {# Dashboard Cards #}
Rating: {{ features.core_avg_rating }}
K/D: {{ features.core_avg_kd }}
ADR: {{ features.core_avg_adr }}
KAST: {{ features.core_avg_kast }}%
{# Radar Chart #} {# Trend Chart #} {# Core Performance Section #}
Rating: {{ features.core_avg_rating | round(2) }}
K/D: {{ features.core_avg_kd | round(2) }}
KAST: {{ (features.core_avg_kast * 100) | round(1) }}%
RWS: {{ features.core_avg_rws | round(1) }}
ADR: {{ features.core_avg_adr | round(1) }}
{# Gunfight Section #}
Avg HS: {{ features.core_avg_hs_kills | round(1) }}
HS Rate: {{ (features.core_hs_rate * 100) | round(1) }}%
Assists: {{ features.core_avg_assists | round(1) }}
AWP K: {{ features.core_avg_awp_kills | round(1) }}
Knife K: {{ features.core_avg_knife_kills | round(2) }}
Zeus K: {{ features.core_avg_zeus_kills | round(2) }}
{# Opening Impact Section #}
FK: {{ features.tac_avg_fk | round(1) }}
FD: {{ features.tac_avg_fd | round(1) }}
FK Rate: {{ (features.tac_fk_rate * 100) | round(1) }}%
FD Rate: {{ (features.tac_fd_rate * 100) | round(1) }}%
{# Clutch Section #}
1v1: {{ features.tac_clutch_1v1_wins }}/{{ features.tac_clutch_1v1_attempts }} ({{ (features.tac_clutch_1v1_rate * 100) | round(1) }}%)
1v2: {{ features.tac_clutch_1v2_wins }}/{{ features.tac_clutch_1v2_attempts }} ({{ (features.tac_clutch_1v2_rate * 100) | round(1) }}%)
1v3+: {{ features.tac_clutch_1v3_plus_wins }}/{{ features.tac_clutch_1v3_plus_attempts }} ({{ (features.tac_clutch_1v3_plus_rate * 100) | round(1) }}%)
{# High IQ Kills Section #}
Wallbang: {{ features.int_wallbang_kills }} ({{ (features.int_wallbang_rate * 100) | round(2) }}%)
Smoke: {{ features.int_smoke_kills }} ({{ (features.int_smoke_kill_rate * 100) | round(2) }}%)
Blind: {{ features.int_blind_kills }} ({{ (features.int_blind_kill_rate * 100) | round(2) }}%)
NoScope: {{ features.int_noscope_kills }} ({{ (features.int_noscope_rate * 100) | round(2) }}%)
IQ Score: {{ features.int_high_iq_score | round(1) }}
{# Map Stats Section #} {% for map_stat in map_stats %}
{{ map_stat.map_name }} {{ map_stat.matches }}场 {{ (map_stat.win_rate * 100) | round(1) }}% {{ map_stat.avg_rating | round(2) }}
{% endfor %} {# Weapon Stats Section #} {% for weapon in weapon_stats %}
{{ weapon.weapon_name }} {{ weapon.total_kills }}击杀 {{ (weapon.hs_rate * 100) | round(1) }}% HS {{ (weapon.usage_rate * 100) | round(1) }}%使用率
{% endfor %} ``` --- ## Part 5: 实施计划 ### Phase 1: Schema & Infrastructure (1-2 days) 1. ✅ 创建L3 schema (dm_player_features + 辅助表) 2. ✅ 初始化L3.db 3. ✅ 创建processor基类 ### Phase 2: Core Processors (2-3 days) 1. 实现BasicProcessor (Tier 1) 2. 实现TacticalProcessor (Tier 2) 3. 测试基础特征计算 ### Phase 3: Advanced Processors (2-3 days) 1. 实现IntelligenceProcessor (Tier 3) 2. 实现MetaProcessor (Tier 4) 3. 实现CompositeProcessor (Tier 5) ### Phase 4: Services Refactoring (1-2 days) 1. 创建PlayerService 2. 重构StatsService 3. 更新Routes层 ### Phase 5: Testing & Validation (1 day) 1. 运行L3_Builder完整构建 2. 验证特征计算正确性 3. Performance测试 ### Phase 6: Frontend Integration (2 days) 1. 更新profile.html模板 2. 适配新的feature字段 3. 测试UI展示 --- ## Part 6: 关键技术点 ### 6.1 标准化与归一化 **Z-score标准化**(用于Composite Score): ```python def z_score_normalize(value, mean, std): """Z-score标准化到0-100""" if std == 0: return 50.0 z = (value - mean) / std # 将z-score映射到0-100,mean=50 normalized = 50 + (z * 15) # ±3σ覆盖约99.7% return max(0, min(100, normalized)) ``` ### 6.2 加权评分计算 **示例:AIM Score** ```python def calculate_aim_score(features, all_players_stats): """ AIM Score = 25% Rating + 20% KD + 15% ADR + 10% DuelWin + 10% HighEloKD + 20% MultiKill """ weights = { 'rating': 0.25, 'kd': 0.20, 'adr': 0.15, 'duel_win': 0.10, 'high_elo_kd': 0.10, 'multikill': 0.20 } # 分别标准化每个组件 rating_norm = z_score_normalize(features['core_avg_rating'], all_players_stats['rating_mean'], all_players_stats['rating_std']) kd_norm = z_score_normalize(features['core_avg_kd'], all_players_stats['kd_mean'], all_players_stats['kd_std']) # ... 其他组件 # 加权求和 aim_score = (rating_norm * weights['rating'] + kd_norm * weights['kd'] + # ... 其他) return aim_score ``` ### 6.3 时间窗口分析 **Trade Kill识别**(5秒窗口): ```sql WITH death_events AS ( SELECT match_id, round_num, event_time, victim_steam_id as dead_player, attacker_steam_id as killer FROM fact_round_events WHERE event_type = 'kill' AND victim_steam_id IN ( SELECT steam_id FROM team_mates -- 同队队友 ) ), trade_kills AS ( SELECT e1.attacker_steam_id, COUNT(*) as trade_count FROM fact_round_events e1 JOIN death_events d ON e1.match_id = d.match_id AND e1.round_num = d.round_num AND e1.victim_steam_id = d.killer -- 杀死队友的敌人 AND e1.event_time BETWEEN d.event_time AND d.event_time + 5 -- 5秒内 WHERE e1.event_type = 'kill' GROUP BY e1.attacker_steam_id ) ``` ### 6.4 位置聚类分析 **基于xyz的位置分类**: ```python from sklearn.cluster import DBSCAN import numpy as np def cluster_positions(xyz_data): """ 使用DBSCAN聚类识别常用位置 Args: xyz_data: [(x, y, z), ...] Returns: cluster_labels, position_names """ coords = np.array(xyz_data) # DBSCAN参数:eps=距离阈值,min_samples=最小点数 clustering = DBSCAN(eps=500, min_samples=5).fit(coords) labels = clustering.labels_ # 为每个cluster分配语义化名称(基于map区域) position_names = map_cluster_to_semantic_name(coords, labels) return labels, position_names ``` --- ## Part 7: 数据质量保证 ### 7.1 空值处理策略 ```python class SafeAggregator: @staticmethod def safe_divide(numerator, denominator, default=0.0): """安全除法""" if denominator == 0 or denominator is None: return default return numerator / denominator @staticmethod def safe_avg(values, default=0.0): """安全平均""" if not values or len(values) == 0: return default return sum(values) / len(values) ``` ### 7.2 最小样本量要求 ```python MIN_MATCHES_FOR_FEATURES = { 'core': 5, # 基础统计至少5场 'tactical': 10, # 战术分析至少10场 'intelligence': 15, # 智能分析至少15场 'meta': 20, # 元数据分析至少20场 'composite': 20, # 综合评分至少20场 } def check_sample_size(steam_id, tier): """检查是否满足最小样本量""" match_count = get_player_match_count(steam_id) return match_count >= MIN_MATCHES_FOR_FEATURES[tier] ``` --- ## Part 8: 性能优化策略 ### 8.1 批量计算 ```python # L3_Builder.py 主循环 def rebuild_all_features(): """批量重建所有玩家特征""" players = get_all_players() # 从dim_players获取 for player in players: steam_id = player['steam_id_64'] # 计算所有特征 features = {} features.update(BasicProcessor.calculate(steam_id, conn_l2)) features.update(TacticalProcessor.calculate(steam_id, conn_l2)) features.update(IntelligenceProcessor.calculate(steam_id, conn_l2)) features.update(MetaProcessor.calculate(steam_id, conn_l2)) features.update(CompositeProcessor.calculate(steam_id, conn_l2, features)) # 批量写入 upsert_player_features(steam_id, features) # 每100个玩家提交一次 if len(batch) >= 100: conn_l3.commit() ``` ### 8.2 增量更新 ```python def update_player_features_incremental(steam_id, new_match_id): """增量更新:仅计算新增match影响的特征""" # 1. 获取现有特征 old_features = get_player_features(steam_id) # 2. 计算新match的统计 new_match_stats = get_match_player_stats(new_match_id, steam_id) # 3. 增量更新(rolling average等) updated_features = incremental_update(old_features, new_match_stats) # 4. 更新数据库 upsert_player_features(steam_id, updated_features) ``` ### 8.3 查询优化 ```sql -- 创建必要的索引 CREATE INDEX idx_match_players_steam ON fact_match_players(steam_id_64); CREATE INDEX idx_round_events_attacker ON fact_round_events(attacker_steam_id); CREATE INDEX idx_round_events_victim ON fact_round_events(victim_steam_id); CREATE INDEX idx_round_events_time ON fact_round_events(match_id, round_num, event_time); ``` --- ## 总结 本架构方案实现了: ✅ **特征去重**:消除Profile中的所有重复指标 ✅ **深度挖掘**:利用rounds/events/economy数据进行高级特征工程 ✅ **模块化设计**:5层processor清晰分工,易于维护扩展 ✅ **服务解耦**:web/services只做查询,不做计算 ✅ **性能优化**:批量计算 + 增量更新 + 查询索引 ✅ **质量保证**:空值处理 + 最小样本量 + 标准化流程 **预期效果**: - L3表包含207列精心设计的特征 - 支持完整的Profile界面展示 - 计算性能:1000玩家约10-15分钟 - 查询性能:单玩家profile加载 < 100ms 下一步开始实施!