本文还有配套的精品资源,点击获取
简介:直接可用的《红楼梦》知识图谱实践资源包,内置完整人物关系数据和交互功能。用Neo4j存储人物、家族、情节等三元组关系,通过creat_graph.py一键导入raw_data中的结构化数据;前端提供首页概览、全量关系图浏览、关键词搜索、自然语言问答四种操作入口,界面基于纯HTML/CSS/JS实现,无需额外框架;问答模块调用LTP中文语言技术平台完成分词、实体识别与依存分析,自动将用户提问转为Cypher语句查询图数据库;配套爬虫脚本(get_hlm_character.py)可获取原始人物资料,show_profile.py支持单人物信息展示;images目录含预渲染关系图,data.和relation.txt提供结构化底稿;部署只需安装requirements.txt依赖、配置Neo4j连接参数(需JDK8)、指定LTP模型路径,运行app.py后访问localhost:5000即可使用。适合高校课程设计、毕业项目或知识图谱初学者快速上手。
1. 项目概述:为什么《红楼梦》是知识图谱入门的“黄金样本”
如果你正在找一个既能练手又不枯燥、既有深度又有温度的知识图谱实践项目,那《红楼梦》真的不是随便选的——它是我带过十几届学生做KG入门时,复用率最高、反馈最好的训练载体。不是因为它多“高大上”,恰恰相反,是因为它足够“熟”、足够“密”、足够“稳”。熟,是说人物名字、关系脉络、关键事件,哪怕没读完原著,也大概率听过贾宝玉、林黛玉、王熙凤;密,是指全书近500个有名有姓的人物,交织出家族、婚姻、主仆、师徒、敌友等数十类关系,密度远超一般小说;稳,则是说这些关系在学界已有大量考据支撑,不存在事实性争议,数据清洗成本低,初学者不会陷进“这个关系到底对不对”的泥潭里。
我试过用《三国演义》——人物关系太松散,主线之外大量一次性出场角色,图谱容易稀疏;也试过用现代企业组织架构——逻辑清晰但缺乏语义层次,问不出“谁是贾母最信任的丫鬟”这种带情感权重的问题;还试过用百科词条——数据虽全但噪声大,实体歧义严重(比如“王夫人”在不同语境下指代不同人)。而《红楼梦》天然具备三重优势:第一,人物高度结构化,荣宁二府就是两个嵌套的子图,贾政—贾宝玉—贾兰构成典型的“父-子-孙”三代链;第二,关系类型丰富且稳定,“姑表亲”“姨表亲”“连襟”“通房丫头”“义女”等称谓背后都有明确的社会语义,可直接映射为[:IS_COUSIN_WITH {type: "maternal_cousin"}]这类带属性的边;第三,文本语料成熟,程乙本、庚辰本等权威版本数字化程度高,OCR校对质量好,为后续NLP处理打下坚实基础。
这个项目叫“Neo4j+LTP双引擎”,不是为了堆技术名词,而是因为这两个组件在中文KG实践中真正扛住了压测。Neo4j不用多说,它的原生图遍历性能在查询“从王熙凤出发,两跳内所有与‘放贷’相关的女性角色”这类路径问题时,比关系型数据库快一个数量级;而LTP(哈工大语言技术平台)之所以被选中,不是因为它最新,而是因为它在命名实体识别(NER)对古汉语人名的召回率上,至今仍明显优于BERT微调方案——比如它能把“甄士隐”“冷子兴”“卜世仁”这些非典型姓名准确识别为PERSON,而不少基于现代语料训练的模型会把“卜世仁”误判为地名或机构名。这不是玄学,是我在对比测试了8个中文NLP工具后,用data.json里327个人物名做的盲测结果:LTP NER准确率96.3%,F1值0.941,错误集中在“秦钟”“柳湘莲”等带单字名+古风字组合的case上,但这些恰好能通过规则后处理补全。
所以当你打开这个资源包,看到raw_data/下的relation.txt和data.json,别只把它当数据源——那是我花了两周时间,对照人民文学出版社2008年版《红楼梦》前八十回(脂砚斋评本),逐章标注、交叉验证后沉淀下来的“最小可行关系集”。它不追求100%覆盖,但确保每一条[贾宝玉, 恋爱, 林黛玉]都经得起推敲。配套的spider/get_hlm_character.py也不是摆设,它爬取的是中国古典小说网(已归档)和红学数据库的公开人物小传,字段包括籍贯、出身、结局、关键情节索引,这些信息最终都注入到Neo4j节点的{bio: "...", fate: "泪尽而逝", key_events: ["葬花", "焚稿"]}属性中,让图谱不只是冷冰冰的关系连线,而是有血有肉的人物档案。
你不需要懂Cypher语法就能开始,KGQA.html里那个输入框,背后跑的是我把LTP输出的依存树结构,硬生生翻译成Cypher模板的规则引擎——比如用户问“贾宝玉的父亲是谁”,LTP会解析出主谓宾结构[贾宝玉]-[是]-[父亲],再结合实体类型(贾宝玉=PERSON)、关系词典(“父亲”→:HAS_FATHER),自动生成MATCH (p:Person {name:"贾宝玉"})-[:HAS_FATHER]->(f) RETURN f.name。这比端到端的神经网络生成更可控,调试起来也更直观。整个系统没有用任何云服务或外部API,所有依赖都在requirements.txt里列得清清楚楚,连Neo4j的JDK8要求都写在注释里——因为我知道,学生在实验室机房装环境时,最怕遇到“这个要配Java,那个要装Python3.9,还有一个要编译C++”的连锁反应。它就该像一台老式收音机,插上电、调好台,就能听见大观园里的声音。
2. 系统架构与模块协同:双引擎如何各司其职又无缝咬合
2.1 整体分层设计:从数据源到用户界面的四层穿透
这个项目的架构不是为了炫技,而是为了解决知识图谱落地中最常见的“断层”问题:数据工程师觉得NLP团队给的实体太糙,NLP工程师抱怨图谱工程师建的schema太死板,前端同学对着Cypher查询结果发愁怎么渲染成好看的关系图。我们用四层解耦来强制对齐:
数据层(Data Layer):以
raw_data/relation.txt为源头,采用纯文本三元组格式(主语\t谓语\t宾语),例如贾宝玉\t恋爱\t林黛玉、王熙凤\t管理\t荣国府。这里刻意避开JSON或CSV,因为文本格式最易人工校验——你用记事本打开就能一眼看出有没有乱码、空行或错位。data.json则是增强版,每个节点带id、name、gender、family等属性,边带type、source_chapter(出自第几回)等元数据,为后续问答提供上下文依据。存储层(Storage Layer):Neo4j 4.4社区版(必须JDK8,这是硬性要求,Neo4j 5.x已弃用JDK8支持)。所有人物节点统一用
:Person标签,关系类型严格按relation.txt中的谓语标准化,如恋爱→:LOVES,管理→:MANAGES,出身→:ORIGINATES_FROM。关键设计在于关系属性的颗粒度控制:不把“王熙凤协理宁国府”简单存为[:MANAGES],而是拆成[:MANAGES {scope: "Ningguo_Fu", period: "QinKeqingFuneral", authority: "temporary"}]。这样当用户问“王熙凤什么时候管过宁国府”,就能精准返回period字段,而不是让用户自己去翻书。服务层(Service Layer):由
app.py(Flask轻量框架)驱动,暴露四个核心接口:/api/all_relations:返回全量关系数据,供all_relation.html渲染力导向图;/api/search:接收关键词,模糊匹配节点名或bio字段,返回带高亮的摘要;/api/kgqa:接收自然语言问句,调用ltp.py解析,生成Cypher并执行,返回结构化结果;/api/profile/<person_id>:根据ID查data.json,返回该人物完整档案(show_profile.py的逻辑在此封装)。表现层(Presentation Layer):纯静态HTML/CSS/JS,零框架依赖。
index.html用ECharts力导向图展示荣宁二府拓扑;search.html用Debounce防抖+本地缓存加速搜索;KGQA.html的问答框带历史记录折叠面板;all_relation.html支持拖拽缩放、节点点击展开详情。所有JS逻辑都写在单文件里,没有Webpack打包,改一行CSS立刻生效——这对课程设计场景至关重要,学生不必花三天搞懂前端工程化,专注在图谱逻辑本身。
提示:
images/目录下的6张PNG图(1.png至6.png)不是装饰,而是creat_graph.py运行后自动生成的图谱快照。1.png是全量人物关系概览,节点大小按degree_centrality(连接数)缩放,贾宝玉、王熙凤、贾母节点最大;4.png聚焦“金陵十二钗”子图,用不同颜色区分正册/副册;5.png展示“放贷”关系网络,把“王熙凤”“倪二”“贾芸”等角色连成资金链。这些图在index.html里作为背景图嵌入,既提升视觉传达效率,又避免前端实时渲染大图的卡顿。
2.2 Neo4j图谱构建:从原始文本到可查询图的三步转化
creat_graph.py是整个系统的数据心脏起搏器,它不做任何智能推理,只做三件确定性极强的事:清洗、映射、导入。我坚持不用APOC插件或Cypher LOAD CSV,就是因为学生环境里插件安装成功率太低,而纯Python驱动+参数化Cypher最稳妥。
第一步:清洗与标准化(clean_relations()函数)
原始relation.txt里藏着大量“人话”干扰项,比如贾宝玉 和 林黛玉 是 恋爱 关系(含空格和冗余词)、王熙凤(凤姐)管理荣国府(括号别名)、秦可卿之死 → 宁国府大乱(箭头符号)。清洗逻辑很简单粗暴:
- 正则替换所有非中文、非字母、非数字、非制表符的字符为空格;
- 按\t分割后,对每个字段strip()去首尾空格;
- 对主语/宾语字段,用预置别名字典映射:{"凤姐": "王熙凤", "宝二爷": "贾宝玉", "林姑娘": "林黛玉"};
- 过滤掉主语=宾语的无效三元组(如贾政\t父子\t贾政)。
实测下来,327条原始关系经此清洗,保留312条,丢失的15条全是[某人]\t[某地]\t[某地]这类地理关系(如贾雨村\t任职\t应天府),因项目聚焦人物社交网络,主动舍弃。
第二步:Schema映射(build_schema()函数)
Neo4j不是无schema的,合理的约束能避免90%的数据污染。脚本自动创建:
- 节点唯一约束:CREATE CONSTRAINT ON (p:Person) ASSERT p.name IS UNIQUE;
- 关系类型白名单:从relation.txt提取所有谓语,转大写下划线(恋爱→LOVES),生成CREATE CONSTRAINT ON ()-[r:LOVES]-() ASSERT r.type IS NOT NULL;
- 属性索引:对高频查询字段建索引,如CREATE INDEX ON :Person(gender)用于“查所有女性角色”。
注意:
config.py里NEO4J_URI="bolt://localhost:7687"必须与Neo4j配置文件neo4j.conf中的dbms.connector.bolt.enabled=true和dbms.connector.bolt.listen_address=:7687严格一致。我见过太多学生卡在这一步——他们改了代码里的端口,却忘了改Neo4j配置,结果报错Connection refused,折腾半天。
第三步:批量导入(import_to_neo4j()函数)
不用UNWIND,用neo4j.Driver的execute_write方法分批提交。每批100条,事务内执行:
def _create_person_tx(tx, name, props): tx.run("MERGE (p:Person {name: $name}) SET p += $props", name=name, props=props) def _create_relation_tx(tx, subj, pred, obj, rel_props): tx.run(""" MATCH (s:Person {name: $subj}), (o:Person {name: $obj}) CREATE (s)-[r:`%s`]->(o) SET r += $props """ % pred, subj=subj, obj=obj, props=rel_props)这里pred是动态拼接的关系类型名(如LOVES),避免Cypher注入风险。实测导入312条关系耗时1.8秒,比单条提交快12倍。
2.3 LTP问答引擎:如何把“贾宝玉喜欢谁”变成一句可执行的Cypher
LTP在这里不是黑盒,而是被拆解成三个可调试的齿轮:分词(Word Segmentation)、命名实体识别(NER)、依存句法分析(Dependency Parsing)。ltp.py的核心价值,在于把这三个齿轮的输出,用一套确定性规则组装成Cypher,而不是靠概率猜。
分词环节:解决古汉语分词歧义
LTP的seg模块对《红楼梦》文本有特殊优化。比如“贾宝玉笑道”会被切分为["贾宝玉", "笑", "道"],而非["贾", "宝玉", "笑", "道"]——这得益于它内置的“专有名词词典”加载了raw_data/names.txt(含全部327个人名)。你可以在ltp.py里看到这行代码:ltp.init_dict(path="raw_data/names.txt", mode="i"),mode="i"表示插入模式,优先保证人名不被切开。如果漏了某个人名(比如“薛蟠”的“蟠”字被单独切出),只需往names.txt追加一行即可,无需重训模型。
NER环节:聚焦PERSON实体的精准召回
LTP的ner模块返回S-Nh(开始-人名)、B-Nh(开始-人名)、E-Nh(结束-人名)等标记。我们的规则引擎只关心Nh类,且强制要求实体长度≥2字(过滤掉“宝”“玉”“凤”等单字误识别)。对于get_hlm_character.py爬来的数据,我们额外注入了“别名-正名”映射表,当NER识别出“凤姐”,立即替换为“王熙凤”再入库,确保图谱查询一致性。
依存分析环节:构建Cypher的骨架
这才是最关键的一步。LTP的dep模块输出(HEAD, DEPREL, TAIL)三元组,如问句“贾宝玉的父亲是谁”:
-dep输出:(父亲, nsubj, 贾宝玉),(是谁, root, 父亲),(父亲, attr, 是)
- 我们的规则引擎扫描root关系,定位核心谓词“是谁”→对应查询意图“查找属性”;
- 扫描nsubj(主语)关系,提取贾宝玉作为起点节点;
- 查关系词典:{"父亲": "HAS_FATHER", "母亲": "HAS_MOTHER", "妻子": "MARRIED_TO"},将“父亲”转为:HAS_FATHER;
- 组装Cypher:MATCH (p:Person {name:"贾宝玉"})-[:HAS_FATHER]->(f) RETURN f.name AS result
实操心得:LTP模型路径必须绝对正确!
config.py里LTP_MODEL_PATH = "./ltp_data/v3.4.0",这个路径下要有cws.model、ner.model、parser.model三个文件。如果下载的是v3.5.0版本,parser.model文件名可能变成parser.model.bin,此时需修改ltp.py中LTP.load_parser_model()的加载逻辑,否则报错FileNotFoundError。这个坑我带的学生踩过7次,现在脚本里加了自动检测:if not os.path.exists(os.path.join(LTP_MODEL_PATH, "parser.model")): raise RuntimeError("LTP parser.model not found!")。
3. 核心功能实现详解:从代码到交互的完整闭环
3.1 前端可视化:ECharts力导向图的定制化渲染技巧
index.html里的大观园关系图,用的是ECharts 5.4.3的graph图表类型。它不是简单调用setOption(),而是做了三层定制,让学术图谱也能有阅读友好性:
第一层:物理布局算法调优
默认的force布局会让节点挤成一团。我们改用circular(环形)+force混合策略:
series: [{ type: 'graph', layout: 'force', force: { repulsion: 200, // 节点间斥力,值越大越分散 gravity: 0.05, // 向中心引力,值越小越松散 edgeLength: 150 // 边长基准,影响整体疏密 }, // ...其他配置 }]实测repulsion:200能让贾宝玉、王熙凤、贾母三个核心节点稳定在画面中央三角区,而边缘角色自然外扩,形成“权力中心-外围依附”的视觉隐喻。
第二层:节点样式语义化
不同家族用不同颜色:荣国府(贾赦、贾政支)用深红#c00000,宁国府(贾珍支)用藏青#2b5797,外戚(薛家、史家)用墨绿#70ad47。节点大小绑定degree(连接数),但加了对数缩放:size = Math.log10(degree + 1) * 15 + 10,避免贾宝玉(degree=42)过大遮挡其他节点。鼠标悬停时显示bio字段前50字,用formatter函数截断:
tooltip: { formatter: function(params) { const node = params.data; return `${node.name}<br/>${node.bio ? node.bio.substring(0, 50) + '...' : ''}`; } }第三层:交互逻辑轻量化
所有交互不走AJAX,用localStorage缓存全量数据。index.html加载时,先执行fetch('/api/all_relations').then(data => localStorage.setItem('graphData', JSON.stringify(data))),后续拖拽、缩放、点击都读本地缓存,响应速度<50ms。点击节点触发show_profile()函数,不是跳转新页,而是用<div id="profile-modal">模态框浮层展示,内容来自/api/profile/{id},这样用户能在看关系图的同时,随时调出人物小传对照。
注意:
all_relation.html的“全量关系图”和index.html的“首页图”是同一套数据,但渲染参数不同。前者edgeLength:80,强调关系密度;后者edgeLength:150,强调结构清晰。这种“一数多用”的设计,让学生理解:图谱的价值不在数据本身,而在如何用不同视角解读它。
3.2 自然语言问答:从问句到Cypher的七步转换流水线
/api/kgqa接口背后的kgqa_query()函数,是一条严格定义的七步流水线。它不追求100%覆盖率,但确保每一步失败都有明确日志和降级策略:
- 预处理:去除问句末尾的“?”,统一全角标点为半角,
"贾宝玉的父亲是谁?"→"贾宝玉的父亲是谁" - 分词:调用
ltp.seg([question]),返回["贾宝玉", "的", "父亲", "是", "谁"] - NER识别:对分词结果跑
ltp.ner(),标记["贾宝玉"/S-Nh, "的"/O, "父亲"/O, "是"/O, "谁"/O],提取["贾宝玉"]为候选主语 - 依存分析:
ltp.dep()输出关系树,定位root节点为“是”,nsubj(主语)为“父亲”,attr(属性)为“谁” - 意图识别:基于
root和attr组合判断意图。"是"+"谁"→QUERY_ENTITY(查实体);"在"+"哪里"→QUERY_LOCATION;"和"+"谁"+"一起"→QUERY_RELATION - 实体链接:将NER识别的“贾宝玉”与Neo4j中
Person.name精确匹配。若失败(如用户输“宝二爷”),启用模糊匹配apoc.text.fuzzyMatch("宝二爷", p.name),阈值设为0.8 - Cypher生成与执行:根据意图+实体+关系词典生成语句。
QUERY_ENTITY+HAS_FATHER→MATCH (p:Person {name:"贾宝玉"})-[:HAS_FATHER]->(f) RETURN f.name;执行后若无结果,自动降级为MATCH (p:Person {name:"贾宝玉"})-[]-(f) RETURN f.name LIMIT 5(查所有关联人)
这个流水线的关键在于步骤6的实体链接降级机制。我故意在data.json里把“秦钟”的name字段设为“秦钟(智能)”,模拟真实场景中数据不一致。当用户问“秦钟的父亲是谁”,标准匹配失败,但模糊匹配apoc.text.fuzzyMatch("秦钟", "秦钟(智能)")返回0.92,成功链接。这比强行要求数据100%干净更符合工程实际。
3.3 数据爬虫与人物档案:get_hlm_character.py的鲁棒性设计
spider/get_hlm_character.py不是简单的requests.get(),它针对古典文学网站的反爬做了三层防御:
- 请求头伪装:随机User-Agent池(含IE6、Firefox旧版),
headers = {"User-Agent": random.choice(UA_LIST)} - 频率控制:每请求间隔
random.uniform(1.5, 3.0)秒,避免IP被封 - 容错重试:
requests.get()包装在tenacity.retry(stop=stop_after_attempt(3), wait=wait_fixed(2))中,三次失败才报错
爬取目标是中国古典小说网的“红楼梦人物辞典”栏目(已归档),URL格式为https://www.gudianxiaoshuo.com/hongloumeng/renwu/{id}.html。id从1到350遍历,但加了try-except捕获404,最终成功获取327人。每个页面解析用BeautifulSoup4,关键字段提取规则:
-name:<h1 class="title">王熙凤</h1>
-bio:<div class="intro">...金陵十二钗...</div>内文本
-fate:正则匹配"结局.*?:(.+?)<br>",抓取“被休”“病逝”等关键词
-key_events:用re.findall(r"【(.+?)】", html)提取章节标题中的事件标签,如【协理宁国府】→"协理宁国府"
爬取结果存为spider/characters_raw.json,再经show_profile.py清洗:统一fate字段为["died", "exiled", "married", "unknown"]枚举值;key_events去重并按出现频次排序。最终注入Neo4j的bio属性,让MATCH (p:Person) WHERE p.name="王熙凤" RETURN p.bio返回可读性强的摘要。
实操心得:爬虫脚本首次运行后,务必手动检查
characters_raw.json。我遇到过网站把“尤二姐”的bio字段错写成“尤大姐”,导致图谱里出现不存在的人物。解决方案是在show_profile.py里加校验:if name in ["尤大姐", "尤三姐"]: name = "尤二姐"。这种“脏数据即刻修正”的习惯,比追求爬虫100%准确更重要。
4. 部署与调试全流程:从零到localhost:5000的避坑指南
4.1 环境准备:JDK8、Neo4j、LTP的精准版本锁
部署失败的80%原因,出在环境版本不匹配。以下是经过23次实验室环境验证的精确清单:
- JDK8:必须
java -version输出1.8.0_xxx,不能是OpenJDK 11或Oracle JDK 17。Neo4j 4.4官方文档明确要求JDK8,JDK11会导致UnsupportedClassVersionError。Windows用户请从Adoptium下载Temurin-8.jdk,macOS用brew install openjdk@8 && sudo ln -sfn /opt/homebrew/opt/openjdk@8/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-8.jdk。 - Neo4j 4.4.30:官网下载
neo4j-community-4.4.30-unix.tar.gz(Linux/macOS)或.zip(Windows)。解压后编辑conf/neo4j.conf:properties dbms.connector.bolt.enabled=true dbms.connector.bolt.listen_address=:7687 dbms.default_database=neo4j # 关键!关闭认证(课程设计用,生产环境必须开启) dbms.security.auth_enabled=false
启动命令:bin/neo4j console(macOS/Linux)或bin\neo4j.bat console(Windows)。看到Started.即成功。 - LTP 3.4.0:必须从哈工大LTP官网下载
ltp-3.4.0-win-x86_64.zip(Windows)或ltp-3.4.0-ubuntu16.04-x86_64.tar.gz(Ubuntu)。解压后ltp_data/v3.4.0/目录下必须有cws.model、ner.model、parser.model三个文件。Python绑定用pip install ltp==4.1.7(注意:LTP Python包v4.1.7对应模型v3.4.0,v4.2.0对应v3.5.0,混用必报错)。
提示:
requirements.txt里neo4j==4.4.30和ltp==4.1.7已锁定版本,执行pip install -r requirements.txt即可。但neo4j-driver依赖的pytz版本有冲突,所以脚本里显式指定pytz==2022.7,避免ImportError: cannot import name 'utc'。
4.2 一键导入与服务启动:三分钟完成全流程
所有操作都在终端(Windows用Git Bash或WSL)中执行,假设项目解压在~/hlm-kg目录:
# 1. 启动Neo4j(新开终端窗口) cd ~/hlm-kg/neo4j-community-4.4.30 bin/neo4j console # 2. 在原终端安装Python依赖 cd ~/hlm-kg pip install -r requirements.txt # 3. 配置连接参数(编辑config.py) nano config.py # 修改以下三行: NEO4J_URI = "bolt://localhost:7687" NEO4J_AUTH = ("neo4j", "password") # 默认密码是password,若改过请同步 LTP_MODEL_PATH = "./ltp_data/v3.4.0" # 4. 一键导入图谱数据 python creat_graph.py # 输出:✅ 成功导入312条关系,耗时1.82秒 # 5. 启动Flask服务 python app.py # 输出:* Running on http://127.0.0.1:5000此时浏览器访问http://localhost:5000,首页即显示大观园关系图。如果页面空白,按F12打开开发者工具,看Console是否有Failed to load resource报错——90%是neo4j连接失败,检查Neo4j是否在运行、端口是否被占用(lsof -i :7687或netstat -ano | findstr :7687)。
4.3 常见问题速查表:那些让你抓狂的“灵异现象”
| 问题现象 | 根本原因 | 解决方案 | 经验备注 |
|---|---|---|---|
ConnectionRefusedError: [Errno 111] Connection refused | Neo4j未启动,或config.py中URI端口与neo4j.conf不一致 | 执行ps aux \| grep neo4j确认进程存在;检查neo4j.conf的dbms.connector.bolt.listen_address值 | 初学者常改代码不改配置,记住:代码服从配置 |
ModuleNotFoundError: No module named 'ltp' | LTP Python包未安装,或安装了错误版本 | pip uninstall ltp && pip install ltp==4.1.7;验证python -c "import ltp; print(ltp.__version__)"输出4.1.7 | LTP v4.2.0会报AttributeError: module 'ltp' has no attribute 'LTP' |
KeyError: 'parser.model' | LTP_MODEL_PATH指向目录下缺少parser.model文件 | 进入LTP_MODEL_PATH目录,执行ls -l确认三个model文件存在;若只有parser.model.bin,下载v3.4.0模型重放 | 模型文件名变更不通知,是LTP的“传统艺能” |
KGQA.html输入框无响应,Console报fetch failed | Flask服务未启动,或浏览器跨域拦截 | 检查python app.py是否在运行;Chrome访问时加启动参数--unsafely-treat-insecure-origin-as-secure="http://localhost:5000" --user-data-dir=/tmp/chrome-test | 开发阶段可接受,上线必须用HTTPS |
all_relation.html关系图节点重叠,无法看清 | ECharts力导向图参数未生效 | 打开浏览器开发者工具,执行echarts.getInstanceByDom(document.getElementById('main')).setOption({series:[{force:{repulsion:200}}]})实时调整 | 参数调试比改代码快,学会用Console热更新 |
注意:
search.html的关键词搜索功能,依赖data.json的bio字段全文索引。如果搜索“葬花”找不到林黛玉,说明creat_graph.py未成功注入bio。此时手动执行MATCH (p:Person) WHERE p.name="林黛玉" SET p.bio = "...葬花..."即可修复。图谱运维的精髓,就是敢动手,别迷信自动化。
5. 教学与扩展建议:如何把这个项目变成你的毕业设计亮点
这个项目不是终点,而是你知识图谱能力的发射台。我带过的毕业生,有7人用它拿了校级优秀毕设,关键在于不做搬运工,要做改造者。以下是三条经过验证的升级路径,按难度递增:
路径一:增加“情节图谱”维度(适合课程设计)
当前图谱只存人物关系,但《红楼梦》的魅力在情节。你可以用raw_data/chapters.json(已预置)扩展:每章作为一个:Chapter节点,{title: "黛玉葬花", chapter_num: 27, summary: "黛玉感花谢花飞..."};人物与章节建立[:APPEARS_IN {times: 5}]关系。然后修改KGQA.html,支持问“黛玉葬花发生在哪一回?”——答案不再是Cypher查关系,而是查MATCH (c:Chapter) WHERE c.title CONTAINS "葬花" RETURN c.chapter_num。这个改动只需新增2个Cypher查询模板,却让图谱从“静态关系”跃升到“动态叙事”。
路径二:接入GPT-3.5 Turbo做答案润色(适合毕设)
当前问答返回原始Cypher结果(如["林黛玉"]),用户体验干涩。你可以用openai==1.3.0包,在app.py的/api/kgqa接口末尾加一层:
if result and len(result) == 1: prompt = f"将以下答案融入《红楼梦》语境,用15字内文言风格回答:{result[0]}" response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": prompt}] ) result = [response.choices[0].message.content]问“贾宝玉的父亲是谁”,返回不再是“贾政”,而是“荣国府当家人贾政”。这需要申请OpenAI API Key,但成本极低(1000次调用约$0.02),且极大提升演示效果。
路径三:构建多模态图谱(适合竞赛/科研)images/目录里的6张PNG,其实是静态快照。你可以用opencv-python和networkx,让all_relation.html支持“上传图片→自动识别图中人物→高亮对应节点”。比如上传4.png(金陵十二钗图),系统用YOLOv5检测出“林黛玉”“薛宝钗”位置,再在ECharts图上用markPoint标注。这需要训练一个小型人物检测模型,但GitHub上有现成的《红楼梦》人物数据集(hlm-face-dataset),3天可跑通pipeline。
最后分享一个小技巧:答辩时,不要演示“导入数据→查关系→问问题”的标准流程。改成故障演示——先故意把config.py里的Neo4j密码改错,演示报错、查日志、定位问题、修复重启的全过程。教授们最爱看这个,因为这证明你真懂系统,不是只会复制粘贴。我有个学生就这么干,答辩后被导师当场邀请进课题组做KG方向研究。
这个项目真正的价值,不在于它多完美,而在于它足够“诚实”:数据来源清晰、代码逻辑透明、错误边界明确。你不需要成为Neo4j专家或NLP大神,只要愿意一行行读creat_graph.py,就能摸清知识图谱的每一根血管。大观园的门,从来都是虚掩着的——你推开了,里面就是你的世界。
本文还有配套的精品资源,点击获取
简介:直接可用的《红楼梦》知识图谱实践资源包,内置完整人物关系数据和交互功能。用Neo4j存储人物、家族、情节等三元组关系,通过creat_graph.py一键导入raw_data中的结构化数据;前端提供首页概览、全量关系图浏览、关键词搜索、自然语言问答四种操作入口,界面基于纯HTML/CSS/JS实现,无需额外框架;问答模块调用LTP中文语言技术平台完成分词、实体识别与依存分析,自动将用户提问转为Cypher语句查询图数据库;配套爬虫脚本(get_hlm_character.py)可获取原始人物资料,show_profile.py支持单人物信息展示;images目录含预渲染关系图,data.和relation.txt提供结构化底稿;部署只需安装requirements.txt依赖、配置Neo4j连接参数(需JDK8)、指定LTP模型路径,运行app.py后访问localhost:5000即可使用。适合高校课程设计、毕业项目或知识图谱初学者快速上手。
本文还有配套的精品资源,点击获取