Files
invoice-master-poc-v2/docs/FIELD_EXTRACTOR_ANALYSIS.md
2026-01-25 15:21:11 +01:00

3.2 KiB
Raw Blame History

Field Extractor 分析报告

概述

field_extractor.py (1183行) 最初被识别为可优化文件,尝试使用 src/normalize 模块进行重构,但经过分析和测试后发现 不应该重构

重构尝试

初始计划

将 field_extractor.py 中的重复 normalize 方法删除,统一使用 src/normalize/normalize_field() 接口。

实施步骤

  1. 备份原文件 (field_extractor_old.py)
  2. 修改 _normalize_and_validate 使用统一 normalizer
  3. 删除重复的 normalize 方法 (~400行)
  4. 运行测试 - 28个失败
  5. 添加 wrapper 方法委托给 normalizer
  6. 再次测试 - 12个失败
  7. 还原原文件
  8. 测试通过 - 全部45个测试通过

关键发现

两个模块的不同用途

模块 用途 输入 输出 示例
src/normalize/ 变体生成 用于匹配 已提取的字段值 多个匹配变体列表 "INV-12345"["INV-12345", "12345"]
field_extractor 值提取 从OCR文本 包含字段的原始OCR文本 提取的单个字段值 "Fakturanummer: A3861""A3861"

为什么不能统一?

  1. src/normalize/ 的设计目的:

    • 接收已经提取的字段值
    • 生成多个标准化变体用于fuzzy matching
    • 例如 BankgiroNormalizer:
      normalize("782-1713")  ["7821713", "782-1713"]  # 生成变体
      
  2. field_extractor 的 normalize 方法:

    • 接收包含字段的原始OCR文本可能包含标签、其他文本等
    • 提取特定模式的字段值
    • 例如 _normalize_bankgiro:
      _normalize_bankgiro("Bankgiro: 782-1713")  ("782-1713", True, None)  # 从文本提取
      
  3. 关键区别:

    • Normalizer: 变体生成器 (for matching)
    • Field Extractor: 模式提取器 (for parsing)

测试失败示例

使用 normalizer 替代 field extractor 方法后的失败:

# InvoiceNumber 测试
Input: "Fakturanummer: A3861"
期望: "A3861"
实际: "Fakturanummer: A3861"  # 没有提取,只是清理

# Bankgiro 测试
Input: "Bankgiro: 782-1713"
期望: "782-1713"
实际: "7821713"  # 返回了不带破折号的变体,而不是提取格式化值

结论

field_extractor.py 不应该使用 src/normalize 模块重构,因为:

  1. 职责不同: 提取 vs 变体生成
  2. 输入不同: 包含标签的原始OCR文本 vs 已提取的字段值
  3. 输出不同: 单个提取值 vs 多个匹配变体
  4. 现有代码运行良好: 所有45个测试通过
  5. 提取逻辑有价值: 包含复杂的模式匹配规则(例如区分 Bankgiro/Plusgiro 格式)

建议

  1. 保留 field_extractor.py 原样: 不进行重构
  2. 文档化两个模块的差异: 确保团队理解各自用途
  3. 关注其他优化目标: machine_code_parser.py (919行)

学习点

重构前应该:

  1. 理解模块的真实用途,而不只是看代码相似度
  2. 运行完整测试套件验证假设
  3. 评估是否真的存在重复,还是表面相似但用途不同

状态: 分析完成,决定不重构 测试: 45/45 通过 文件: 保持 1183行 原样