PDF多表格结构识别与跨表语义对齐:基于对抗迁移的鲁棒相似度度量模型
文章目录
- 一. 项目结构
- 二.流程分析
- 2.1 批处理器核心代码解析
- 三. 跨页表格相似度匹配原理
- 3.1 表头内容相似度-特征向量归一化
- 3.2 表头内容相似度-余弦相似度
- 3.3 定时缓存清理
ocr扫描有其局限性。对于pdf文本类型这种pdfbox,aspose-pdf,spire直接提取文本的精准性更高。经过综合对比我们觉得aspose和spire在读取pdf文本方面较为优秀。基于此我们可能需要提取pdf中所有表格数据,完成数据录入。但是表格数据不同,还存在跨页表格问题。但是按照以下方案即可解决。本文的表格处理思想来源于mybatis的底层设计。
| 特征 | 余弦相似度 | 编辑距离 |
|---|---|---|
| 原理 | 衡量向量方向的夹角(语义相似性) | 计算字符串转换所需的最小操作次数(字符级差异) |
| 输入类型 | 向量(如文本的TF-IDF或词嵌入向量) | 字符串或序列 |
| 关注点 | 语义层面的相似性(如主题、用词) | 结构层面的差异(如拼写错误、字符顺序) |
| 输出范围 | [-1, 1](通常取绝对值或归一化为0-1) | 非负整数(0表示完全匹配) |
| 计算复杂度 | O(n)(向量化后快速计算) | O(n*m)(对长文本较慢) |
| 典型应用 | 文档相似度、推荐系统、语义搜索 | 拼写纠错、DNA序列比对、短文本模糊匹配 |
开源地址
一. 项目结构
本设计基于aspose-pdf实现
|-- SpringContextUtil.java
`-- pdf|-- AbstractTextMappingTemplate.java #抽象模板映射器 解析内容映射到结构化对象|-- PDFboxTable.java # 暂留扩展|-- PdfTableParsingEngine.java # 表格解析引擎 提供从PDF文档中提取并处理表格数据的功能|-- StringEscapeUtil.java # 字符串转义工具类 防止注入攻击|-- TableBatchProcessor.java # 具体表格执行处理器 表格批处理器|-- annotation # 映射注解包|-- aspect # 注解处理器包|-- converter # 抽象模板映射器具体实现 包`-- entity # 想要映射的结构化对象包
二.流程分析
- 表格解析器提取pdf表格文本
- 表格批处理器负责具体执行表格解析
- 字符串转义避免恶意攻击
- 抽象映射器允许用户具体实现映射实体
2.1 批处理器核心代码解析
表格解析器每检测一页的所有表格,就提交到批处理器进行具体数据清洗,归一化。以下是进行数据批处理的核心逻辑
/*** 添加表格到批处理队列** @param pageIndex 页码索引* @param tables 页面中的表格列表*/public void addPageTables(int pageIndex, List<AbsorbedTable> tables) {// 资源限制检查 一页10个表格if (tables.size() > MAX_TABLES_PER_PAGE) {log.warn("页面{}表格数量超过限制: {}", pageIndex, tables.size());// 截取前MAX_TABLES_PER_PAGE个表格tables = tables.subList(0, MAX_TABLES_PER_PAGE);}// 处理当前页的表格List<StringBuilder> processedTables = new ArrayList<>();for (AbsorbedTable table : tables) {// 处理单个表格StringBuilder tableContent = processSingleTable(table);if (tableContent == null) continue;// 数据清洗PdfTableParsingEngine.cleanData(tableContent);// 生成表格指纹String tableFingerprint = generateTableFingerprint(tableContent);// 将表格指纹和内容存储到跨页表格缓存中crossPageTableCache.putIfAbsent(tableFingerprint, new CacheEntry(new StringBuilder(tableContent)));// 更新缓存条目的最后访问时间crossPageTableCache.get(tableFingerprint).updateLastAccessTime();// 检查是否为跨页表格if (isCrossPageTable(tableFingerprint)) {// 合并跨页表格tableContent = mergeCrossPageTable(tableContent, tableFingerprint);} else {// 异常检测(连续重复表格)if (isDuplicateTable(tableFingerprint)) {log.warn("检测到连续重复表格类型: {}", tableFingerprint);continue;}}// 添加到处理队列processedTables.add(tableContent);}// 将处理后的表格添加到缓冲队列if (!processedTables.isEmpty()) {try {// 尝试添加到队列,如果队列已满则提交当前队列中的所有表格if (!tableBufferQueue.offer(processedTables, 100, TimeUnit.MILLISECONDS)) {log.info("缓冲队列已满,提交批处理任务");submitBatchTask();// 重新尝试添加tableBufferQueue.put(processedTables);}} catch (InterruptedException e) {log.error("添加表格到缓冲队列失败: {}", e.getMessage());Thread.currentThread().interrupt();}}}
如上述代码,
- processSingleTable(AbsorbedTable table)用于具体解析表格内容并拼接成特定字符串。
- cleanData(StringBuilder builder) 移除所有空白字符和换行符
- generateTableFingerprint(StringBuilder tableContent) 用于识别跨页表格相似度合并
- crossPageTableCache 缓存跨页表格,因为是以页为单位检测表格的。下一页需要保留上一页表格
- mergeCrossPageTable(tableContent, tableFingerprint) 设定相似度大于85%且不为100%。为同一表格。进行合并。
- submitBatchTask() 提交批处理任务
- processBatchTables(List<List> batchTables) 获取抽象映射器的具体实现。根据具体规则进行映射匹配
三. 跨页表格相似度匹配原理
- 1.根据特定表头内容相似度
- 2.根据表格样式特征
3.1 表头内容相似度-特征向量归一化
字符串长度建议不要超过特征矩阵维度长度
使用余弦相似矩阵,比较两个表头字符串相似度.一般认为表头字串很短,因此初始化16特征向量即可
表示我们可以把字符ascii映射到特征向量上,并通过单位向量归一化结果。获取第一块内容字串的标准化特征向量。同理对第二块内容字串做标准化计算。
/*** 计算内容相似度(基于矢量相似度)** @param str1 字符串1* @param str2 字符串2* @return 内容相似度*/private double calculateContentSimilarity(String str1, String str2) {if (str1 == null || str2 == null) {throw new IllegalArgumentException("输入字符串不能为空");}// 将字符串转换为特征向量double[] vector1 = stringToVector(str1);double[] vector2 = stringToVector(str2);// 计算余弦相似度return cosineSimilarity(vector1, vector2);}/*** 将字符串转换为特征向量** @param str 输入字符串* @return 特征向量*/private double[] stringToVector(String str) {// 初始化特征向量double[] vector = new double[VECTOR_DIMENSION];// 创建字符频率映射Map<Character, Integer> charFrequency = new HashMap<>();// 统计字符频率for (char c : str.toCharArray()) {charFrequency.put(c, charFrequency.getOrDefault(c, 0) + 1);}// 将字符频率映射到特征向量for (char c : charFrequency.keySet()) {int index = Math.abs(c) % VECTOR_DIMENSION;vector[index] += charFrequency.get(c);}// 归一化向量normalizeVector(vector);return vector;}/*** 归一化向量** @param vector 输入向量*/private void normalizeVector(double[] vector) {double magnitude = 0.0;// 计算向量模长for (double value : vector) {magnitude += value * value;}magnitude = Math.sqrt(magnitude);// 归一化向量if (magnitude > 0) {for (int i = 0; i < vector.length; i++) {vector[i] /= magnitude;}}}
3.2 表头内容相似度-余弦相似度
- 我们将原始特征向量进行标准化(归一化)处理,使其转化为单位向量(模长为1),从而消除向量尺度差异对相似性度量的影响。(注:此步骤确保所有向量处于同一量纲空间,使得后续计算具有可比性)
- 对于两个单位向量 u u u 和 v v v,其点积在数值上等于它们的余弦相似度(即 c o s θ cosθ cosθ)。
几何意义:余弦相似度反映向量方向的接近程度,与向量维度无关。
数学表达:
c o s θ = u ⋅ v ∣ u ∣ ⋅ ∣ v ∣ cosθ=\frac{u·v}{|u|·|v|} cosθ=∣u∣⋅∣v∣u⋅v
结果解释:
cos θ ≈ 1 c o s θ ≈ 1 \cos\theta \approx 1cosθ≈1 cosθ≈1cosθ≈1:向量方向高度一致,对应字符串内容几乎相同。
cos θ ≈ 0 c o s θ ≈ 0 \cos\theta \approx 0cosθ≈0 cosθ≈0cosθ≈0:向量正交,字符串内容无相关性。
应用示例:在文本匹配任务中,可通过该值量化两段文本的语义相似性。
点积与哈达玛积的区别:
点积输出标量,用于衡量整体相似性;
哈达玛积为元素级乘法,输出同维向量,常用于局部特征交互。
private double cosineSimilarity(double[] vector1, double[] vector2) {if (vector1.length != vector2.length) {throw new IllegalArgumentException("向量维度不匹配");}double dotProduct = 0.0;double magnitude1 = 0.0;double magnitude2 = 0.0;for (int i = 0; i < vector1.length; i++) {dotProduct += vector1[i] * vector2[i];magnitude1 += vector1[i] * vector1[i];magnitude2 += vector2[i] * vector2[i];}magnitude1 = Math.sqrt(magnitude1);magnitude2 = Math.sqrt(magnitude2);if (magnitude1 == 0.0 || magnitude2 == 0.0) {return 0.0;} else {return dotProduct / (magnitude1 * magnitude2);}}
3.3 定时缓存清理
由于我们为了保证跨页表格的关联关系。我们使用map集合保存上一页表格内容。
/*** 构造函数*/public TableBatchProcessor() {// 使用虚拟线程池处理批量映射任务this.executorService = Executors.newVirtualThreadPerTaskExecutor();// 初始化表格缓冲队列this.tableBufferQueue = new LinkedBlockingQueue<>(BUFFER_CAPACITY);// 初始化表格类型计数器this.tableTypeCounter = new ConcurrentHashMap<>();// 初始化跨页表格缓存this.crossPageTableCache = new ConcurrentHashMap<>();// 初始化缓存清理调度器this.cacheCleanupScheduler = Executors.newScheduledThreadPool(1);// 启动定时清理任务this.cacheCleanupScheduler.scheduleAtFixedRate(this::cleanupCrossPageTableCache, 1, 1, TimeUnit.MINUTES);}
我设计了最早时间淘汰机制,同时为了进一步防止内存溢出。设计了map最大值。超出阈值清理所有。但显然这是有问题的,可能导致跨表关联关系断开。因此先以抛出异常解决
/*** 清理跨页表格缓存(增强版)*/private void cleanupCrossPageTableCache() {long currentTime = System.currentTimeMillis();List<String> expiredKeys = new ArrayList<>();for (Map.Entry<String, CacheEntry> entry : crossPageTableCache.entrySet()) {if (currentTime - entry.getValue().lastAccessTime > CACHE_ENTRY_TTL) {expiredKeys.add(entry.getKey());}}// 限制缓存条目数量if (crossPageTableCache.size() > MAX_CACHE_ENTRIES) {crossPageTableCache.clear();throw new IllegalStateException("缓存条目数量超过限制");}for (String key : expiredKeys) {crossPageTableCache.remove(key);log.info("清理过期缓存条目: {}", key);}}相关文章:
PDF多表格结构识别与跨表语义对齐:基于对抗迁移的鲁棒相似度度量模型
文章目录 一. 项目结构二.流程分析2.1 批处理器核心代码解析 三. 跨页表格相似度匹配原理3.1 表头内容相似度-特征向量归一化3.2 表头内容相似度-余弦相似度3.3 定时缓存清理 ocr扫描有其局限性。对于pdf文本类型这种pdfbox,aspose-pdf,spire直接提取文本…...
docker启动nacos+redis+seata
docker启动nacos 最新版本的nacos需要再启动的时候设置mysql的一些属性,【也可以先启动nacos,再到配置文件中找到application.yml设置mysql的一些属性】。 1.如果直接启动nacos设置的mysql我们需要确定两个容器的ip都是一样的。 查看mysql容器中的ip命令…...
从 select 到 epoll:拆解 I/O 多路复用的演进与实战
目录 一、引言:为什么需要 I/O 多路复用? 二、select 1.函数介绍 2.原理 3.样例代码 4.优缺点总结 三、poll 1.函数介绍 2.样例代码 3.优缺点总结 四、epoll 1.函数介绍 2.原理 3.LT和ET两种工作模式 4.优缺点总结 五、核心机制对比&…...
Go后端架构探索:从 MVC 到 DDD 的演进之路
Go语言 MVC 与 DDD 分层架构详细对比 MVC和DDD是后台开发两种流行的分层架构思想,MVC(Model-View-Controller)是一种设计模式,主要用于分离用户界面、业务逻辑和数据模型,便于分层解耦,而DDD(领…...
【力扣hot100题】(017)矩阵置零
还是挺简单的,使用哈希表记录需要置换的行列即可,这样就可以避免重复节省时间。 class Solution { public:void setZeroes(vector<vector<int>>& matrix) {unordered_set<int> row;unordered_set<int> line;for(int i0;i&l…...
One Commander 3,文件管理新体验
One Commander 3 是一款集多功能于一体 Windows 10/11的文件管理工具,其设计目的在于为用户带来多元化的操作体验。这款工具通过支持多栏界面布局,让用户能够迅速且高效地组织和管理文件。此外,它还提供了多主题选项和多种图标集,…...
Ubuntu 下 nginx-1.24.0 源码分析
main 函数在 src\core\nginx.c int ngx_cdecl main(int argc, char *const *argv) {ngx_buf_t *b;ngx_log_t *log;ngx_uint_t i;ngx_cycle_t *cycle, init_cycle;ngx_conf_dump_t *cd;ngx_core_conf_t *ccf;ngx_debug_init();if (ngx_strerror_in…...
c# ftp上传下载 帮助类
工作中FTP的上传和下载还是很常用的。如下载打标数据,上传打标结果等。 这个类常用方法都有了:上传,下载,判断文件夹是否存在,创建文件夹,获取当前目录下文件列表(不包括文件夹) ,获取当前目录下文件列表(不包括文件夹) ,获取FTP文件列表(包括文件夹), 获取当前目…...
Java进阶——静态代理与动态代理
代理模式是一种常用的设计模式,为其他对象提供一种代理以控制对这个对象的访问。代理模式就像是一个中间人,客户端通过代理来间接访问目标对象,可以在不修改目标对象的基础上,对目标对象的功能进行增强或扩展。代理模式主要分为静…...
VS Code 中 .history`文件的来源与 .gitignore`的正确使用
引言 在使用 VS Code 进行 Git 版本控制时,有时会发现项目中多出一个 .history 目录,并被 Git 识别为未跟踪文件。本文将解释 .history 的来源,并提供 .gitignore 的正确配置方法,确保开发环境的整洁性。 1. .history 文件的来源…...
非手性分子发光有妙招:借液晶之力,实现高不对称圆偏振发光
*本文只做阅读笔记分享* 一、圆偏振发光研究背景与挑战 圆偏振发光(CPL)材料在3D显示、光电器件等领域大有用处,衡量它的一个重要指标是不对称发光因子(glum)。早期CPL材料的glum值低,限制了实际应用。为…...
解释器模式_行为型_GOF23
解释器模式 解释器模式(Interpreter Pattern)是一种行为型设计模式,核心思想是定义语言的文法规则,并构建一个解释器来解析和执行该语言中的表达式。它类似于“翻译器”——将符合特定语法规则的文本(如数学公式、脚本…...
OTN(Optical Transport Network)详解
OTN(光传送网)是一种基于**波分复用(WDM)**的大容量光传输技术,结合了SDH的运维管理优势和WDM的高带宽特性,广泛应用于骨干网、城域核心层及数据中心互联(DCI)。 1. OTN 的基本概念 …...
YOLOv8+ Deepsort+Pyqt5车速检测系统
该系统通过YOLOv8进行高效的目标检测与分割,结合DeepSORT算法完成目标的实时跟踪,并利用GPU加速技术提升处理速度。系统支持模块化设计,可导入其他权重文件以适应不同场景需求,同时提供自定义配置选项,如显示标签和保存…...
【干货】前端实现文件保存总结
⚠️⚠️文前推荐一下👉 前端必备工具推荐网站(图床、API和ChatAI、智能AI简历、AI思维导图神器等实用工具): 站点入口:http://luckycola.com.cn/ 前端实现文件保存实现总结 在Web开发中,文件下载是常见的交互需求。本文将系统总结前端实现文…...
并发编程之FutureTask.get()阻塞陷阱:深度解析线程池CPU飚高问题排查与解决方案
FutureTask.get方法阻塞陷阱:深度解析线程池CPU飚高问题排查与解决方法 FutureTask.get()方法阻塞陷阱:深度解析线程池CPU飚高问题排查与解决方法1、情景复现1.1 线程池工作原理1.2 业务场景模拟1.3 运行结果1.4 发现问题:线程池没有被关闭1.…...
DGNN-YOLO:面向遮挡小目标的动态图神经网络检测与追踪方法解析
一、算法结构与核心贡献 1.1 文章结构 采用经典五段式结构: 引言:分析智能交通系统(ITS)中小目标检测与追踪的挑战,提出研究动机。相关工作:综述小目标检测(YOLO系列、Faster R-CNN)、目标追踪(SORT、Transformer)和图神经网络(GNN)的进展。方法论:提出DG…...
在Ubuntu中固定USB设备的串口号
获取设备信息 lsusb # 记录设备的Vendor ID和Product ID(例如:ID 0403:6001)# 获取详细属性(替换X和Y为实际设备号) udevadm info -a /dev/ttyUSBX 结果一般如下 创建udev规则文件 sudo gedit /etc/udev/rules.d/us…...
javaSE————文件IO(2)、
文件内容的读写——数据流 我们对于文件操作使用流对象Stream来操作,什么是流对象呢,水流是什么样的,想象一下,水流的流量是多种的,可以流100ml,也可以流1ml,流对象就和水流很像,我…...
前端常问的宏观“大”问题详解(二)
JS与TS选型 一、为什么选择 TypeScript 而不是 JavaScript? 1. 静态类型系统:核心优势 TypeScript 的静态类型检查能在 编译阶段 捕获类型错误(如变量类型不匹配、未定义属性等),显著减少运行时错误风险。例如&…...
[创业之路-343]:创业:一场认知重构与组织进化的双向奔赴
目录 前言:关键词: 一、重构企业认知框架: 1、认知框架的顶层设计——六大维度生态模型 2、认知重构的精密设计——五层结构化模型 第一层:战略层(脑) 第二层:运营层(躯干&…...
智慧电力:点亮未来能源世界的钥匙
在科技日新月异的今天,电力行业正经历着前所未有的变革。智慧电力,作为这一变革的核心驱动力,正逐步改变着我们对电力的认知和使用方式。它不仅是电力行业的一次技术革新,更是推动社会可持续发展、实现能源高效利用的重要途径。 智…...
架构师面试(二十三):负载均衡
问题 今天我们聊微服务相关的话题。 大中型微服务系统中,【负载均衡】是一个非常核心的组件;在微服务系统的不同位置对【负载均衡】进行了实现,下面说法正确的有哪几项? A. LVS 的负载均衡一般通过前置 F5 或是通过 VIP keepa…...
CSS3学习教程,从入门到精通, CSS3 列表控制详解语法知识点及案例代码(24)
CSS3 列表控制详解 CSS 列表控制的语法知识点及案例代码的详细说明,包括 list-style-type、list-style-image、list-style-position 和 list-style 的用法。 1. list-style-type 属性 list-style-type 属性用于设置列表项标记的类型。 语法 list-style-type: v…...
NSSCTF(MISC)—[justCTF 2020]pdf
相应的做题地址:https://www.nssctf.cn/problem/920 binwalk分离 解压文件2AE59A.zip mutool 得到一张图片 B5F31内容 B5FFD内容 转换成图片 justCTF{BytesAreNotRealWakeUpSheeple}...
坚持“大客户战略”,昂瑞微深耕全球射频市场
北京昂瑞微电子技术股份有限公司(简称“昂瑞微”)是一家聚焦射频与模拟芯片设计的高新技术企业。随着5G时代的全面到来,智能手机、智能汽车等终端设备对射频前端器件在通信频率、多频段支持、信道带宽及载波聚合等方面提出了更高需求…...
LiteDB 数据库优缺点分析与C#代码示例
LiteDB 是一个轻量级的 .NET NoSQL 嵌入式数据库,完全用 C# 开发,支持跨平台(Windows、Linux、MacOS),并提供类似于 MongoDB 的简单 API。它以单文件形式存储数据,类似于 SQLite,支持事务和 ACID 特性,确保数据的一致性和可靠性。 优缺点分析 优点: 轻量级与嵌入式:…...
上海SMT贴片技术解析与行业趋势
内容概要 随着长三角地区电子制造产业集群的快速发展,上海作为核心城市正引领着SMT贴片技术的革新浪潮。本文聚焦表面组装技术在高密度互连、微间距贴装等领域的突破性进展,通过解析焊膏印刷精度控制、元件定位算法优化等核心工艺,展现上海企…...
HTML5和CSS3的一些特性
HTML5 和 CSS3 是现代网页设计的基础技术,它们引入了许多新特性和功能,极大地丰富了网页的表现力和交互能力。 HTML5 的一些重要特性包括: 新的语义化标签: HTML5 引入了一些重要的语义化标签如 <header>, <footer>, <articl…...
Linux系统中快速安装docker
1 查看是否安装docker 要检查Ubuntu是否安装了Docker,可以使用以下几种方法: 方法1:使用 docker --version 命令 docker --version如果Docker已安装,输出会显示Docker的版本信息,例如: Docker version …...
