在数字化文档处理场景中,自动提取文档的章节结构是一项核心需求,尤其是面对无书签的pdf、纯文本文档等非结构化数据时,如何精准识别标题层级、构建树形章节结构成为关键。
本文将分享一套基于java实现的文档章节结构智能提取方案,涵盖大模型辅助识别、文本规则分析、unstructured json解析三种核心场景。
一、整体设计思路
本方案的核心类为detecttitlechapters,整体提取逻辑遵循“优先大模型识别,兜底规则分析”的策略,同时支持从unstructured输出的json数据中解析章节结构。核心流程如下:
- 大模型优先识别:利用llm对文本进行目录解析,输出标准化json格式的章节结构;
- 规则兜底分析:若大模型识别失败,通过文本规则匹配、层级判定提取标题;
- 层级结构整理:对识别出的标题进行排序,构建父子层级关系;
- unstructured json解析:针对结构化输出的json,基于element_id和parent_id构建树形章节。
二、核心功能实现
2.1 依赖与基础配置
核心依赖包括fastjson2(json解析)、apache commons lang3(字符串处理)、slf4j(日志)等。
2.2 大模型辅助章节提取
通过调用大模型api,传入定制化prompt,让llm解析文本并输出标准化的章节json结构,适合结构化程度低但文本规范的文档。
private list<chapter> getllmchapters(string input) {
list<chapter> alltitles = new arraylist<>();
if (input.length() > 100000) // 限制文本长度,避免大模型调用超限
return alltitles;
try {
// 获取大模型配置(模型编码、api地址、密钥)
kbllmmodelscacheservice.kbllmmodeldto model = kbllmmodelscacheservice.getchatmodel().getmodelmapbyid().get(2l);
// 定制化prompt,约束输出格式为json
string prompt = "角色:你是一名文档解析助手,请对用户的输入文本进行解析,找到目录所在,输出文本的章节目录结构。\n" +
"输出格式:json格式:[{\"title\":\"标题\", \"level\":2, \"pagenumber\":7, \"subchapters\":[]}\n" +
"约束条件:输出原文";
jsonobject cfgllm = new jsonobject();
cfgllm.put("model", model.getmodelcode());
cfgllm.put("prompt", prompt);
cfgllm.put("url", model.getapiurl());
cfgllm.put("authorization", model.getapikey());
// 调用大模型api
jsonobject result = httputils.chatmessages(input, cfgllm);
if (result.getboolean("success")) {
string content = result.getstring("content");
jsonarray jsonarray = httputils.formatlistjson(content);
alltitles = chapter.parsechapter(jsonarray); // 解析json为chapter对象
} else
log.info("大模型识别目录失败:" + result.tojsonstring());
} catch (exception e) {
e.printstacktrace();
}
return alltitles;
}
2.3 文本规则分析提取章节
当大模型识别失败时,通过文本规则匹配标题特征,判定层级并构建章节结构,核心分为“标题判定”“层级识别”“结构整理”三步。
2.3.1 标题判定规则
通过正则匹配、关键词过滤等方式,筛选出符合标题特征的文本行:
public static boolean istitletext(string text) {
// 过滤空文本、制表符、特殊标点
if (text.trim().isempty() || text.matches("\t") || text.contains("\t") || text.contains("。") || text.endswith("、"))
return false;
// 过滤纯数字/特殊符号文本
string cleantext = text.trim();
if (cleantext.matches("^[0-9\\p{punct}]+$"))
return false;
// 过滤长度异常文本(2-50字符为合理标题长度)
if (text.length() > 50 || text.length() < 2) return false;
// 匹配常见标题格式(第x章、x.1、一、(一)等)
for (pattern pattern : title_patterns) {
if (pattern.matcher(text).matches()) {
return true;
}
}
// 匹配标题关键词(概况、总则、前言等)
string[] titlekeywords = {"概况", "概述", "前言", "引言", "摘要", "总结", "结论", "总则"};
for (string keyword : titlekeywords) {
if (text.contains(keyword)) {
return true;
}
}
return false;
}
// 常见标题格式正则
private static final list<pattern> title_patterns = arrays.aslist(
pattern.compile("^第[零一二三四五六七八九十百千\\d]+章[\\s ]+(.+)$"),
pattern.compile("^第[零一二三四五六七八九十百千\\d]+节[\\s ]+(.+)$"),
pattern.compile("^\\d+[.\\.](?!.*%).*[^%]$"),
pattern.compile("^[一二三四五六七八九十]、[\\s ]*(.+)$"),
pattern.compile("^[\\((][一二三四五六七八九十][\\))][\\s\\t]*(.+)$"),
pattern.compile("^\\d+[.\\.]\\d+[.\\.].[^%]$")
);
2.3.2 章节层级识别
根据标题格式判定层级(1级:第x章/一、;2级:(一)/x.1;其他为非标题):
public static int detectchapterlevel(string text) {
text = text.trim();
// 1级标题:第x章、中文数字+顿号
if (text.matches("^第[零一二三四五六七八九十百千\\d]+章.*") || text.matches("^[零一二三四五六七八九十百千\\d]+、.*")) {
return 1;
}
// 2级标题:(一)、x.x格式
if (text.matches("^[\\((][一二三四五六七八九十][\\))][\\s\\t]*(.+)$") || text.matches("^\\d+[.\\.]\\d+[.\\.].[^%]$")) {
return 2;
}
return 0; // 非标题
}
2.3.3 层级结构整理
利用栈结构构建父子层级关系,核心逻辑是“弹出栈中层级≥当前层级的节点,将当前节点加入父节点子列表”:
public list<chapter> organizechaptersbylevel(list<chapter> rawchapters) {
list<chapter> rootchapters = new arraylist<>();
stack<chapter> levelstack = new stack<>(); // 栈记录当前层级父节点
for (chapter chapter : rawchapters) {
int level = chapter.getlevel();
// 找到当前节点的父节点(栈顶层级 < 当前层级)
while (!levelstack.isempty() && levelstack.peek().getlevel() >= level) {
levelstack.pop();
}
// 根节点(无父节点)加入根列表,否则加入父节点子列表
if (levelstack.isempty()) {
rootchapters.add(chapter);
} else {
levelstack.peek().getsubchapters().add(chapter);
}
// 当前节点入栈,作为后续子节点的父节点
levelstack.push(chapter);
}
return rootchapters;
}
2.4 解析unstructured json章节结构
针对unstructured工具输出的json数据,基于element_id和parent_id构建树形章节:
public list<chapter> extractchaptersfromunstructured(jsonarray responsejson) {
list<chapter> chapters = new arraylist<>();
map<string, chapter> chaptermap = new hashmap<>(); // element_id -> chapter
map<string, list<chapter>> parentchildrenmap = new hashmap<>(); // parent_id -> 子章节
// 第一步:提取所有title类型元素
for (object parsed : responsejson) {
jsonobject parsedobject = (jsonobject) parsed;
string type = parsedobject.getstring("type");
if (stringutils.isnotempty(type) && type.tolowercase().contains("title")) {
string elementid = parsedobject.getstring("element_id");
string text = parsedobject.getstring("text");
jsonobject metadata = parsedobject.getjsonobject("metadata");
integer depth = metadata != null ? metadata.getinteger("category_depth") : null;
string parentid = metadata != null ? metadata.getstring("parent_id") : null;
int level = (depth != null ? depth : 0) + 1; // 层级计算(depth从0开始)
chapter chapter = new chapter(text, level, 0);
chaptermap.put(elementid, chapter);
// 建立父子映射
if (parentid != null && !parentid.isempty()) {
parentchildrenmap.computeifabsent(parentid, k -> new arraylist<>()).add(chapter);
} else {
chapters.add(chapter); // 无父节点为根章节
}
}
}
// 第二步:将子章节挂载到父章节
for (map.entry<string, list<chapter>> entry : parentchildrenmap.entryset()) {
string parentid = entry.getkey();
list<chapter> children = entry.getvalue();
chapter parent = chaptermap.get(parentid);
if (parent != null) {
parent.getsubchapters().addall(children);
}
}
return chapters;
}
三、核心入口方法
对外提供统一的章节提取入口,自动选择提取策略:
public list<chapter> extractchapters(string content) throws ioexception {
log.info("开始大模型识别文本标题");
if (content == null || content.isempty())
return new arraylist<>();
list<chapter> llmchapters = getllmchapters(content);
if (llmchapters.isempty()) {
log.info("未检测到大模型识别的文本标题,开始文本分析识别文本标题");
return getchaptersbyanalysis(content);
} else
return llmchapters;
}
四、方案优势与扩展方向
4.1 优势
- 多策略兜底:大模型+规则双策略,兼顾识别精度和稳定性;
- 通用性强:支持纯文本、unstructured json等多种输入格式;
- 层级精准:通过正则+栈结构,精准构建章节父子关系;
- 可配置化:标题正则、关键词、层级规则均可按需调整。
4.2 扩展方向
- 字体特征融合:若解析pdf时能获取字体大小、加粗等特征,可融入层级判定逻辑,提升精度;
- 自定义规则:支持配置化管理标题正则、关键词,适配不同行业文档(如法律、医疗、技术文档);
- 大模型优化:优化prompt模板,加入更多格式约束,提升llm输出稳定性;
- 性能优化:针对超长文本,实现分段处理、并行解析,提升处理效率。
五、总结
本文的文档章节提取方案,结合了大模型的智能解析能力和规则引擎的稳定性,能够高效处理各类非结构化文档的章节提取需求。
以上就是基于java实现文档章节结构智能提取方案详解的详细内容,更多关于java文档章节结构智能提取的资料请关注代码网其它相关文章!
发表评论