---
title: "为 PDF 逐页建立可追溯的检索引用"
canonical: "https://siyuanailab.com/curation/translations/f9ce1bc263a5db616adc13ee1d1bf8c7-ea57595b2c67e222e9655e3b56f1470ab8a8be52d625a2025e20539d5924ab79/"
dateModified: "2026-10-02"
datePublished: "2026-10-02"
---

[返回日报条目](https://siyuanailab.com/curation/#entry/f9ce1bc263a5db616adc13ee1d1bf8c7)

 

资料节译

 

# 为 PDF 逐页建立可追溯的检索引用

 

[阅读原文](https://dev.to/darianreed1254/index-pdf-text-per-page-durable-retrieval-citations-for-support-bundles-3i1l)

 

现有资料无法确认原文完整，本页只翻译已取得的材料。

 

现有原件无法确认图片是否齐全。

 

可将客户支持文档包合并以供审阅，再拆分以便升级处理，因此当前 PDF 中显示的页码并非持久的引用位置。**按源页面为文本编制索引，在每次文档包操作中保留该身份，并仅在呈现边界处将其转换为渲染后的页面。**这样，即使模板更换所有者，检索证据仍然清晰可解释。

 

简而言之：为 PDF 的每一页提取一条有序文本记录，附加不可变的文档 ID 和源页码，将每次合并或拆分记录为映射，而不是覆盖这些坐标，并在每个结果中同时返回稳定的源坐标和当前显示坐标。Node.js 服务可以调用这个索引边界；契约比运行时更重要。

 

这种类似事故的故障很容易在仪表板上被忽略。一名支持专员搜索了一个文档包，其中包含客户来信、故障排查记录和退货授权。结果显示第 14 页。之后，运营人员将退货文件拆分成单独的文档包，第 14 页现在成了别的内容。搜索状态仍为绿色，延迟仍然平稳，但引用已经失实。究竟是哪一页触发了结果：结果中标出的那一页，还是实际包含该句子的源页面？

 

PDF 是一种分页文档格式，但拼装文件中的序号位置并非业务标识符。合并两个文件后，第二个文件中的每一页都会移位。插入封面后，几乎所有可见页码都会移位。拆分文档包后，同一个源页面可能会变成新文件中的第 1 页。提取出的文本可能仍有用，但定位信息会悄然失效。

 

它会悄无声息地失效。

 

模板归属会让问题更严重。在客户支持中，一个团队可能负责信函模板，另一个团队负责退货或合规表单。如果文档打包流程只把最终 PDF 当作记录，模板团队一次无害的插入，就会改变其并不拥有的内容的检索坐标。**所有权应止于源文档边界；拼装过程负责管理映射，而非源身份。**

 

这条不变量很简单：`(source_document_id, source_page)`永不改变。生成的文件有自己的 ID，并带有一份将每个显示页面映射回该文档与页面组合的映射。搜索分块继承这个稳定组合。界面可以显示`Bundle page 14`，但审计记录仍必须注明引用文本来自哪个源文档和页面。

 

将提取、拼装和检索分开。提取过程输出有序的页面记录。拼装过程输出沿袭关系。检索过程存储带有页面级溯源信息的分块，并在缺少溯源信息时拒绝编造引用。

 

```
type PageRecord struct {
    SourceDocumentID string
    SourcePage       int // One-based, as shown to reviewers.
    Text             string
    TextSHA256       string
}
type DisplayPage struct {
    ArtifactID       string
    DisplayPage      int
    SourceDocumentID string
    SourcePage       int
}
type Citation struct {
    SourceDocumentID string
    SourcePage       int
    ArtifactID       string
    DisplayPage      int
    Quote            string
}
```

 

不要使用提取出的文本作为身份标识。规范化或模板修订可能会改变文本，而重复的固定文本可能会出现在多个页面上。摘要值可以检测提取结果是否发生变化，但文档 ID 和页序号才是定位信息。

 

对于 Node.js 接收端点，让边界接收 PDF 和调用方提供的文档身份，然后在分块之前生成页面记录。不要把文档展平成一个字符串，再事后重建分页符。提取器必须保留页面顺序，并将没有可提取文本的页面表示为显式记录；否则第 8 页可能会被丢弃，导致第 9 页被误标为第 8 页。

 

预防性检查应放在已拼装文件的注册环节。它应拒绝重复的显示页面、页码间断、非正序号，以及对提取台账中不存在页面的引用。

 

```
func ValidateAssembly(pages []DisplayPage, known map[string]map[int]bool) error {
    seen := make(map[int]bool, len(pages))
    for _, p := range pages {
        if p.DisplayPage < 1 || p.SourcePage < 1 {
            return fmt.Errorf("page ordinals must be positive")
        }
        if seen[p.DisplayPage] {
            return fmt.Errorf("duplicate display page %d", p.DisplayPage)
        }
        if !known[p.SourceDocumentID][p.SourcePage] {
            return fmt.Errorf("unknown source page %s:%d", p.SourceDocumentID, p.SourcePage)
        }
        seen[p.DisplayPage] = true
    }
    for n := 1; n <= len(pages); n++ {
        if !seen[n] {
            return fmt.Errorf("missing display page %d", n)
        }
    }
    return nil
}
```

 

很好。

 

凌晨 3 点，已索引分块数量只是薄弱的证据；有用的页面会指出某个文件引用了`return-form:3`，尽管提取过程只生成了两页。应针对被拒绝的沿袭关系、持续的提取失败，以及无法解析映射的引用发出警报。页面应指出失效的不变量和受影响的文件。

 

重试也需要稳定的键。同一源修订版被索引两次时，应替换或确认相同的页面记录，而不是创建并行身份。即使文件名未变，新的模板修订版也应获得新的源修订身份。否则，较晚的重试可能会把旧文本关联到新映射。

 

一次顺利路径的搜索测试几乎不能证明什么。围绕转换构建测试夹具：将三页的对话记录与两页的授权文件合并，插入一页封面，将第 2–4 页拆分到新文件中，并重新排列文档包。断言每个显示页面都恰好映射到一个已知源页面，并且引用结果能追溯到相同的提取页面文本。有些测试中，可见页码应该变化；源坐标必须保持不变。

 

也要使用格式异常的测试夹具：提取器无法打开的受保护文件、没有嵌入文本的扫描页面、重复的固定文本，以及漏掉一页的映射。预期行为应是明确失败或处于`extraction_required`状态，绝不能给出看似确定的空结果。OCR 是一种独立的提取模式，应记录这一区别，因为它提取出的文本可能不同于嵌入文本；引用仍然指向审阅者可以检查的页面图像。

 

部署应围绕数据契约进行版本管理。更改提取或分块方式时运行影子索引，比较页数和无法解析的映射，然后仅在新索引通过沿袭检查后切换读取。旧索引应保留足够长时间，以解析已发出的引用。这会增加存储和运维投入，但可避免提取升级变成无法追溯的证据改写。

 

如果文件不可变、永不拆分，并且引用只需在该确切文件有效期内存在，那么只为最终拼装的 PDF 编制索引是可以接受的。这是最简单的模型。但如果支持工作流以不同顺序重新发布相同文档，它就会失效。

 

将页面标签嵌入分块文本可能会改善检索上下文，但这并不能确立沿袭关系；标签可能重复、遗漏，或由模板生成。仅存储边界框可以在页面内实现精确高亮，但仍需要稳定的页面身份。保留源坐标和显示坐标会在读取时增加一次连接。这确实是一种权衡，但这次连接可以测试，而替代做法会掩盖历史。

 

如果检索单元是具有内容寻址标识符的不可变页面图像，并且不存在重新生成文档包的概念，那么这条建议不适用。在这种情况下，图像身份本身就提供了稳定坐标。对于可变的支持文档包，决策规则很明确：拥有模板的团队可以修订自己的页面，但任何修订都不得改写另一团队的证据身份。

 

选择提取组件时，应验证它能否为你的测试夹具语料库确定性地输出页面边界、能否显式报告失败而不是静默跳过页面，以及能否固定版本并进行回归测试。选择索引架构时，应考虑在合并、拆分或模板修订之前发出的引用，之后是否仍可解析。名称和功能列表是次要的。

 

有用的结果应包含引文、稳定的源文档和页面、当前文件和显示页面、提取修订版，以及足以防止用户解析其无权访问文档证据的授权上下文。记录标识符和结果，而非客户文本。除延迟外，还要衡量无法解析的沿袭关系和提取状态数量。

 

**持久可靠的设计是附带搜索功能的溯源台账，而不是在搜索索引上随意添加页码。**它让文档包变更清晰可见，限定模板所有权的边界，并在引用无法解析时为值班工程师提供一条具体的不变量。

 

参考资料：

 

- - ISO 32000-2，《便携式文档格式》：[https://www.iso.org/standard/75839.html](https://www.iso.org/standard/75839.html)

 

AI 翻译；具体表述请与原文对照。
