2026/10/3 10:16:28

红楼梦知识图谱实战:Neo4j图数据库构建与可视化

红楼梦知识图谱实战:Neo4j图数据库构建与可视化 简介这份资源围绕《红楼梦》知识图谱的构建与展示展开面向希望入门知识图谱、图数据库与Python实战的学生和开发者。它解决的是如何将人物、家族、事件等文本信息转化为结构化图数据并借助Neo4j完成存储、查询与可视化呈现的问题适合作为课程设计、毕业项目或自学练手素材。压缩包共7个文件约1.62MB包含csv三元组数据、Python脚本、Neo4j数据库备份、图谱展示图片及说明文档覆盖从数据组织到图库导入再到结果呈现的完整链路。目前已有160人学习下载。读者可借助三元组文件理解实体与关系的组织方式通过Python脚本完成数据抽取与导入利用数据库备份快速还原图谱环境并结合展示图与说明文档核对节点、边及查询效果从而掌握知识图谱从数据到可视化的基本流程。1. 红楼梦知识图谱展示与 Neo4j从文本到图数据库的落地路径读《红楼梦》时人物关系复杂到让人抓狂——贾、史、王、薛四大家族盘根错节光是有名有姓的角色就超过四百个。如果只用关系型数据库存人物和事件多跳查询会写得又长又慢比如“找出与贾宝玉有间接关系且出现在同一回目中的所有女性角色”SQL 写起来得嵌套好几层。知识图谱用节点和边直接表达“谁认识谁”“谁住在哪”“谁和谁有血缘”天然适合这种场景。这份资源把红楼梦文本整理成结构化数据导入 Neo4j 图数据库再配一套前端展示页面让你能直观看到人物关系网络。适合做课程设计、毕设或者想练手知识图谱构建的 Python 开发者。下面从数据准备、Neo4j 安装配置、图谱构建到前端展示一步步拆开讲。2. 数据准备与 Neo4j 环境搭建从 CSV 到图数据库2.1 红楼梦人物关系数据的组织方式这份资源的数据层通常包含三类 CSV 文件节点文件人物、地点、事件、关系文件亲属、主仆、社交、属性文件人物别号、判词、回目。常见做法是把人物节点存成person.csv字段包括id、name、gender、identity、family关系存成relation.csv字段包括start_id、end_id、type、weight。weight表示关系亲密度比如宝玉和黛玉的“知己”关系权重设为 5宝玉和袭人的“主仆”关系权重设为 3。这样后续在 Neo4j 里可以用weight做路径排序找出“最强关系链”。我一般会先用 Python 的pandas做一轮清洗把重复人物合并比如“宝玉”和“贾宝玉”统一成同一个id。清洗脚本如下import pandas as pd # 读取原始人物列表 df pd.read_csv(raw_person.csv, encodingutf-8) # 统一名称去掉“贾”前缀的别名映射 name_map { 宝玉: 贾宝玉, 黛玉: 林黛玉, 宝钗: 薛宝钗, 凤姐: 王熙凤 } df[name] df[name].replace(name_map) # 生成唯一 id用拼音首字母加序号 df[id] df[name].apply(lambda x: p_ str(abs(hash(x)) % 10000)) # 去重保留第一次出现的记录 df df.drop_duplicates(subset[name], keepfirst) df.to_csv(person_clean.csv, indexFalse, encodingutf-8) print(f清洗后人物数量{len(df)})这段代码做了三件事别名归一、生成稳定id、去重。hash取模是为了让id短一点但注意hash在不同 Python 进程里可能不一致生产环境建议用uuid或自增序号。清洗完的人物表大概 400 行左右关系表大概 800 行数据量不大Neo4j 社区版完全够用。2.2 Neo4j 安装与配置社区版够用但内存要调Neo4j 有桌面版、社区版、企业版。做红楼梦知识图谱社区版足够因为数据量小不需要集群和高级权限。Windows 和 macOS 都能装常见做法是下载压缩包解压然后改配置文件。关键参数在conf/neo4j.conf里# 允许远程访问默认只监听 localhost dbms.default_listen_address0.0.0.0 # Bolt 协议端口Python 驱动默认连 7687 dbms.connector.bolt.listen_address:7687 # HTTP 端口浏览器访问 7474 dbms.connector.http.listen_address:7474 # 堆内存根据机器调整4G 内存机器给 1G 左右 dbms.memory.heap.initial_size1G dbms.memory.heap.max_size1G # 页面缓存数据小可以设 512M dbms.memory.pagecache.size512M改完配置后Linux/macOS 用bin/neo4j start启动Windows 用bin\neo4j.bat start。启动后浏览器打开http://localhost:7474默认用户名和密码都是neo4j第一次登录会强制改密码。如果启动报错“找不到数据库引擎启动句柄”八成是 Java 版本不对——Neo4j 4.x 需要 Java 115.x 需要 Java 17。用java -version确认一下别在这上面翻车。提示社区版不支持多数据库默认只有一个neo4j库。导入数据前先清空旧数据避免节点重复。2.3 用 Cypher 批量导入 CSV 数据Neo4j 导入 CSV 有两种方式LOAD CSV和neo4j-admin import。数据量小用LOAD CSV更灵活可以边导入边建关系。先把 CSV 文件放到 Neo4j 安装目录的import文件夹下然后执行// 导入人物节点 LOAD CSV WITH HEADERS FROM file:///person_clean.csv AS row CREATE (p:Person { id: row.id, name: row.name, gender: row.gender, identity: row.identity, family: row.family }); // 建立索引加速后续查询 CREATE INDEX person_id_index IF NOT EXISTS FOR (p:Person) ON (p.id); // 导入关系 LOAD CSV WITH HEADERS FROM file:///relation_clean.csv AS row MATCH (a:Person {id: row.start_id}) MATCH (b:Person {id: row.end_id}) CREATE (a)-[:RELATION { type: row.type, weight: toInteger(row.weight) }]-(b);LOAD CSV默认从import目录读文件路径写file:///开头。CREATE会重复创建节点如果反复执行会生成重复数据建议先用MATCH检查再决定用CREATE还是MERGE。MERGE会先查再建速度慢一点但安全。关系导入时用了toInteger转换因为 CSV 读进来默认是字符串不转会变成字符串类型的weight后续排序会出错。3. 知识图谱构建实体抽取与关系建模的实操细节3.1 从回目文本中抽取人物共现关系红楼梦一百二十回每回出场人物不同。如果两个人出现在同一回可以认为他们之间有“共现关系”。这种关系虽然粗糙但能快速构建一个基础图谱。用 Python 的jieba分词加人物词典匹配可以统计每回的人物列表import jieba import pandas as pd from collections import defaultdict # 加载人物词典确保人名不被切碎 jieba.load_userdict(person_dict.txt) # 读取回目文本每回一个 txt 文件 co_occur defaultdict(int) for chapter in range(1, 121): with open(fchapters/{chapter}.txt, r, encodingutf-8) as f: text f.read() # 分词并过滤出人物名 words jieba.lcut(text) persons set([w for w in words if w in person_set]) # 统计两两共现 person_list list(persons) for i in range(len(person_list)): for j in range(i1, len(person_list)): pair tuple(sorted([person_list[i], person_list[j]])) co_occur[pair] 1 # 输出共现关系过滤掉共现次数小于 2 的噪声 with open(co_occur.csv, w, encodingutf-8) as f: f.write(start_id,end_id,weight\n) for (a, b), w in co_occur.items(): if w 2: f.write(f{a},{b},{w}\n)jieba.load_userdict是关键不加的话“贾宝玉”会被切成“贾”、“宝玉”、“玉”三个词。person_set是从清洗后的人物表里读出来的集合。共现次数小于 2 的边建议过滤掉否则图谱会太密前端展示时像一团毛线。这个脚本跑完大概生成 2000 多条共现边配合之前的人物关系边图谱就有层次了。3.2 用 Neo4j 查询验证图谱结构数据导入后先用几条 Cypher 验证图谱是否合理。比如查贾宝玉的直接关系MATCH (p:Person {name: 贾宝玉})-[r:RELATION]-(other) RETURN p.name, r.type, r.weight, other.name ORDER BY r.weight DESC LIMIT 20;这条查询会返回宝玉的所有出边关系按权重降序。如果发现“贾宝玉 - 贾宝玉”这种自环说明关系表里有脏数据需要回 CSV 里检查start_id和end_id是否相等。再查一个多跳路径MATCH path (a:Person {name: 贾宝玉})-[*1..3]-(b:Person {name: 林黛玉}) RETURN path LIMIT 5;[*1..3]表示 1 到 3 跳不限方向。这条查询能找出宝玉和黛玉之间的所有间接路径比如“宝玉-袭人-黛玉”或者“宝玉-宝钗-黛玉”。如果路径太多可以加WHERE限制关系类型比如只走RELATION边。注意*1..3在数据量大时会很慢红楼梦数据小无所谓但工业场景下要控制跳数一般不超过 4 跳。3.3 图谱展示的前端选型D3.js 还是 ECharts前端展示知识图谱常见方案有 D3.js、ECharts、Vis.js、Cytoscape.js。D3.js 最灵活但学习曲线陡ECharts 的graph类型开箱即用适合快速出效果。这份资源如果带前端页面大概率用的是 ECharts 或 D3.js。我一般会选 ECharts因为配置简单支持力导向布局、拖拽、缩放还能自定义节点颜色和大小。一个最小示例// 从 Neo4j 后端接口获取节点和边数据 fetch(/api/graph) .then(res res.json()) .then(data { const chart echarts.init(document.getElementById(graph)); const option { series: [{ type: graph, layout: force, data: data.nodes.map(n ({ name: n.name, symbolSize: n.weight * 5, // 权重越大节点越大 category: n.family })), links: data.edges.map(e ({ source: e.start, target: e.end, value: e.weight })), force: { repulsion: 300, // 斥力越大节点越分散 edgeLength: 150 // 边长 }, roam: true, label: { show: true } }] }; chart.setOption(option); });repulsion和edgeLength是两个关键参数。repulsion太小节点会挤在一起太大又散得看不见edgeLength控制边的长度一般 100 到 200 之间。symbolSize用权重映射能让重要人物更显眼。后端接口可以用 Flask 或 FastAPI 写从 Neo4j 查数据转成 JSON 返回。注意跨域问题前端和后端不同端口时要加 CORS 头。4. 避坑与常见问题排查4.1 导入 CSV 时报“Unable to load CSV”现象执行LOAD CSV时提示文件找不到或权限不足。原因Neo4j 只允许从import目录读文件而且路径要用file:///开头。如果 CSV 放在其他目录要么复制到import下要么改conf/neo4j.conf里的dbms.directories.import参数。解决把 CSV 放到import目录确认文件编码是 UTF-8 无 BOMWindows 下用记事本另存为时选 UTF-8。4.2 中文乱码或人物名显示为问号现象Neo4j 浏览器里看到的人物名是乱码。原因CSV 文件编码不是 UTF-8或者 Neo4j 启动时 JVM 编码不对。解决CSV 统一用 UTF-8 保存启动脚本里加-Dfile.encodingUTF-8Linux 下在neo4j.conf里加dbms.jvm.additional-Dfile.encodingUTF-8。另外LOAD CSV时可以指定FIELDTERMINATOR但中文逗号不行必须用英文逗号。4.3 关系导入后查询不到路径现象节点都导入了但MATCH path (a)-[*1..3]-(b)返回空。原因关系导入时MATCH没匹配到节点导致关系没建上。常见情况是start_id和end_id在人物表里不存在或者大小写不一致。解决先跑MATCH (p:Person) RETURN count(p)确认节点数再跑MATCH ()-[r:RELATION]-() RETURN count(r)确认关系数。如果关系数为 0检查 CSV 里的id是否和人物表的id完全一致包括前缀。4.4 Neo4j 启动后内存占用过高现象启动 Neo4j 后机器变卡或者报“OutOfMemoryError”。原因默认堆内存设置偏大或者页面缓存设得太大。解决在neo4j.conf里把dbms.memory.heap.max_size调到 1G 或 2Gdbms.memory.pagecache.size调到 512M。如果数据量确实大再往上加。另外社区版不支持动态调整内存改完必须重启。4.5 前端图谱节点重叠严重现象ECharts 力导向图里节点挤成一团看不清标签。原因repulsion太小或者节点太多。解决把repulsion调到 500 以上edgeLength调到 200 左右。如果节点超过 200 个建议做筛选比如只显示权重前 100 的关系或者按家族分色显示。ECharts 还支持draggable和roam让用户手动拖拽调整。5. 进阶技巧用 APOC 做路径分析和图谱导出5.1 安装 APOC 插件扩展 Cypher 能力Neo4j 社区版自带的功能有限APOCAwesome Procedures on Cypher提供了大量实用过程比如路径展开、节点相似度、图算法。安装方法从 GitHub 下载对应版本的 APOC jar 包放到plugins目录然后在neo4j.conf里加一行dbms.security.procedures.unrestrictedapoc.*重启后跑RETURN apoc.version()验证。APOC 装好后可以用apoc.path.expandConfig做更灵活的路径查询MATCH (start:Person {name: 贾宝玉}) CALL apoc.path.expandConfig(start, { relationshipFilter: RELATION, minLevel: 1, maxLevel: 3, limit: 100 }) YIELD path RETURN path;relationshipFilter可以指定只走某种关系minLevel和maxLevel控制跳数limit防止返回过多结果。这比原生[*1..3]更可控尤其在图谱边很多的时候。5.2 用 Neo4j 图算法找核心人物Neo4j 的 Graph Data Science 库GDS可以做 PageRank、社区发现、中心度计算。红楼梦里谁是最核心的人物用 PageRank 跑一下就知道// 先投影一个子图 CALL gds.graph.project( hongloumeng, Person, RELATION ); // 跑 PageRank CALL gds.pageRank.stream(hongloumeng) YIELD nodeId, score RETURN gds.util.asNode(nodeId).name AS name, score ORDER BY score DESC LIMIT 10;结果大概率是贾宝玉、王熙凤、林黛玉、薛宝钗排前面。score越高说明人物在图中的影响力越大。这个结果可以反哺前端把高分节点显示得更大。GDS 库需要单独安装社区版支持但有限制数据量小没问题。5.3 图谱导出与静态展示如果不想每次开 Neo4j 服务可以把图谱导出成 JSON 或 GraphML前端直接读静态文件。用 APOC 导出CALL apoc.export.json.all(hongloumeng.json, {useTypes: true});导出的 JSON 包含所有节点和关系前端用 D3.js 或 ECharts 加载即可。注意导出的文件在 Neo4j 的import目录下。如果要做成静态网站可以把 JSON 和 HTML 一起打包部署到任意静态服务器。我习惯在导出前先跑一遍apoc.export.json.query只导出需要的子图避免文件太大。从那以后我每次做知识图谱项目都强制走一遍“清洗-导入-验证-导出”的流程尤其是验证环节不跑几条多跳查询心里不踏实。希望帮到你。本文还有配套的精品资源点击获取