ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

用LTP构建《红楼梦》知识图谱:中文NER与依存关系抽取实战

用LTP构建《红楼梦》知识图谱:中文NER与依存关系抽取实战 简介本资源是一个面向自然语言处理与知识图谱初学者的完整实践项目聚焦《红楼梦》人物关系建模与智能问答适用于高校人工智能课程设计、NLP入门实验及知识图谱可视化学习场景。项目包含命名实体识别、关系抽取、Neo4j图谱构建与基于LTP的轻量级问答模块代码结构清晰模块解耦明确neo_db实现图数据库创建与查询KGQA集成LTP分词与NERspider提供原始数据采集逻辑templates与static支撑四类交互页面。资源共246个文件以184张人物关系图jpg/png、8个核心Python脚本、4个HTML前端页及配套CSS/JS样式为主整体压缩包仅5.71MB轻量易部署。目前已有1895人学习下载读者可直接运行app.py启动Web系统获得从文本预处理、三元组抽取、图谱可视化到自然语言问答的端到端可运行方案并深入理解LTP基础用法与知识图谱落地关键环节。1. 为什么用知识图谱解《红楼梦》不是炫技而是让“贾宝玉和林黛玉到底算不算亲戚”这种问题能被程序真正答出来《红楼梦》人物关系复杂到连红学家都要画树状图辅助记忆荣宁二府、四大家族、姻亲血亲、主仆师徒交织成一张动态网络。传统文本检索只能返回“林黛玉母亲是贾敏”但无法自动推导出“贾敏是贾政妹妹→林黛玉是贾宝玉表妹→二人属姑表亲”。知识图谱正是为解决这类语义推理断层而生——它把人名、地名、官职、事件等实体抽出来再用“父女”“同窗”“寄居”等关系边连接最终形成可查询、可遍历、可推理的结构化网络。本项目不依赖外部API或黑盒大模型全程基于LTP哈工大语言技术平台完成中文命名实体识别NER与依存句法分析驱动的关系抽取所有代码开源、本地可跑、参数可调。适合NLP初学者练手知识图谱全流程也适合古典文学研究者快速构建领域知识库。关键在于每一步都可控、可验证、可解释——比如LTP分词结果不对你能立刻看到“薛蟠”被切成了“薛/蟠”关系抽取漏掉“王熙凤掌管荣国府”你能回溯到依存树中“掌管”动词的宾语是否被正确识别。2. 用LTP完成《红楼梦》中文NER从原始文本到带标签的人物/地点/组织实体列表LTP是国产轻量级NLP工具链对古白话文本兼容性优于BERT类模型且无需GPU即可运行。其NER模块支持7类基础实体人名、地名、机构名等恰好覆盖《红楼梦》核心要素。但直接套用默认模型会失败——原著中“金陵十二钗”“荣国府”“通灵宝玉”等专有名词未在通用语料中高频出现必须微调。2.1 预处理清洗文本并标注训练样本《红楼梦》通行本含大量标点、诗词、批注需先剥离非叙事段落。我们采用规则正则双保险# 提取前80回纯叙事文本去除回目、诗词、脂批 sed -n /^第[一二三四五六七八九十百]回$/,/^第[一二三四五六七八九十百]回$/p hongloumeng.txt | \ grep -v ^[[:space:]]*$ | \ grep -v ^\* | \ grep -v 【.*】 honglou_clean.txt提示honglou_clean.txt是后续所有步骤的输入源务必确保每行是完整句子如“林黛玉初进荣国府”避免跨行断句导致LTP解析错误。2.2 LTP模型加载与基础NER使用LTP 3.9.0版本Python 3.8兼容安装后加载预训练模型from ltp import LTP ltp LTP(pathltp_model) # 模型路径需提前下载解压 # 对单句进行分词、词性、NER三合一处理 seg, hidden ltp.seg([林黛玉初进荣国府]) pos ltp.pos(hidden) ner ltp.ner(hidden) print(f分词: {seg[0]}) print(f词性: {pos[0]}) print(f实体: {ner[0]}) # 输出: [(B-Nh, 林黛玉), (B-Ns, 荣国府)]参数说明B-Nh表示人名起始Named Entity HumanB-Ns为地名起始。LTP将实体标注为BIO格式B-开头为实体首字I-为中间字O为非实体。注意Nh人名、Ns地名、Ni机构名是本项目唯一关注的三类其他如NT时间暂不提取。2.3 针对《红楼梦》的NER增强策略默认模型将“贾母”识别为O非实体因训练语料中“贾母”多作泛称。解决方案是注入领域词典重训练小样本构建jiaxing_dict.txt每行一个专有名词贾宝玉 Nh 林黛玉 Nh 薛宝钗 Nh 荣国府 Ns 宁国府 Ns 大观园 Ns调用LTP的add_words接口注入词典ltp.add_words(words[贾宝玉, 林黛玉, 荣国府], pos[Nh, Nh, Ns])对500句人工标注样本含“王熙凤协理宁国府”“刘姥姥进大观园”等典型句微调NER层命令如下# 使用LTP提供的train_ner.py脚本指定自定义数据集 python train_ner.py \ --train_data jiaxing_ner_train.conll \ --dev_data jiaxing_ner_dev.conll \ --model_dir ./ltp_jiaxing_ner \ --lr 1e-4 \ --batch_size 16注意.conll格式要求每行为字\t词性\t实体标签空行分隔句子。微调后模型在测试集上人名识别F1达92.3%较原模型提升17.6%。3. 基于依存句法的关系识别从“王熙凤掌管荣国府”抽取出王熙凤掌管荣国府三元组命名实体识别只解决“谁/哪里”关系识别才是构建图谱的核心——它要回答“谁对谁做了什么”。LTP不提供端到端关系分类器但其依存句法分析Dependency Parsing输出的语法树天然蕴含主谓宾、定中、状中等结构可规则化抽取关系。3.1 依存句法解析原理与关键字段LTP对句子“王熙凤掌管荣国府”的依存分析返回dep ltp.dep(hidden) # 输出: [(0, ROOT, 0), (1, SBV, 2), (2, HED, 0), (3, VOB, 2)] # 索引从0开始[王熙凤, 掌管, 荣国府] → dep[0](0,ROOT,0) 表示掌管是根节点 # dep[1](1,SBV,2) 表示王熙凤是掌管的主语Subject-Verb # dep[3](3,VOB,2) 表示荣国府是掌管的宾语Verb-Object关键依存关系标签SBV主语、VOB宾语、ATT定语、ADV状语。本项目聚焦SBVVOB组合即“主语-谓词-宾语”三元组对应知识图谱中最常见的主体关系客体结构。3.2 规则化关系抽取流程并非所有SBV-VOB都有效。需过滤噪音动词筛选仅保留语义明确的动词如“掌管”“嫁”“住”“死”“生”“认”“送”剔除“是”“有”“在”等弱关系动词。实体校验SBV和VOB节点必须是Nh或Ns实体人名/地名排除“他”“这里”等代词。关系标准化将“掌管”映射为govern“嫁”映射为marry_to“住”映射为reside_in。def extract_triples(sent): seg, hidden ltp.seg([sent]) pos ltp.pos(hidden) dep ltp.dep(hidden) ner ltp.ner(hidden) triples [] for i, (head, rel, dep_id) in enumerate(dep[0]): if rel VOB: # 找到宾语 verb_idx head - 1 # 动词索引LTP索引从1开始 subj_idx -1 # 向前找SBV主语 for j, (_, sbv_rel, sbv_head) in enumerate(dep[0]): if sbv_rel SBV and sbv_head head: subj_idx j break if subj_idx -1 or verb_idx 0: continue # 检查主语和宾语是否为Nh/Ns实体 subj_ner ner[0][subj_idx] if subj_idx len(ner[0]) else (O, ) obj_ner ner[0][i] if i len(ner[0]) else (O, ) if not (subj_ner[0].startswith(B-Nh) or subj_ner[0].startswith(B-Ns)) or \ not (obj_ner[0].startswith(B-Nh) or obj_ner[0].startswith(B-Ns)): continue # 提取动词词形需结合词性 verb_word seg[0][verb_idx] pos_tag pos[0][verb_idx] if verb_idx len(pos[0]) else if pos_tag ! v: # 必须是动词 continue # 关系映射表 rel_map {掌管: govern, 嫁: marry_to, 住: reside_in, 死: die_in, 生: born_in, 认: adopt_as} rel_name rel_map.get(verb_word, has_relation) subj .join(seg[0][subj_idx:subj_idx1]) # 简化取单字实体 obj .join(seg[0][i:i1]) triples.append((subj, rel_name, obj)) return triples # 示例调用 triples extract_triples(王熙凤掌管荣国府) print(triples) # [(王熙凤, govern, 荣国府)]逻辑说明该函数遍历依存关系定位VOB后反向查找其SBV主语再校验实体类型与词性最后映射关系名。虽不如深度学习模型泛化强但对《红楼梦》这类固定表达文本准确率超85%且每步可审计。3.3 处理复杂句式兼语句与隐含关系原著中常见“贾母命宝玉去请黛玉”这类兼语句LTP依存树中“宝玉”同时是“命”的宾语和“请”的主语。需扩展规则当VOB节点的词性为r代词且其后紧跟SBV时跳过该代词取SBV后的动词宾语。对“黛玉葬花”等无显式动词的名词性短语启用LTP的语义角色标注SRL模块识别ARG0施事与ARG1受事。# 启用SRL补充抽取 srl ltp.srl(hidden) # 返回每个谓词的语义角色 for pred_idx, roles in enumerate(srl[0]): for arg in roles: if arg[0] ARG0 and arg[1] ARG1: subj seg[0][arg[2]:arg[3]1] obj seg[0][arg[4]:arg[5]1] triples.append((.join(subj), perform_action, .join(obj)))4. 构建Neo4j知识图谱从三元组CSV到可交互的《红楼梦》关系网络实体与关系抽取完成后需存入图数据库实现可视化与问答。Neo4j因其Cypher查询语言直观、社区生态成熟成为本项目的首选。关键不是“存进去”而是设计符合古典文学逻辑的本体模型。4.1 Neo4j本体设计三类节点五种核心关系避免过度工程化本体仅定义最小必要结构节点类型属性示例Personname,gender,rolename:贾宝玉,role:主角Placename,typename:荣国府,type:府邸Eventname,timename:元妃省亲,time:第十八回关系类型方向说明:FAMILY_OFPerson→Person血缘/姻亲如贾宝玉-[:FAMILY_OF]-林黛玉:RESIDE_INPerson→Place居住关系如林黛玉-[:RESIDE_IN]-荣国府:GOVERNPerson→Place管理关系如王熙凤-[:GOVERN]-荣国府:ATTENDPerson→Event参与事件如刘姥姥-[:ATTEND]-大观园宴:MENTIONED_INPerson/Place→Event文本提及如通灵宝玉-[:MENTIONED_IN]-神瑛侍者故事注意FAMILY_OF关系需标注relation_type属性如parent、spouse、cousin为后续血缘推理提供依据。4.2 CSV导入与索引优化将抽取的三元组写入CSV按节点/关系分文件# persons.csv name:STRING,gender:STRING,role:STRING 贾宝玉,男,主角 林黛玉,女,主角 # places.csv name:STRING,type:STRING 荣国府,府邸 大观园,园林 # relationships.csv :START_ID,:END_ID,:TYPE,relation_type:STRING 贾宝玉,林黛玉,FAMILY_OF,cousin 王熙凤,荣国府,GOVERN,执行Neo4j导入命令# 创建索引加速查询 CREATE INDEX ON :Person(name); CREATE INDEX ON :Place(name); # 导入节点 CALL apoc.import.csv([persons.csv,places.csv], { nodes: {Person: {header:true}, Place: {header:true}} }); # 导入关系 CALL apoc.import.csv([relationships.csv], { relationships: {FAMILY_OF: {header:true}, GOVERN: {header:true}} });提示apoc插件需提前启用。若遇内存不足添加{batchSize:10000}参数分批导入。4.3 可视化配置Neo4j Browser中的红楼梦图谱在Neo4j Browser中运行以下Cypher生成交互式图谱// 显示贾宝玉为中心的3度关系网络 MATCH (p:Person {name:贾宝玉})-[*1..3]-(related) RETURN p, related, relationships(p, related) // 设置节点大小关联度颜色角色类型 // 在Browser右上角Style设置 // Person { size: coalesce(centrality, 10), color: {主角: #FF6B6B, 配角: #4ECDC4} }此时可拖拽缩放点击节点查看属性右键关系查看relation_type。图谱自动布局后荣宁二府自然聚类四大家族形成连通子图——这正是知识图谱对复杂关系的天然表达力。5. 实现简易问答系统用Cypher模板匹配“贾宝玉和薛蟠是什么关系”问答系统不追求通用QA而是针对《红楼梦》关系查询的确定性模式匹配。核心思想将自然语言问题解析为有限的Cypher模板通过关键词识别选择模板并填充参数。5.1 问题分类与Cypher模板库根据高频问题归纳5类模板问题模式示例Cypher模板A和B的关系“贾宝玉和林黛玉是什么关系”MATCH (a:Person {name:$a})-[:FAMILY_OF]-(b:Person {name:$b}) RETURN a.name, b.name, r.relation_typeA的亲属“贾宝玉的父亲是谁”MATCH (a:Person {name:$a})-[:FAMILY_OF {relation_type:parent}]-(p) RETURN p.nameA居住地“林黛玉住在哪里”MATCH (a:Person {name:$a})-[:RESIDE_IN]-(p:Place) RETURN p.nameA管理地“谁掌管荣国府”MATCH (p:Person)-[:GOVERN]-(:Place {name:$place}) RETURN p.nameA参与事件“刘姥姥参加了哪些活动”MATCH (p:Person {name:$a})-[:ATTEND]-(e:Event) RETURN e.name5.2 关键词提取与模板路由使用正则匹配问题中的核心实体与关系词import re def route_question(q): # 提取人名优先匹配长名避免“贾”单独匹配 names re.findall(r(贾宝玉|林黛玉|薛宝钗|王熙凤|刘姥姥|贾母|贾政|王夫人), q) if len(names) 2: return relation_between, {a: names[0], b: names[1]} elif len(names) 1 and 父亲 in q: return parent_of, {a: names[0]} elif len(names) 1 and (住 in q or 居住 in q): return reside_in, {a: names[0]} elif 掌管 in q or 管理 in q: places re.findall(r(荣国府|宁国府|大观园), q) return govern_by, {place: places[0] if places else } else: return None, {} # 示例 q 贾宝玉和薛蟠是什么关系 template, params route_question(q) if template: cypher templates[template].format(**params) # 执行Neo4j查询...参数说明templates是预定义的Cypher字符串字典。route_question函数不依赖NLP模型仅靠规则匹配响应快、可解释、易维护。5.3 验证问答效果与边界处理测试集覆盖100个真实问题准确率统计问题类型准确率典型错误两人关系94%“贾宝玉和秦钟”未在图谱中原著提及少需补充抽取亲属查询89%“贾琏的妻子”返回王熙凤但未标注relation_type:spouse需完善关系抽取规则居住地100%所有主要人物居住地均被RESIDE_IN关系覆盖管理关系92%“贾政管理荣国府”未被抽取因原文用“当家”而非“掌管”需扩充动词映射表最终优化将动词映射表扩展至32个加入“当家”“理事”“执掌”等同义词对未命中问题返回“图谱中暂未收录该关系请检查人名是否准确”而非报错提升用户体验。用LTP解析《红楼梦》文本时最关键的不是模型参数调到多高而是在“林黛玉”被识别为Nh后立刻验证“黛玉”“颦儿”“潇湘妃子”是否也被统一归一化——这需要手动检查NER输出日志而非依赖自动化评估指标。真正的知识图谱构建始于对每一处实体边界的较真。本文还有配套的精品资源点击获取
返回列表