资讯动态

基于Neo4j构建《红楼梦》知识图谱:从数据建模到可视化查询实践

发布时间:2026/9/3 16:38:34 来源:尧图企业网站定制
简介本资源是一套面向Python初学者与知识图谱入门者的《红楼梦》结构化知识建模实践包聚焦于Neo4j图数据库的构建、导入与可视化展示解决人文文本知识抽取与关系建模的学习痛点。压缩包共7个文件1.62MB含核心Neo4j数据库备份.zbak、三元组数据源CSV、知识图谱可视化PNG图、主控Python脚本HLM.py、项目说明文档README.md及配套图像资源覆盖从数据准备、图库还原到前端展示的完整流程。已有160人学习下载适合高校文科信息学、数字人文或AI基础课程的教学辅助与课设参考。读者可直接加载数据库运行查询示例复现人物关系网络掌握实体-关系建模逻辑并基于CSV与Python脚本理解知识图谱构建的关键步骤——包括节点/边定义、属性映射及Cypher语句生成机制。1. 项目缘起当古典名著遇上现代图数据库最近在整理个人知识库时我一直在琢磨怎么把《红楼梦》里那几百号人物、错综复杂的关系和事件给理清楚。用Excel表格太扁平了贾宝玉和林黛玉的“木石前盟”和“知己”关系跟贾宝玉和薛宝钗的“金玉良缘”和“夫妻”关系在表格里就是几行冰冷的文字完全体现不出那种微妙的差异和情感的权重。用思维导图关系一多线条就乱成一团麻根本没法做深度的查询和分析比如“找出所有与王熙凤有直接经济往来且同时与贾琏有情感纠葛的女性角色”这种多跳查询在传统工具里几乎无法优雅实现。这让我想起了知识图谱。它本质上就是用“图”这种数据结构来建模真实世界节点代表实体比如人物、地点、事件边代表关系比如“是父亲”、“居住在”、“发生于”。这不正是为《红楼梦》这种关系密集型文本量身定做的吗而说到存储和查询知识图谱Neo4j几乎是绕不开的选择。它是一个原生图数据库不像传统的关系型数据库如MySQL需要通过各种JOIN来模拟关系Neo4j将关系作为一等公民存储查询起来就像在图上“漫步”直观又高效。网络上关于“neo4j构建知识图谱”、“neo4j使用教程”的搜索热度一直很高也侧面印证了大家对这个技术栈解决复杂关系问题的兴趣。所以我决定动手以《红楼梦》为蓝本构建一个可视化的知识图谱并用Neo4j作为后台引擎。这个项目的目的很纯粹第一亲手走一遍从数据整理、建模、导入到查询展示的全流程把“知识图谱”、“Neo4j”这些概念从理论落到实地第二产出一个能交互查询的“红楼人物关系图”算是给这部经典一个数字化的、可探索的新注解。无论你是对《红楼梦》感兴趣的文学爱好者还是想入门图数据库和知识图谱的开发者相信这个实践过程都能给你带来一些直观的启发。2. 知识图谱设计定义《红楼梦》的“数字灵魂”在往数据库里灌数据之前最重要的一步是设计图谱的“骨架”——也就是数据模型。这一步没做好后面查询和扩展都会很痛苦。我的核心思路是抓住《红楼梦》中最核心的实体和关系先建立一个最小可行模型MVP后续再根据需求丰富。2.1 实体类型节点标签设计在Neo4j中我们使用“标签”来分类节点。我为《红楼梦》设计了以下几类核心实体人物这是图谱的绝对核心。每个人物作为一个节点。属性方面我计划包含name姓名如“贾宝玉”、alias别名/字号如“怡红公子”、generation辈分如“玉”字辈、gender性别以及一个简短的intro简介。家族荣国府、宁国府、薛家、王家等。属性包括name家族名和faction阵营如“四大家族”。居所怡红院、潇湘馆、蘅芜苑等。属性主要是name名称和type类型如“院落”、“厅堂”。事件“黛玉葬花”、“宝玉挨打”、“元妃省亲”等关键情节。属性包括name事件名、chapter发生回目和summary概要。物品“通灵宝玉”、“金锁”、“冷香丸”等具有象征意义的重要物品。属性是name物品名和description描述。注意实体类型的设计不是一成不变的。比如初期我可能只设“人物”和“家族”但当我发现需要频繁查询“谁住在哪个院子”时增加“居所”实体就变得必要了。这是一个迭代的过程。2.2 关系类型设计关系是知识图谱的“经络”它让静态的节点活了起来。我定义了以下几种主要关系每一条关系都有方向和类型人物 - 人物:FAMILY_OF(属于...家族): 贾宝玉 - 贾家。:FATHER_OF/:MOTHER_OF/:SPOUSE_OF/:SIBLING_OF: 描述血缘与婚姻关系。:MASTER_OF/:SERVANT_OF: 描述主仆关系。:FRIEND_WITH/:LOVES/:RIVAL_WITH: 描述社会与情感关系。这里LOVES的权重和含义与SPOUSE_OF截然不同。人物 - 其他:LIVES_IN(居住在): 林黛玉 - 潇湘馆。:PARTICIPATED_IN(参与了): 贾宝玉 - 宝玉挨打。:OWNS(拥有): 薛宝钗 - 金锁。家族 - 家族:ALLIED_WITH(联姻/结盟于): 贾家 - 王家。这里有一个关键点关系的属性。例如:PARTICIPATED_IN关系上我可以增加一个role属性来区分参与者在事件中的角色是“主导者”、“受害者”还是“旁观者”。在“宝玉挨打”事件中贾政的role是“执行者”贾宝玉是“承受者”王夫人可能是“求情者”。这极大地丰富了关系的语义。2.3 从文本到结构化数据的挑战设计好模型下一步就是准备数据。这是最耗时、也最需要细致的一步。《红楼梦》原文是自然语言我们需要将其“翻译”成结构化的(实体1)-[关系]-(实体2)三元组。我采用的方法是混合策略手动整理核心数据对于主要人物金陵十二钗、贾府主要成员及其核心关系我手动从原著和权威资料中提取。这保证了基础数据的准确性。利用现有结构化资料互联网上有一些爱好者整理的红楼梦人物关系CSV或JSON数据。我可以将这些数据作为补充但必须仔细清洗和校验与我的数据模型对齐。考虑NLP技术辅助对于大规模、非核心的人物和事件理论上可以用自然语言处理工具进行实体识别和关系抽取。但这需要高质量的模型和大量的后处理对于个人项目来说成本较高我将其列为未来可探索的方向。最终我准备将数据整理成Neo4j支持的导入格式主要是CSV文件。我会为每种节点类型和关系类型分别创建CSV文件。3. Neo4j环境搭建与数据导入让图谱“安家”有了设计好的模型和清洗好的数据接下来就是让它们在Neo4j里“安家落户”。我选择在本地使用Neo4j Desktop进行开发因为它集成了数据库、浏览器和管理工具对初学者和开发者都非常友好。3.1 Neo4j Desktop的安装与项目创建从官网下载Neo4j Desktop的安装包过程很简单。安装完成后新建一个项目比如就叫“DreamOfRedMansion”。在项目中“添加”一个数据库。我选择了最新的Neo4j 5.x社区版。这里有个细节你需要为数据库设置一个密码比如honglou这个密码在后续连接时会用到。点击“Start”启动数据库。看到状态变成运行中说明数据库服务已经就绪。点击“Open”打开Neo4j Browser这是一个内置的Web界面我们可以在这里执行Cypher查询语句Neo4j的查询语言和管理数据库。整个过程如果网络通畅十分钟内就能完成一个可用的图数据库环境。比起在服务器上从头配置Desktop省去了大量繁琐步骤。3.2 使用Cypher创建图模式在导入海量数据前我习惯先创建一些约束和索引这能保证数据的一致性和查询性能。我在Neo4j Browser中执行以下Cypher语句// 为Person节点的name属性创建唯一性约束确保没有重名人物现实中需处理重名这里简化 CREATE CONSTRAINT person_name_unique IF NOT EXISTS FOR (p:Person) REQUIRE p.name IS UNIQUE; // 为常用查询字段创建索引加速查找 CREATE INDEX person_name_index IF NOT EXISTS FOR (p:Person) ON (p.name); CREATE INDEX family_name_index IF NOT EXISTS FOR (f:Family) ON (f.name); CREATE INDEX event_name_index IF NOT EXISTS FOR (e:Event) ON (e.name);创建约束和索引是一个好习惯尤其是在数据量大之后。UNIQUE约束防止了数据重复导入而索引能让MATCH (p:Person {name: \林黛玉\})这样的查询从全表扫描变成快速查找。3.3 通过LOAD CSV导入数据这是将外部数据载入Neo4j的核心步骤。假设我已经准备好了persons.csv、families.csv和relationships_family.csv等文件并将它们放在了Neo4j数据库的import目录下Neo4j Desktop中每个数据库都有对应的import文件夹。首先导入人物节点// 导入人物节点 LOAD CSV WITH HEADERS FROM file:///persons.csv AS row CREATE (p:Person) SET p row;LOAD CSV会读取CSV文件的每一行WITH HEADERS表示第一行是列名。CREATE创建节点SET p row是一个简洁的写法将row对象中的所有属性一次性赋给节点p。接着导入家族节点// 导入家族节点 LOAD CSV WITH HEADERS FROM file:///families.csv AS row CREATE (f:Family) SET f row;最后也是最关键的一步建立关系。这里需要用到节点的唯一标识通常是name来匹配并创建关系// 建立人物与家族的归属关系 LOAD CSV WITH HEADERS FROM file:///relationships_family.csv AS row MATCH (p:Person {name: row.person_name}) MATCH (f:Family {name: row.family_name}) CREATE (p)-[:FAMILY_OF]-(f);这个语句先根据CSV文件中提供的person_name和family_name分别找到对应的Person节点和Family节点然后在它们之间创建一条:FAMILY_OF的关系。实操心得在导入关系数据时最容易出错的就是节点匹配失败。务必确保CSV中的名称与已创建节点的属性值完全一致包括空格和标点。我建议在导入关系前先用小批量数据测试用LIMIT 5子句查看匹配结果。例如MATCH (p:Person {name: row.person_name}) RETURN p.name LIMIT 5确认能正确查到节点后再进行CREATE。4. Cypher查询实战探索红楼关系网络数据导入后Neo4j Browser就成了我们探索《红楼梦》世界的“望远镜”。Cypher查询语言的语法非常直观像在描述一幅图。4.1 基础查询寻找与探索让我们从一些简单的查询开始感受一下图查询的威力。查询林黛玉这个人物节点MATCH (p:Person {name: 林黛玉}) RETURN p这会返回林黛玉节点的所有属性。查找林黛玉的所有直接关系MATCH (p:Person {name: 林黛玉})-[r]-(related) RETURN p, r, related-[r]-表示任意类型和方向的关系。这个查询会返回一个图视图中心是林黛玉周围是她直接关联的所有人和事一目了然。查找贾宝玉的兄弟姐妹MATCH (jia:Person {name: 贾宝玉})-[:SIBLING_OF]-(sibling) RETURN sibling.name这里使用了:SIBLING_OF关系方向是双向的-因为兄弟姐妹关系是相互的。4.2 多跳查询挖掘深层关联图数据库最擅长的就是多跳查询这也是它相比关系型数据库的优势所在。查找与王熙凤有直接经济往来且同时与贾琏有情感纠葛的女性角色。这个查询听起来复杂但用Cypher表达却很清晰MATCH (wang:Person {name: 王熙凤})-[:BUSINESS_WITH]-(person1:Person) MATCH (jialian:Person {name: 贾琏})-[:LOVES|:SPOUSE_OF]-(person2:Person) WHERE person1 person2 AND person2.gender 女 RETURN person2.name这个查询做了两件事首先找到所有与王熙凤有:BUSINESS_WITH关系的人person1然后找到所有与贾琏有情感或婚姻关系的人person2。最后要求person1和person2是同一个人并且性别为女。结果可能会指向像“尤二姐”这样的角色。这里|符号用于匹配多种关系类型。查找“贾赦”和“贾政”的共同后代路径查询MATCH path (p1:Person {name: 贾赦})-[:FATHER_OF|:MOTHER_OF*1..3]-(commonDescendant)-[:FATHER_OF|:MOTHER_OF*1..3]-(p2:Person {name: 贾政}) RETURN commonDescendant.name, length(path) as depth ORDER BY depth这个查询使用了可变长度关系[*1..3]表示查找1到3跳以内的父子/母子关系。它找到了一个节点commonDescendant这个节点同时是贾赦和贾政在3代以内的后代。结果可能会是“贾兰”等。length(path)可以计算出这个共同后代与任一祖先之间的辈分距离。4.3 聚合与统计洞察全局我们还可以用Cypher做一些有趣的统计。统计荣国府和宁国府各自的人口数量MATCH (p:Person)-[:FAMILY_OF]-(f:Family) WHERE f.name IN [荣国府, 宁国府] RETURN f.name as 家族, count(p) as 人口数量 ORDER BY 人口数量 DESC查找关系最复杂的“社交中心”人物度中心性MATCH (p:Person)-[r]-() RETURN p.name, count(r) as connection_count ORDER BY connection_count DESC LIMIT 10这个查询计算每个Person节点连接的关系总数排序后就能找出图谱中连接数最多的人物如贾宝玉、王熙凤他们很可能是故事中的核心枢纽。5. 前端可视化展示让图谱“活”起来Neo4j Browser的内置可视化对于开发和调试已经足够好但如果我们想做一个更友好、更定制化的展示界面就需要借助前端技术了。我的目标是构建一个简单的Web应用用户可以在页面上搜索人物、查看其关系网络并动态交互。5.1 技术选型Neo4j Driver 前端图库整个技术栈分为后端和前端后端我选择了Node.js因为它与JavaScript生态结合紧密。核心是使用官方的Neo4j JavaScript Driver来连接和查询数据库。前端图可视化库有很多选择。Cytoscape.js功能强大且高度可定制Vis.js的图模块上手简单D3.js最灵活但学习曲线陡峭。考虑到快速出原型我选择了Vis.js它的网络模块文档清晰能轻松实现节点的拖拽、缩放和点击事件。5.2 后端API搭建连接数据库的桥梁首先在Node.js项目中安装Neo4j驱动npm install neo4j-driver。然后创建一个简单的Express服务提供查询APIconst express require(express); const neo4j require(neo4j-driver); const app express(); const port 3000; // 创建Neo4j驱动实例连接到本地数据库 const driver neo4j.driver(bolt://localhost:7687, neo4j.auth.basic(neo4j, honglou)); // 替换为你的密码 app.get(/api/person/:name, async (req, res) { const personName req.params.name; const session driver.session(); try { const result await session.run( MATCH (p:Person {name: $name})-[r]-(related) RETURN p, r, related LIMIT 50, { name: personName } ); // 将Neo4j返回的记录转换为前端需要的格式 const nodes []; const edges []; const nodeSet new Set(); // 用于去重 result.records.forEach(record { const p record.get(p); const related record.get(related); const r record.get(r); if (!nodeSet.has(p.identity.toString())) { nodes.push({ id: p.identity, label: p.properties.name, group: p.labels[0] }); nodeSet.add(p.identity.toString()); } if (related !nodeSet.has(related.identity.toString())) { nodes.push({ id: related.identity, label: related.properties.name, group: related.labels[0] }); nodeSet.add(related.identity.toString()); } if (r) { edges.push({ from: r.start, to: r.end, label: r.type }); } }); res.json({ nodes, edges }); } catch (error) { console.error(error); res.status(500).send(查询出错); } finally { await session.close(); } }); app.listen(port, () { console.log(后端服务运行在 http://localhost:${port}); });这个API接收一个人物姓名查询其一度关系并将节点和关系转换成Vis.js能识别的{ nodes: [], edges: [] }格式。5.3 前端界面集成绘制交互式关系图前端页面HTMLJavaScript负责调用API并渲染图形!DOCTYPE html html head title红楼梦知识图谱/title script typetext/javascript srchttps://unpkg.com/vis-network/standalone/umd/vis-network.min.js/script link hrefhttps://unpkg.com/vis-network/styles/vis-network.min.css relstylesheet / style #network { width: 100%; height: 600px; border: 1px solid #ccc; } /style /head body h1红楼梦人物关系图谱/h1 input typetext idsearchInput placeholder输入人物姓名如贾宝玉 button onclicksearchPerson()查询/button div idnetwork/div script let network null; function searchPerson() { const name document.getElementById(searchInput).value; if (!name) return; fetch(http://localhost:3000/api/person/${encodeURIComponent(name)}) .then(response response.json()) .then(data { const container document.getElementById(network); const options { nodes: { shape: dot, font: { size: 16 } }, edges: { arrows: to, font: { size: 12, align: middle } }, interaction: { dragNodes: true, zoomView: true } }; // 创建或更新网络图 if (network) { network.setData({ nodes: data.nodes, edges: data.edges }); } else { network new vis.Network(container, { nodes: data.nodes, edges: data.edges }, options); } // 添加点击节点事件可以进一步查询该节点的关系 network.on(click, function(params) { if (params.nodes.length 0) { const nodeId params.nodes[0]; const node data.nodes.find(n n.id nodeId); if (node) { document.getElementById(searchInput).value node.label; searchPerson(); // 递归查询实现图的漫游 } } }); }) .catch(err console.error(获取数据失败:, err)); } /script /body /html这个页面提供了一个搜索框输入人物姓名后会从后端获取该人物的关系数据并用Vis.js绘制成可交互的网络图。点击图中的任意节点会自动将该节点设为中心并重新查询实现了在知识图谱中的“漫游”效果。5.4 部署与优化考虑本地运行没问题后如果想让别人也能访问就需要部署。你可以将Node.js后端部署到任何云服务器如阿里云ECS、腾讯云CVM将前端静态页面部署到GitHub Pages或Netlify等平台。记得在服务器上安装并运行Neo4j数据库并修改后端代码中的连接地址将localhost改为服务器IP或域名。踩坑提醒在部署到生产环境时安全问题至关重要。绝对不要在前端代码或公开的API中硬编码数据库密码。后端API应设置合理的CORS策略、请求频率限制并对前端传入的查询参数进行严格的校验和清理防止Cypher注入攻击。对于复杂查询最好在后端固化查询语句只接受有限的参数。6. 项目总结与扩展思考通过这个项目我完整地实践了知识图谱构建的全流程从领域分析、数据建模到利用Neo4j进行数据存储与高效查询最后通过一个简单的Web应用进行可视化展示。整个过程下来有几个体会特别深刻第一模型设计优先于一切。初期多花时间思考实体、关系和属性后期会省下大量数据清洗和重构的功夫。比如是否将“情感关系”细分为“爱慕”、“憎恶”、“同情”取决于你分析的重点。第二Cypher语言的学习曲线很平缓。它的声明式语法描述你想要什么而不是如何得到非常贴合图的思维方式。多写、多试是掌握它的最好方法Neo4j Browser的即时反馈很棒。第三可视化是理解复杂关系的利器。当几百个人物和上千条关系以图的形式展开时很多在文本中难以察觉的模式比如某个角色的桥梁作用、家族的派系划分会变得一目了然。这个项目还有很多可以深挖和扩展的方向数据丰富化目前只涵盖了核心人物和关系。可以继续导入更多次要人物、所有事件、诗词、典故甚至每一回的情节概要让图谱更加丰满。属性图分析利用Neo4j Graph Data Science库进行更专业的图算法分析如社区发现自动识别“金陵十二钗”、“贾府管理层”等圈子、中心性分析定量计算谁才是全书真正的核心、路径查找找出两个看似不相关人物之间的最短关联路径。与LLM/RAG结合这是当前的一个热点。可以将知识图谱作为大语言模型的外部知识库。当用户问“贾宝玉和薛宝钗是什么关系”时系统可以先从Neo4j中精准查询到结构化关系SPOUSE_OF再将此信息与《红楼梦》原文片段结合生成更准确、更有依据的答案避免LLM的“幻觉”。这就是“RAG检索增强生成 知识图谱”的典型应用场景。性能优化当数据量达到十万、百万节点时就需要考虑索引策略、查询优化、甚至数据库集群部署了。Neo4j的EXPLAIN和PROFILE命令是分析查询性能的好帮手。对我来说这个项目不仅仅是一个技术demo它更像是一次用现代数据工具重新解读古典文学的尝试。当你用MATCH path shortestPath((a:Person)-[*]-(b:Person)) WHERE a.name刘姥姥 AND b.name贾母 RETURN path这样的语句瞬间找出刘姥姥三进大观园最终见到贾母的那条路径时技术带来的那种穿透文本的洞察力确实令人着迷。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价