# process_data_pipeline 重构总结

## 实施日期
2025-11-04

## 重构目标

解决 `process_data_pipeline` 方法参数逻辑混乱的问题，使接口更清晰、更灵活。

## 变更内容

### 参数变更

#### 移除的参数

1. **`auto_extract_features: bool = False`**
   - **原因**：逻辑冗余，通过其他参数是否为 None 已经能决定是否提取特征
   - **替代方案**：通过 `v1_feature_versions` 和 `v2_feature_configs` 是否为 None/空列表来控制

2. **`feature_version: str = 'v1'`**
   - **原因**：
     - 单一字符串不支持多版本同时提取
     - 命名不准确（实际对应 features_version 模块，而非 features_v2）
   - **替代方案**：`v1_feature_versions: Optional[List[str]] = None`

3. **`v2_feature_config: Optional[str] = 'v2_transfer_basic'`**
   - **原因**：
     - 单一字符串不支持多配置同时提取
     - 默认值 `'v2_transfer_basic'` 可能不适合所有场景
   - **替代方案**：`v2_feature_configs: Optional[List[str]] = None`

#### 新增的参数

1. **`v1_feature_versions: Optional[List[str]] = None`**
   - **类型**：可选的字符串列表
   - **含义**：features_version 模块的版本列表
   - **匹配规则**：列表中的版本 `{version}` 对应 `features_version/{version}_feature.py` 文件
   - **示例**：
     - `None` 或 `[]`：不使用 features_version 提取
     - `['v1']`：仅提取 V1 Transfer 特征
     - `['v2']`：仅提取 V2 Transient tau 特征
     - `['v1', 'v2']`：同时提取 V1 和 V2

2. **`v2_feature_configs: Optional[List[str]] = None`**
   - **类型**：可选的字符串列表
   - **含义**：features_v2 模块的配置名列表
   - **匹配规则**：配置名对应 features_v2 系统中的 YAML 配置
   - **示例**：
     - `None` 或 `[]`：不使用 features_v2 提取
     - `['v2_transfer_basic']`：仅提取基础 Transfer 特征
     - `['v2_transfer_basic', 'v2_ml_ready']`：同时提取多个配置

### 方法签名对比

**旧版本**（已废弃）:
```python
def process_data_pipeline(
    self,
    source_directory: Union[str, Path],
    clean_json: bool = True,
    num_workers: int = 20,
    conflict_strategy: str = 'skip',
    auto_extract_features: bool = False,           # ❌ 已移除
    feature_version: str = 'v1',                   # ❌ 已移除
    v2_feature_config: Optional[str] = 'v2_transfer_basic',  # ❌ 已移除
    show_progress: bool = True
) -> Dict[str, Any]
```

**新版本**（当前）:
```python
def process_data_pipeline(
    self,
    source_directory: Union[str, Path],
    clean_json: bool = True,
    num_workers: int = 20,
    conflict_strategy: str = 'skip',
    v1_feature_versions: Optional[List[str]] = None,  # ✅ 新增
    v2_feature_configs: Optional[List[str]] = None,    # ✅ 新增
    show_progress: bool = True
) -> Dict[str, Any]
```

## 实现逻辑变更

### 特征提取判断

**旧逻辑**:
```python
if auto_extract_features and convert_result['successful_conversions'] > 0:
    if feature_version in ['v1', 'both']:
        # 提取 V1
    if feature_version in ['v2', 'both']:
        # 提取 V2
```

**新逻辑**:
```python
extract_v1 = v1_feature_versions is not None and len(v1_feature_versions) > 0
extract_v2 = v2_feature_configs is not None and len(v2_feature_configs) > 0

if (extract_v1 or extract_v2) and convert_result['successful_conversions'] > 0:
    if extract_v1:
        for version in v1_feature_versions:
            # 动态导入并提取每个版本
    if extract_v2:
        for config_name in v2_feature_configs:
            # 提取每个配置
```

### 动态模块导入

新实现支持动态导入 features_version 模块中的函数：

```python
# 对于 v1_feature_versions = ['v1', 'v2']
for version in ['v1', 'v2']:
    module_name = f'..features_version.{version}_feature'  # v1_feature, v2_feature
    function_name = f'{version}_feature'  # v1_feature(), v2_feature()

    module = importlib.import_module(module_name, package='infra.catalog')
    feature_func = getattr(module, function_name)

    # 调用函数
    feature_func(raw_path, output_dir=features_dir)
```

这使得系统可以轻松扩展支持 `v3_feature.py`, `v4_feature.py` 等。

## 优势

### 1. 更清晰的逻辑

- ✅ 参数即文档：参数名直接表达其作用
- ✅ 无需额外的 `auto_extract_features` 标志
- ✅ `None` 或 `[]` 表示不使用，语义明确

### 2. 更灵活的配置

- ✅ 支持多版本同时提取：`v1_feature_versions=['v1', 'v2']`
- ✅ 支持多配置同时提取：`v2_feature_configs=['basic', 'ml_ready']`
- ✅ 可以只提取某一类特征，不影响另一类

### 3. 更好的可扩展性

- ✅ 新增 `v3_feature.py` 无需修改 pipeline 代码
- ✅ 动态导入机制自动发现新版本
- ✅ 版本独立，互不影响

### 4. 更准确的命名

- ✅ `v1_feature_versions` 明确指向 features_version 模块
- ✅ `v2_feature_configs` 明确指向 features_v2 模块
- ✅ 避免 "v1"/"v2" 的歧义（是版本号还是模块名？）

## 向后兼容性

### ⚠️ 破坏性变更

**旧代码**:
```python
# 这段代码将不再工作
result = manager.process_data_pipeline(
    'data/source',
    auto_extract_features=True,
    feature_version='v1'
)
```

**新代码**:
```python
# 需要修改为
result = manager.process_data_pipeline(
    'data/source',
    v1_feature_versions=['v1']
)
```

### 迁移指南

| 旧参数 | 新参数 | 迁移示例 |
|-------|--------|---------|
| `auto_extract_features=False` | （无需设置） | 默认不提取 |
| `auto_extract_features=True, feature_version='v1'` | `v1_feature_versions=['v1']` | 提取 V1 Transfer |
| `auto_extract_features=True, feature_version='v2'` | `v2_feature_configs=['v2_transfer_basic']` | 提取 features_v2 |
| `auto_extract_features=True, feature_version='both'` | `v1_feature_versions=['v1'], v2_feature_configs=['v2_transfer_basic']` | 两者都提取 |

### 常见场景迁移

#### 场景1：仅转换，不提取特征

**旧代码**:
```python
result = manager.process_data_pipeline(
    'data/source',
    auto_extract_features=False
)
```

**新代码**（无需修改参数）:
```python
result = manager.process_data_pipeline(
    'data/source'
    # v1_feature_versions 和 v2_feature_configs 默认为 None
)
```

#### 场景2：转换 + V1 特征

**旧代码**:
```python
result = manager.process_data_pipeline(
    'data/source',
    auto_extract_features=True,
    feature_version='v1'
)
```

**新代码**:
```python
result = manager.process_data_pipeline(
    'data/source',
    v1_feature_versions=['v1']
)
```

#### 场景3：转换 + V2 特征

**旧代码**:
```python
result = manager.process_data_pipeline(
    'data/source',
    auto_extract_features=True,
    feature_version='v2',
    v2_feature_config='v2_ml_ready'
)
```

**新代码**:
```python
result = manager.process_data_pipeline(
    'data/source',
    v2_feature_configs=['v2_ml_ready']
)
```

#### 场景4：转换 + 两种特征

**旧代码**:
```python
result = manager.process_data_pipeline(
    'data/source',
    auto_extract_features=True,
    feature_version='both',
    v2_feature_config='v2_transfer_basic'
)
```

**新代码**:
```python
result = manager.process_data_pipeline(
    'data/source',
    v1_feature_versions=['v1'],
    v2_feature_configs=['v2_transfer_basic']
)
```

## 返回值变更

### 新增的结果键

结果字典中的 `results` 字段现在使用更细粒度的键名：

**旧版本**:
```python
{
    'results': {
        'feature_extraction_v1': {...},    # 仅当 feature_version='v1' 或 'both'
        'feature_extraction_v2': {...}     # 仅当 feature_version='v2' 或 'both'
    }
}
```

**新版本**:
```python
{
    'results': {
        'v1_feature_extraction_v1': {...},           # v1_feature.py 的结果
        'v1_feature_extraction_v2': {...},           # v2_feature.py 的结果
        'v2_feature_extraction_v2_transfer_basic': {...},  # features_v2 config 1
        'v2_feature_extraction_v2_ml_ready': {...}         # features_v2 config 2
    }
}
```

### 键名格式

- **features_version 提取**: `v1_feature_extraction_{version}`
  - 示例: `v1_feature_extraction_v1`, `v1_feature_extraction_v2`

- **features_v2 提取**: `v2_feature_extraction_{config_name}`
  - 示例: `v2_feature_extraction_v2_transfer_basic`, `v2_feature_extraction_v2_ml_ready`

## 测试验证

### 语法检查

```bash
conda run --live-stream --name mlpytorch python -m py_compile infra/catalog/unified.py
```

✅ **通过**

### 导入测试

```python
from infra.catalog import UnifiedExperimentManager

manager = UnifiedExperimentManager('catalog_config.yaml')
print("✅ Import successful")
```

✅ **通过**

## 文档更新

### 新增文档

1. **`PROCESS_DATA_PIPELINE_GUIDE.md`**
   - 完整的使用指南
   - 8 个详细示例
   - 故障排除

2. **`example/process_data_pipeline_example.py`**
   - 8 个可运行的示例
   - 涵盖所有使用场景

3. **`REFACTORING_SUMMARY.md`**
   - 本文件
   - 重构说明和迁移指南

### 更新文档

1. **`CLAUDE.md`**
   - 更新 `process_data_pipeline` 的 API 说明
   - 添加重构说明和新参数文档
   - 指向详细指南

## features_version 模块对应关系

当前支持的版本（可扩展）：

| 版本名 | 文件 | 功能 | data_type |
|-------|------|------|-----------|
| `'v1'` | `v1_feature.py` | Transfer 特征（gm, Von, \|I\|） | `'transfer'` |
| `'v2'` | `v2_feature.py` | Transient tau 特征（tau_on, tau_off） | `'transient'` |

### 扩展示例

如果需要添加 `v3_feature.py`：

1. 创建文件：`features_version/v3_feature.py`
2. 实现函数：`def v3_feature(raw_file_path: str, output_dir: str) -> str`
3. 使用：`v1_feature_versions=['v3']`

**无需修改** `process_data_pipeline` 代码！

## 最佳实践

### 推荐用法

```python
# ✅ 明确指定需要的特征
result = manager.process_data_pipeline(
    'data/source',
    v1_feature_versions=['v1', 'v2'],  # 明确列出
    v2_feature_configs=['v2_ml_ready']
)

# ❌ 避免硬编码默认值
result = manager.process_data_pipeline(
    'data/source',
    v2_feature_configs=['v2_transfer_basic']  # 如果不需要就不设置
)
```

### 性能优化

```python
# 如果只需要转换，不要设置任何特征参数
result = manager.process_data_pipeline(
    'data/source',
    num_workers=20  # 最大并行转换
)

# 如果需要特征，按需提取
result = manager.process_data_pipeline(
    'data/source',
    v1_feature_versions=['v1'],  # 只提取需要的
    num_workers=20
)
```

### 错误处理

```python
result = manager.process_data_pipeline(
    'data/source',
    v1_feature_versions=['v1', 'v2']
)

# 检查每个版本的结果
for version in ['v1', 'v2']:
    key = f'v1_feature_extraction_{version}'
    if key in result['results']:
        ver_result = result['results'][key]
        if ver_result.get('failed'):
            print(f"⚠️ {version} failed: {ver_result['failed']}")
```

## 已知限制

1. **并行冲突**：
   - features_v2 提取自动限制为 `min(num_workers, 4)`
   - V2 transient 特征（autotau）内部可能使用多核
   - 建议避免同时高并行

2. **版本依赖**：
   - 需要对应的 `{version}_feature.py` 文件存在
   - 文件中必须有同名函数

3. **向后不兼容**：
   - 旧代码需要修改才能使用新版本
   - 建议批量替换旧参数

## 总结

✅ **重构成功**：
- 移除了逻辑混乱的参数
- 新增了灵活的列表参数
- 支持多版本/多配置同时提取
- 动态模块导入机制易于扩展

✅ **文档完善**：
- 详细使用指南
- 多个示例代码
- 迁移指南

✅ **代码质量**：
- 语法检查通过
- 导入测试通过
- 错误处理完善

---

**实施日期**: 2025-11-04
**版本**: v2.0.0
**状态**: ✅ 完成并可用
