基于minerU的基于 RAG 溯源的高精度合并策略
问题:
入库阶段(极其简单,还原真实):
- 不跨行合并 。依然按 Line (物理行)入库。
- 只解决问题1(同行碎片) :将同一个 Line 下的多个 Span (如 10 和 m )拼接成一个完整的 Line 字符串入库。
- 结果 :数据库里的每一条记录,就是 PDF 上真实的一行。不加任何冗余字段,不乱合并不属于一起的行。 是解决了第一个问题;
第二个问题可不可这么做:把用户输入的,如果没有查询到数据字数大于10个或者12个的是,我先截取前10个或者12个去数据库查询,如果查询到,会返回数据所在的页码,然后在根据文件id,类型,页码去数据库中查询当前页内的数据,这个时候数据就少了很多,一页数据加载内存也没多少,然后在走内存配置+坐标反推,这样可以吗?
继续理解我需求,然后给出方案。
方案:
您提出的这个**“截取前缀做页码定位 + 单页内存拼接反推”的思路非常聪明,且工程落地性极强!**
它完美地结合了“数据库的快速定位”和“内存拼接的跨行匹配能力”,同时把内存消耗降到了最低(从加载整个文档变成了只加载一两页)。
我完全赞同这个方案,我们来详细梳理一下这个方案的完整执行流程和一些需要注意的边界情况,以便后续直接转化为代码。
最终敲定方案:“前缀定位 + 单页/多页内存动态反推”
一、 入库阶段(保持极致简单)
核心原则:不跨行合并,只合并同行 Span。
遍历
middle.json时,以Line为单位入库。将同一个
Line内的spans数组中的所有content直接字符串拼接。(解决痛点1:
10m被拆分的问题在此完美解决)数据库
doc_minerU_detail表中,一条记录就是 PDF 物理排版上的一行,包含该行的完整文本text和单行坐标bbox。不需要新增任何冗余字段。
二、 查询阶段(您提出的优化版 RAG 溯源逻辑)
当接收到前端传来的溯源长句(设为 searchText,例如:“焊接、切割设备应处于正常的工作状态,存在安全隐患时,应停止使用并由维修人员修理。”):
第一步:全句精准尝试(快速通道)
直接用完整的 searchText 去数据库 LIKE '%searchText%'。
命中:说明这句话恰好没有跨行,直接返回该行数据及坐标。流程结束。
未命中:说明这句话可能跨行了,进入第二步。
第二步:截取前缀,定位目标页码
由于全句跨行被切断了,但句子的开头部分一定存在于某一行中。
判断
searchText的长度。如果长度大于 12 个字符,截取前 12 个字符作为prefixText(例如:“焊接、切割设备应处于正”)。
(注:为什么是 10~12 个字?因为 PDF 一行通常有 30-40 个字,截取 12 个字大概率不会跨行,且具有足够的区分度,能唯一命中一行)。使用这个
prefixText去数据库LIKE '%prefixText%'查询。获取页码:从查询结果中提取出命中的页码
targetPageIdx。
(如果没查到,可以尝试缩短截取长度,比如取前 8 个字再试一次;或者尝试截取句子的中间部分,防止段首刚好有特殊不可见字符。)
第三步:提取局部数据,内存拼接(核心魔法)
我们现在知道了这句话大概在第 targetPageIdx 页。
防跨页边界处理(重要!):为了防止这句话刚好跨页(上一页末尾 + 下一页开头),我们不能只查
targetPageIdx这一页。我们应该查:targetPageIdx及其下一页(targetPageIdx + 1)。从数据库中查询这两页的所有
do
原创不易,完成人机校验,阅读全文