Files
tianxuan/.omo/plans/tianxiu-v4.md
T

9.3 KiB
Raw Blame History

天璇 v4 修复计划

TL;DR (For humans)

7个问题,24个todo。核心改动:IP子网实体聚合、多列实体、地球手动缩放、异步聚类修复、列类型值优先检测。


Problem & Approach

Intent: CLEAR — 用户列出7个具体问题,方案可从前端/后端代码推导。无需高精度审查。

Issue 1 — 聚类选非数值列报错

根因: _run_analysis_worker (views.py:502) 默认取前10非_开头的列;手动向导步骤2未过滤非数值列。_handle_run_clustering (tool_registry.py:787-791) 虽有数值过滤,但无列给用户时返回"无可用维度"且不提示哪些可用。 方案:

  • manual.html 步骤2特征列只展示数值列(标注dtype)
  • _handle_run_clustering 报错时返回可用数值列名清单
  • views.py 默认特征列选择排除实体列自身

Issue 2 — 地球问题 (4个子问题)

根因:

  • TLS流不显示 → globe_view 只用GeoIP,未用数据列经纬度
  • 经纬线 → Three.js未画辅助线
  • 滚轮缩放 → 无wheel事件处理
  • 复选框状态丢失 → GET表单→刷新页面→选中状态丢失 方案:
  • globe_view 优先用数据列src_latitude/src_longitude/dst_latitude/dst_longitude,回退GeoIP
  • 增强现有手动拖拽JS + 添加滚轮事件(不引入OrbitControls——three.min.js是UMD构建,OrbitControls需要ESM,不兼容)
  • 用 LineLoop 绘10度间隔经纬线
  • 模板端将 ?runs=1,2 参数回填到checkbox checked属性

Issue 3 — Django异步聚类失败

根因: _run_analysis_worker (views.py:503) 在线程中调 asyncio.run()_handle_run_clustering 本质是同步代码(polars/numpy/sklearn,无await)_handle_extract_features 内有 sync_to_async 用于ORM。 方案:

  • _handle_run_clustering 提取同步核心函数 _cluster_sync()worker直接调同步版
  • _handle_extract_featuresasgiref.sync.async_to_sync 包装

Issue 4 — 列类型靠列名而非数值

根因: type_classifier.py 优先级: config→名称匹配→值检测。名称匹配(如 _ip→IPv4)过于宽泛。 方案: 改为 config→值检测→名称匹配(仅值检测返回STRING时作为二次提示)。增加MAC地址、端口值模式。

Issue 5 — 数据列初步分析

方案: scripts/column_survey.py——standalone脚本,输出每列名称/dtype/唯一值数/空值率/前5非空样本。

Issue 6 — src_ip和dst_ip都作为实体

根因: entity_detector.py 只返回单 recommended_background_process (views.py:367) 只用单列。 实际状态: manual.html line 46 <select multiple> 已支持多选!_run_analysis_worker (views.py:464) 已处理 entity_columns 列表。gap仅在于 _background_processentity_detector方案:

  • entity_detector 增加 recommended_multi (前N候选)
  • _background_process 支持多列实体聚合
  • manual.html 确认页(步骤3)修复多选显示

Issue 7 — IP子网实体聚合 (/24 + /28)

根因: 无子网处理。IP直接作为实体标识。 方案:

  • Config新增 Entity 类,含 subnet_masksip_columns
  • entity_aggregator.py 新增 ip_to_subnet()apply_subnet_aggregation()
  • 在 group_by 之前将IP转换为子网前缀
  • 支持 /24 (0-255) 和 /28 (240-255)

Architecture & Design Decisions

Decision 1: IP子网聚合设计

  • 位置: entity_aggregator.pyaggregate_by_entity 之前
  • mask从 config 读取,支持 [24, 28]
  • 转换后的子网前缀替代原始IP:
    • ip_to_subnet('10.0.1.15', 24)'10.0.1.0/24'
    • ip_to_subnet('10.0.1.250', 28)'10.0.1.240/28'
    • 无效IP/None → 原值
# IP → subnet prefix
def ip_to_subnet(ip_str: str, mask: int) -> str:
    """Convert IP to CIDR subnet prefix."""
    if not ip_str or not isinstance(ip_str, str):
        return ip_str
    try:
        parts = [int(o) for o in ip_str.strip().split('.')]
        if len(parts) != 4:
            return ip_str
        if any(p < 0 or p > 255 for p in parts):
            return ip_str
        ip_int = (parts[0]<<24) + (parts[1]<<16) + (parts[2]<<8) + parts[3]
        subnet_int = ip_int & (0xFFFFFFFF << (32 - mask))
        return f"{(subnet_int>>24)&255}.{(subnet_int>>16)&255}.{(subnet_int>>8)&255}.{subnet_int&255}/{mask}"
    except (ValueError, IndexError, TypeError):
        return ip_str

Decision 2: 多列实体

  • EntityProfile.entity_value (max_length=512) 存储多列值: "src_ip=10.0.0.1||dst_ip=203.0.113.5"
  • AnalysisRun.entity_column (max_length=256) 存储逗号分隔: "src_ip,dst_ip"
  • unique_together = ['run', 'entity_value'] 自然支持多列唯一性

Decision 3: 值优先类型检测

优先级:

  1. Config override → 立即返回
  2. 值采样 → 按顺序检测: IPv4→MAC→HEX→URL→Port→BOOL_ENUM→ENUM→Float→STRING
  3. 名称匹配 → 仅值检测返回STRING时作为二次提示(如 _ip 后缀提示IPv4)
  4. STRING作为最终兜底

新增模式:

  • MAC: r'^([0-9A-Fa-f]{2}[:.-]){5}[0-9A-Fa-f]{2}$'
  • Port: 非空值全部在 1-65535 且全为整数 → ENUM
  • Float: >80% 样本可 float() 解析 → FLOAT

Decision 4: 地球缩放+旋转 (不引入OrbitControls)

重要: three.min.js (603KB) 是 UMD 独立构建,OrbitControls 是 three/examples/jsm/ 的 ESM 格式, 无法直接加载。两个可行方案已评估:

a) 下载 OrbitControls 到 static/ - 需要处理模块依赖链(Controls→Euler→...),不适用于离线场景 b) 增强现有手动拖拽JS + 添加滚轮缩放事件 (globe.html lines 101-110 已有拖拽骨架)

实施:

  • 保留并增强现有 mousedown/mousemove/mouseup 逻辑(已验证可用)
  • 添加 wheel 事件: camera.position.z += event.deltaY * 0.01 + clamp(3, 30)
  • 鼠标中键重置视角

Dependency Graph

独立阶段(可并行):
  Todo 1-2: 列分析脚本 ──── (无依赖)
  Todo 3-4: 值类型检测 ──── (无依赖)
  Todo 5-8: 地球修复 ────── (无依赖)
  Todo 9-10: 异步修复 ───── (无依赖)

顺序阶段:
  Todo 11-13: 子网聚合 ──── (无依赖,但避免与类型检测冲突,需确保IP列识别的正确性)
  Todo 14-17: 多列实体 ──── (依赖子网聚合的 IP→subnet 转换,因为多列中的IP列需要被子网处理)
  Todo 18-20: 聚类列过滤 ── (依赖多列实体,因为 entity 列需要从 feature 列中排除)

最终:
  Todo 21-24: 测试+文档 ─── (依赖所有)
  F1-F3: 最终验证 ───────── (依赖所有)

Todos

  • 1. 创建 scripts/column_survey.py: 对每列输出名称/dtype/唯一值数/空值率/前5样本
  • 2. QA column_survey: 在现有测试数据上有合理输出
  • 3. type_classifier.py: 值优先检测(IPv4→MAC→HEX→URL→Port→BOOL→ENUM→Float→STRING);名称降级为二次提示
  • 4. QA type_classifier: pytest tests/test_type_classifier.py
  • 5. globe.html: 添加wheel滚轮缩放事件 + 增强现有mousedown/move/up拖拽(不引入OrbitControls
  • 6. globe.html: 添加经纬线网格(10度间隔 LineLoop 绘制纬线圆+经线弧)
  • 7. globe.html + globe_view 修复: (a) 复选框提交后保留选中状态 (b) globe_view 优先用数据列经纬度
  • 8. QA globe: 打开 /globe/ 交互验证滚轮缩放+经纬线+复选框
  • 9. views.py + tool_registry.py: 提取 _cluster_sync() 同步核心 + async_to_sync(_handle_extract_features)
  • 10. QA async: 手动分析流程聚类步骤不报 asyncio.run() 错误
  • 11. config/loader.py: 新增 Config.Entity 类含 subnet_masks(list[int]) 和 ip_columns
  • 12. entity_aggregator.py: 新增 ip_to_subnet() 函数(含空值/无效IP处理)+ apply_subnet_aggregation()
  • 13. QA subnet: ip_to_subnet('10.0.1.15', 24) == '10.0.1.0/24' + ip_to_subnet(None, 24) == None
  • 14. entity_detector.py: 返回 recommended_multi(前3候选list);对IP列自动推荐多列
  • 15. views.py: _background_process 支持多列实体聚合;AnalysisRun.entity_column 存逗号分隔
  • 16. manual.html: 步骤3确认页展示多选实体列(entity_columns|join:", ")
  • 17. QA multi-col: 选 src_ip+dst_ip → 确认页显示两个 → 聚合 → 聚类 → 成功
  • 18. manual.html: 步骤2特征列只展示数值列(标注dtype如"bytes_sent (Int64)");排除entity列
  • 19. views.py + tool_registry.py: 聚类报错时返回可用数值列清单;views.py默认排除entity列
  • 20. QA cluster-col: 手动向导验证特征列仅数值列
  • 21. tests/test_type_classifier.py: 添加 MAC/端口/值优先测试
  • 22. tests/test_entity.py: 添加多列实体+IP子网测试
  • 23. tests/test_e2e.py: 添加多列实体→聚类端到端
  • 24. 更新 AGENTS.md 和 docs/工作流.md: 新增架构决策+已知问题表

Final Verification Wave

  • F1. 全量测试: pytest tests -q → 全部通过
  • F2. 解除占用: 清理临时文件
  • F3. 更新所有 MD 文件到最终状态

Approval Gate

状态: 等待批准 待执行: 24个todo,预计500-800行变更 关键变更: 10个文件(views.py/tool_registry.py/type_classifier.py/entity_aggregator.py/ entity_detector.py/globe.html/manual.html/config.yaml/loader.py/models.py)

同意后开始执行?