SuperAPI AI 工具集

content-hash-cache-pattern

编程与开发

查看项目

更新于 10-15 10:36

技能介绍

用途

内容哈希文件缓存模式用于缓存高成本的文件处理结果,例如 PDF 解析、文本提取、图像分析等。它使用文件内容的 SHA-256 哈希作为缓存键,而不是文件路径。这样做的核心好处是:文件被重命名或移动后缓存依然命中;文件内容一旦改变,缓存自动失效;并且不需要额外的索引文件。

主要能力

  1. 基于内容哈希的缓存键:对文件内容计算 SHA-256 哈希,分块读取(默认 64KB 一块)以处理大文件,避免一次性将整个文件载入内存。
  2. 冻结数据类作为缓存条目:使用 @dataclass(frozen=True, slots=True) 定义 CacheEntry,包含 file_hash、source_path 和缓存的 document 结果。
  3. 基于文件的缓存存储:每个缓存条目以 {hash}.json 命名存储,实现 O(1) 查找,无需索引文件。
  4. 服务层包装(单一职责):处理函数保持纯净,不感知缓存;缓存作为独立的服务层,负责缓存检查、提取和写入。
  5. 优雅降级:读取缓存时若遇到 JSON 解析错误、值错误或键错误,视为缓存未命中并返回 None,不会崩溃,下次运行会重新处理。
  6. 惰性目录创建:首次写入时通过 cache_dir.mkdir(parents=True, exist_ok=True) 创建缓存目录。

使用方式

核心流程为:计算文件内容哈希 → 读取缓存 → 命中则返回缓存结果 → 未命中则调用纯处理函数提取 → 写入缓存并返回结果。

关键代码结构包括:

  • compute_file_hash(path):分块计算文件内容的 SHA-256 哈希,文件不存在时抛出 FileNotFoundError。
  • CacheEntry:冻结数据类,保存哈希、源路径和提取结果。
  • write_cache(cache_dir, entry) 与 read_cache(cache_dir, file_hash):以 {hash}.json 形式读写缓存,读取失败时返回 None。
  • extract_with_cache(file_path, *, cache_enabled=True, cache_dir=Path(".cache")):服务层函数,根据 cache_enabled 决定是否走缓存,命中/未命中时记录带截断哈希的日志。

设计决策包括:使用 SHA-256 内容哈希实现路径无关与自动失效;采用 {hash}.json 命名实现 O(1) 查找;服务层包装保持提取函数纯净;手动 JSON 序列化以完全控制冻结数据类的序列化;损坏缓存返回 None 实现优雅降级;惰性创建目录。

适用场景

  • 文件处理流水线(PDF 解析、OCR、文本提取、图像分析)。
  • 需要 --cache/--no-cache 选项的 CLI 工具。
  • 批处理任务中相同文件在多次运行中重复出现。
  • 在不修改现有纯函数的前提下为其添加缓存。

限制与不适用场景

  • 必须始终保持最新的数据(如实时数据流)不适合使用。
  • 缓存条目可能极其庞大的情况(应考虑流式处理)。
  • 结果依赖于文件内容之外的参数时(例如不同的提取配置)不适用。

最佳实践

  • 哈希内容而非路径——路径会变,内容身份不变。
  • 对大文件分块哈希,避免将整个文件载入内存。
  • 保持处理函数纯净,不应感知缓存。
  • 记录缓存命中/未命中日志,使用截断哈希便于调试。
  • 优雅处理损坏缓存,将无效条目视为未命中,绝不崩溃。

应避免的反模式

  • 基于路径的缓存(文件移动/重命名后失效)。
  • 在处理函数内部添加缓存逻辑(违反单一职责)。
  • 对嵌套冻结数据类使用 dataclasses.asdict()(复杂嵌套类型可能出问题),应改用手动序列化。