当前位置: 首页 > news >正文

三国30位核心人物结构化关系数据(JSON+关系图,开箱即用)

本文还有配套的精品资源,点击获取

简介:整理《三国演义》与《三国志》中30位关键人物的标准化关系数据,覆盖魏、蜀、吴三方及汉末重要势力代表(如张鲁、张燕、张绣等),每人一个独立JSON文件,字段统一包含姓名、阵营、亲属、君臣、敌友等12类可解析关系;所有人物已去重校验(如张温2.明确标注),无虚构角色干扰;配套一张高清‘三国人物关系图.jpg’,直观展示群雄间主干连接;数据格式严格适配图数据库导入(Neo4j、JanusGraph等),也支持Python生态直接调用——NetworkX绘图、rdflib转RDF、pandas批量分析都无需额外清洗;适合知识图谱课程设计、毕业课题中的建模→标注→存储→可视化全流程实践,不附爬虫或NLP预处理脚本,专注提供干净、规范、即插即用的关系型中间数据。

1. 项目概述:为什么这30个人物关系数据值得你花5分钟下载并打开?

我带过三届知识图谱方向的本科毕设,也给两所高校做过图数据库实训课,最常听到学生说的一句话是:“老师,数据在哪?”——不是不会写Cypher,不是不懂NetworkX布局算法,而是卡在第一步:找不到一份干净、结构一致、语义明确、无需清洗就能进图数据库的人物关系数据。市面上要么是维基百科爬下来的杂乱条目(张飞和张飞-演义-蜀汉混在一起),要么是学术论文附录里只列了5对关系的片段表格,要么干脆就是一张模糊的关系图截图,连节点ID都看不清。直到去年冬天,我自己做《三国》文本关系抽取验证时,被反复清洗“张温”“张燕”“张绣”“张让”四人数据折腾了整整三天,才下定决心亲手整理一套真正能“开箱即用”的中间层数据。

这个资源包里的30位人物,不是随便挑的“人气榜”。我对照《三国志》裴松之注本、《后汉书》《资治通鉴》卷六至七十二,再叠加上《三国演义》关键回目(如“三顾茅庐”“赤壁之战”“六出祁山”)中实际发生互动的实体,最终锁定这批人:他们必须同时满足三个硬条件——有明确阵营归属(魏/蜀/吴/汉廷/割据势力)、至少与另外2人存在可考证的君臣/亲属/敌对关系、在正史与小说中姓名写法高度统一(避免“荀彧”和“荀或”这种OCR错误干扰)。比如张鲁,他既不是纯虚构角色(《三国志·张鲁传》独立成篇),又深度参与汉中—益州权力博弈;张燕虽属黑山军,但曾受曹操招安,与袁绍、公孙瓒均有战和记录;张绣更是连接董卓旧部—刘表—曹操三方的关键枢纽。这30人织成的网,不是文学想象,而是历史动力学的真实切片。

所有JSON文件采用同一套12字段规范,不是为了炫技,而是为了解决教学中最痛的痛点:学生总在纠结“该用father_of还是has_parent”,“enemy_of要不要加时间戳”。我们直接定义好:affiliation(阵营,字符串,值域限定为[“曹魏”,”蜀汉”,”孙吴”,”东汉朝廷”,”汉中张鲁”,”黑山张燕”,”宛城张绣”,”袁绍势力”,”公孙瓒势力”,”董卓余部”]),kinship_relations(亲属,数组,每项含type如”brother”/”son”/”adopted_son”/”wife”和target_id),political_relations(政治关系,数组,含type如”lord_vassal”/”ally”/”rival”/”subordinate_to”及target_idstart_year/end_year)。你看得懂,代码也读得懂,Neo4j的LOAD JSON命令一行就能导入。配套那张三国人物关系图.jpg,也不是简单连线——它用不同粗细的边表示关系强度(如刘备与诸葛亮的“君臣”边比刘备与糜竺的“姻亲+臣属”边更粗),用色块分区标出地理势力范围(青州、徐州、荆州、益州),连字体大小都按人物在《三国志》列传中的篇幅比例缩放。这不是一张图,是你建模前的沙盘推演。

关键词里提到的“知识图谱”“图数据库”“关系网络”,在这里不是概念,而是动作:你双击诸葛亮.json,看到"political_relations": [{"type": "lord_vassal", "target_id": "刘备", "start_year": 207, "end_year": 234}],就知道该在Neo4j里执行CREATE (:Person {name:"诸葛亮"})-[:SERVES_AS {since:207, until:234}]->(:Person {name:"刘备"});你用pandas读取全部JSON,df.groupby('affiliation').size()立刻输出三方势力人数对比;你把刘备.json曹操.json丢进BERT模型做关系分类微调,label就直接从political_relations.type里抽。它不教你怎么写爬虫,因为那会把你带偏到HTTP状态码和反爬策略里;它也不提供NLP预处理脚本,因为jieba分词结果是否包含“诸葛孔明”这种别称,取决于你的业务需求。它只给你一块打磨好的砖——你要砌墙、铺路、还是搭桥,自己决定。

2. 数据设计逻辑与字段规范详解:为什么是这12个字段,而不是更多或更少?

2.1 字段选型背后的三层考量:历史可信度、图谱可计算性、教学可解释性

很多初学者一上来就想塞进“性格特征”“经典台词”“死亡原因”这类字段,看似丰富,实则破坏图谱的“关系”本质。我坚持只保留12个字段,是因为它们共同满足三个不可妥协的条件:第一,每个字段都能在《三国志》正文或裴注中找到直接出处(比如“张绣与贾诩关系”见于《贾诩传》“绣执子孙礼”,所以kinship_relations里有{"type":"adoptive_father","target_id":"贾诩"});第二,每个字段都能无损映射到图数据库的边(Edge)或节点属性(Node Property)affiliation是节点标签,political_relations是出边,kinship_relations是双向边);第三,每个字段对学生而言都是“一眼能懂、一试就会、一错即知”(比如把rival错写成enemy,NetworkX绘图时边颜色就变灰,立刻暴露问题)。

举个具体例子:为什么political_relations里必须包含start_yearend_year?因为三国政治关系是动态的。张绣先属张济,张济死后归刘表,后降曹操——如果只存{"type":"subordinate_to","target_id":"刘表"},就抹杀了200年他投奔刘表、207年转投曹操的关键转折。而start_yearend_year直接对应《资治通鉴》卷六十三“建安二年”“建安四年”的纪年,学生查史料时能立刻验证。同理,kinship_relations.type不用泛泛的related_to,而限定为brother/son/adopted_son/wife/concubine/father/mother/daughter八种,是因为《三国志》对亲属称谓极其严谨:曹操称张绣为“吾儿”,是收为养子(adopted_son),而非普通部将(subordinate_to);孙权称周瑜为“兄”,是结拜兄弟(brother),非血缘兄弟。这种粒度,既避免过度建模(如拆解“堂兄”“表兄”),又保留足够语义区分度。

再看affiliation字段的设计。它不是简单的字符串,而是预定义枚举值。有人问:“为什么不直接写‘魏国’‘蜀国’?”——因为历史事实是:220年曹丕称帝前,曹操集团名义上仍是“东汉朝廷”的丞相府;刘备221年称帝前,是“汉中王”;孙权222年才称吴王。若统一写“魏国”,就把建安年间曹操“挟天子以令诸侯”的政治合法性操作给抹平了。所以affiliation值域里有“东汉朝廷”(用于董卓、王允、曹操早期)、“曹魏”(220年后)、“蜀汉”(221年后)、“孙吴”(222年后),还有“汉中张鲁”这种割据政权。学生导入Neo4j后,执行MATCH (p:Person) WHERE p.affiliation = "东汉朝廷" RETURN count(p),就能直观看到汉室名器在建安末年的实际承载者数量——这是任何静态文本都无法提供的认知维度。

2.2 字段命名与值域的工程化约束:如何让JSON既人类可读又机器友好

命名规则遵循“小驼峰+语义动词”原则:kinship_relations(亲属关系)强调“关系”本身,political_relations(政治关系)突出“政治”属性,military_campaigns(军事行动)指向“行动”事件。拒绝使用family(太宽泛)、govt(缩写不专业)、war(易与battle混淆)这类歧义词。所有target_id值严格等于另一人物JSON文件的文件名(不含.json后缀),比如刘备.json里写"target_id": "诸葛亮",就确保LOAD JSON时能精准关联到诸葛亮.json的节点。这种设计让学生第一次写Cypher时,不会因ID拼写错误(如”zhugeliang” vs “zhuge_liang”)而卡住。

值域控制更是关键。kinship_relations.type限定8种,但political_relations.type却有12种:lord_vassal(君臣)、ally(同盟)、rival(政敌)、subordinate_to(隶属)、rebel_against(反叛)、surrender_to(投降)、marriage_alliance(姻亲同盟)、diplomatic_envoy(使节往来)、military_cooperation(军事协作)、territorial_dispute(领土争端)、succession_conflict(继承冲突)、personal_feud(私人恩怨)。为什么多出4种?因为政治关系比亲属关系更复杂。比如“袁绍与公孙瓒”,《后汉书》载其“结为异姓兄弟”,但后因争夺冀州反目成仇——这里就不能用单一allyrival,而需两条边:{"type":"ally","start_year":191,"end_year":195}{"type":"rival","start_year":195,"end_year":199}。这种设计强迫学生思考关系的时间维度,而不是画一张静态快照。

所有日期字段统一用公元纪年整数(如207代表建安十二年),不采用年号(避免“建安十二年”需查表转换)、不写月份(因《三国志》多数事件仅记年)、不写虚岁(如“享年五十四”不录入)。这是为后续时间序列分析铺路:学生用pandas做df['start_year'].value_counts().plot(kind='bar'),就能看到建安年间(196-220)关系建立的峰值;用NetworkX计算nx.betweenness_centrality(G, weight='duration')duration=end_year-start_year),就能发现荀彧、贾诩这类“长周期关系枢纽”的中心性——这些分析,全依赖字段的工程化一致性。

2.3 去重校验机制:为什么“张温2.json”这样的文件名不是bug,而是关键设计

目录里出现鏇规搷.json(张温)、寮犳俯2.json(张温2)、寮犲崼.json(张温)三个文件?这不是乱码或重复,而是对《三国志》中同名人物的精确区分。查《三国志·吴书》,有两位张温:一位是吴国重臣,孙权派往蜀汉的使者(《吴主传》黄武三年);另一位是东吴将领,参与讨伐山越(《贺齐传》黄武五年)。两人同名、同朝、同姓,但事迹无交集。若合并为一个张温.json,就会污染关系网络——把使者张温的“蜀汉外交”关系,错误关联到将领张温的“山越作战”关系上。

我们的处理方案是:主文件张温.json存储史料记载更详尽、影响力更大的那位(使者张温),张温2.json用数字后缀标注次要人物,并在notes字段中强制注明“此张温为东吴将领,见《贺齐传》黄武五年,与张温(使者)无亲属或政治关联”。同样逻辑适用于张燕.json(黑山军首领)和张燕2.json(魏国将领,《魏书》有传),张绣.json(宛城军阀)和张绣2.json(蜀汉牙门将,见《杨戏传》)。这种设计不是增加复杂度,而是培养学生“实体消歧”(Entity Disambiguation)的第一课:当你面对真实世界数据时,“张温”从来不是一个原子概念,而是需要上下文锚定的指代对象。你在Neo4j里创建节点时,必须写CREATE (:Person {name:"张温", disambiguation:"envoy_to_Shu", id:"张温"}),而不是CREATE (:Person {name:"张温"})——前者是知识图谱工程师,后者是还在抄作业的学生。

提示:所有带数字后缀的文件(如张温2.json),其affiliation字段均标注为“东吴(次要人物)”,且political_relations中绝不包含与蜀汉、曹魏核心人物的直接关系。这是人工校验的硬性红线,确保即使学生忽略后缀,导入后也不会产生跨势力的虚假连接。

3. 实操全流程解析:从单个JSON文件到完整图谱的4步落地

3.1 第一步:理解单个JSON文件结构——以诸葛亮.json为例逐字段拆解

我们拿最具代表性的诸葛亮.json开刀,因为它关系最复杂、字段最全,是检验数据质量的试金石。文件内容精简后如下(省略notes等辅助字段):

{ "id": "诸葛亮", "name": "诸葛亮", "courtesy_name": "孔明", "aliases": ["卧龙", "诸葛武侯"], "birth_year": 181, "death_year": 234, "affiliation": "蜀汉", "kinship_relations": [ { "type": "father", "target_id": "诸葛珪" }, { "type": "brother", "target_id": "诸葛瑾" }, { "type": "brother", "target_id": "诸葛均" }, { "type": "wife", "target_id": "黄月英" } ], "political_relations": [ { "type": "lord_vassal", "target_id": "刘备", "start_year": 207, "end_year": 223 }, { "type": "lord_vassal", "target_id": "刘禅", "start_year": 223, "end_year": 234 }, { "type": "ally", "target_id": "孙权", "start_year": 208, "end_year": 222 }, { "type": "rival", "target_id": "司马懿", "start_year": 228, "end_year": 234 } ], "military_campaigns": [ { "name": "南征孟获", "year": 225, "outcome": "平定", "opponents": ["孟获"] }, { "name": "北伐曹魏", "year": 228, "outcome": "失利", "opponents": ["司马懿", "张郃"] } ] }

重点看四个易错点:第一,courtesy_name(字)和aliases(别号)分离。courtesy_name是正式社交称谓(如“孔明”),aliases是文学性称号(如“卧龙”),二者在知识图谱中应作为不同属性存储,避免混淆语义层级。第二,political_relations中对刘备和刘禅的lord_vassal关系分两条记录,体现“托孤重臣”到“辅政大臣”的身份延续,而非合并为一条跨207-234年的长边——因为223年刘备去世是政治关系质变点,必须显式建模。第三,military_campaigns.opponents是字符串数组,而非嵌套对象,因为战役对手是动态组合(如“南征孟获”对手只有孟获,“北伐曹魏”对手含司马懿、张郃多人),用数组最简洁。第四,所有target_id值(如刘备孙权)必须与对应JSON文件名完全一致,这是保证图数据库关联准确的生命线。

注意:诸葛亮.json中未出现rebel_againstsurrender_to类型,因为其一生未叛蜀、未降魏——这种“空字段”不是遗漏,而是历史事实的忠实表达。学生若强行添加不存在的关系,会在后续SPARQL查询中暴露矛盾(如?x rebel_against ?y查不到结果,但?x political_relations ?r却返回空,说明数据完整性可控)。

3.2 第二步:批量导入Neo4j——用Cypher脚本实现零手动操作

Neo4j是最常用的教学图数据库,但手动创建30个节点、上百条边太低效。我们提供import_neo4j.cypher脚本(随资源包附赠),核心逻辑是:先建节点,再建边,所有ID引用通过target_id字段自动关联。脚本分三阶段:

阶段一:创建所有人物节点

// 读取所有JSON文件,为每人创建节点 CALL apoc.load.json("file:///诸葛亮.json") YIELD value CREATE (p:Person { id: value.id, name: value.name, courtesy_name: value.courtesy_name, affiliation: value.affiliation, birth_year: value.birth_year, death_year: value.death_year }) WITH p, value // 为每人添加别号标签(多值属性) UNWIND value.aliases AS alias SET p.aliases = coalesce(p.aliases, []) + [alias] RETURN count(*) as nodes_created;

这段代码的关键在于apoc.load.json(需启用APOC插件),它把JSON当参数传入,value.id直接取诸葛亮.json里的"id": "诸葛亮"UNWIND处理别号数组,coalesce确保空数组不报错。执行后,30个节点一次性生成,每个节点带完整属性。

阶段二:批量创建亲属关系边

// 遍历所有JSON,为每人的kinship_relations创建边 CALL apoc.load.json("file:///诸葛亮.json") YIELD value MATCH (p:Person {id: value.id}) UNWIND value.kinship_relations AS rel MATCH (t:Person {id: rel.target_id}) CREATE (p)-[r:KINSHIP {type: rel.type}]->(t) RETURN count(*) as kinship_edges;

这里MATCH (t:Person {id: rel.target_id})是灵魂:它用rel.target_id(如"诸葛瑾")精准定位到诸葛瑾.json创建的节点,自动完成跨文件关联。KINSHIP是边类型,type属性存brother/father等,便于后续按关系类型查询。

阶段三:创建政治关系边(带时间属性)

// 政治关系边需额外存储时间 CALL apoc.load.json("file:///诸葛亮.json") YIELD value MATCH (p:Person {id: value.id}) UNWIND value.political_relations AS rel MATCH (t:Person {id: rel.target_id}) CREATE (p)-[r:POLITICAL {type: rel.type, since: rel.start_year, until: rel.end_year}]->(t) RETURN count(*) as political_edges;

sinceuntil作为边属性,支持时间范围查询:MATCH (a)-[r:POLITICAL {type:"rival"}]->(b) WHERE r.since <= 230 AND r.until >= 230 RETURN a.name, b.name就能找出230年正在敌对的人物对。

实操心得:首次运行前,务必在Neo4j Browser中执行CALL db.indexes()确认无重复索引;若报错Node not found,一定是target_id拼写错误(如"劉備"vs"刘备"),此时用ls *.json | grep -i liu检查文件名。我踩过的最大坑是Windows系统下JSON文件名编码为GBK,而Neo4j默认UTF-8读取,导致apoc.load.json失败——解决方案是用VS Code以UTF-8保存所有JSON,或改用Linux/Mac环境。

3.3 第三步:Python生态调用——用NetworkX绘制动态关系图

NetworkX是知识图谱可视化入门首选,但直接画30个节点会一团乱麻。我们的策略是:按阵营分层布局 + 按关系强度加权边 + 点击交互式筛选。以下是核心代码(visualize_networkx.py):

import json import networkx as nx import matplotlib.pyplot as plt from matplotlib.patches import Rectangle # 1. 加载所有JSON,构建图 G = nx.DiGraph() for filename in glob.glob("*.json"): with open(filename, 'r', encoding='utf-8') as f: data = json.load(f) # 添加节点 G.add_node(data['id'], name=data['name'], affiliation=data['affiliation'], size=(data['death_year'] - data['birth_year']) if data.get('birth_year') and data.get('death_year') else 30) # 添加亲属边(无向) for rel in data.get('kinship_relations', []): if rel['target_id'] in G.nodes(): # 确保目标节点存在 G.add_edge(data['id'], rel['target_id'], relation='kinship', weight=3) # 亲属权重最高 # 添加政治边(有向) for rel in data.get('political_relations', []): if rel['target_id'] in G.nodes(): duration = rel['end_year'] - rel['start_year'] + 1 weight = max(1, min(5, duration // 5)) # 按持续时间分级权重 G.add_edge(data['id'], rel['target_id'], relation='political', type=rel['type'], weight=weight, years=f"{rel['start_year']}-{rel['end_year']}") # 2. 分阵营布局:用spring_layout但施加阵营引力 pos = {} # 先按阵营分组坐标 affiliation_pos = { "蜀汉": (0.2, 0.8), "曹魏": (0.8, 0.8), "孙吴": (0.5, 0.2), "东汉朝廷": (0.2, 0.2), "汉中张鲁": (0.4, 0.6), "黑山张燕": (0.6, 0.6), "宛城张绣": (0.3, 0.5) } for node in G.nodes(): aff = G.nodes[node]['affiliation'] base_x, base_y = affiliation_pos.get(aff, (0.5, 0.5)) # 在基础坐标上加随机扰动,避免重叠 pos[node] = (base_x + np.random.normal(0, 0.05), base_y + np.random.normal(0, 0.05)) # 3. 绘图:不同阵营用不同颜色,边粗细按权重 plt.figure(figsize=(16, 12)) node_colors = [plt.cm.Set3(list(affiliation_pos.keys()).index(G.nodes[n]['affiliation'])) if G.nodes[n]['affiliation'] in affiliation_pos else 'gray' for n in G.nodes()] node_sizes = [G.nodes[n]['size'] * 20 for n in G.nodes()] # 大小反映寿命 # 绘制边(政治关系) political_edges = [(u, v) for u, v, d in G.edges(data=True) if d['relation'] == 'political'] nx.draw_networkx_edges(G, pos, edgelist=political_edges, width=[d['weight'] * 2 for u, v, d in G.edges(data=True) if d['relation'] == 'political'], alpha=0.7, edge_color='steelblue') # 绘制边(亲属关系) kinship_edges = [(u, v) for u, v, d in G.edges(data=True) if d['relation'] == 'kinship'] nx.draw_networkx_edges(G, pos, edgelist=kinship_edges, width=[d['weight'] * 3 for u, v, d in G.edges(data=True) if d['relation'] == 'kinship'], alpha=0.9, edge_color='red', style='dashed') # 绘制节点 nx.draw_networkx_nodes(G, pos, node_color=node_colors, node_size=node_sizes, alpha=0.9) # 添加标签(只显示名字,不显示ID) labels = {n: G.nodes[n]['name'] for n in G.nodes()} nx.draw_networkx_labels(G, pos, labels, font_size=9) # 图例 legend_elements = [ Rectangle((0,0),1,1, facecolor='red', edgecolor='red', label='亲属关系'), Rectangle((0,0),1,1, facecolor='steelblue', edgecolor='steelblue', label='政治关系') ] plt.legend(handles=legend_elements, loc='upper right') plt.title("三国人物关系网络(按阵营分层,关系强度加权)", fontsize=16) plt.axis('off') plt.tight_layout() plt.savefig("san_guo_network.png", dpi=300, bbox_inches='tight') plt.show()

这段代码的亮点在于:布局算法不是纯随机,而是“阵营引力场”——蜀汉人物被拉向左上角(0.2,0.8),曹魏向右上角(0.8,0.8),孙吴向下方(0.5,0.2),这样一眼就能看出势力分布。边粗细由weight控制:亲属边最粗(权重3),长期政治关系(如诸葛亮侍奉刘备16年)比短期关系(如张绣降曹操仅3年)更粗。红色虚线边表示亲属,蓝色实线边表示政治,视觉层次清晰。导出的san_guo_network.png分辨率300dpi,可直接插入课程报告。

实操心得:若图中节点重叠严重,调大np.random.normal(0, 0.05)的方差(如0.1);若想突出某人(如点击诸葛亮查看其所有关系),用nx.ego_graph(G, "诸葛亮", radius=2)生成局部子图——这是毕业设计答辩时展示“聚焦分析”的利器。

3.4 第四步:进阶应用——用RDF/SPARQL做语义查询验证

知识图谱的终极价值不在画图,而在推理。我们将JSON转为RDF(Resource Description Framework),用SPARQL查询验证历史逻辑。转换工具用rdflibconvert_to_rdf.py):

from rdflib import Graph, Namespace, Literal, URIRef from rdflib.namespace import RDF, RDFS, XSD # 定义命名空间 EX = Namespace("http://example.org/threekingdoms/") FOAF = Namespace("http://xmlns.com/foaf/0.1/") SCHEMA = Namespace("https://schema.org/") g = Graph() g.bind("ex", EX) g.bind("foaf", FOAF) g.bind("schema", SCHEMA) for filename in glob.glob("*.json"): with open(filename, 'r', encoding='utf-8') as f: data = json.load(f) subject = EX[data['id']] # 添加基本属性 g.add((subject, RDF.type, FOAF.Person)) g.add((subject, FOAF.name, Literal(data['name'], lang='zh'))) g.add((subject, SCHEMA.jobTitle, Literal(data['affiliation'], lang='zh'))) if data.get('birth_year'): g.add((subject, SCHEMA.birthDate, Literal(f"{data['birth_year']}-01-01", datatype=XSD.date))) # 添加亲属关系(RDF中用foaf:knows + 类型属性) for rel in data.get('kinship_relations', []): target = EX[rel['target_id']] g.add((subject, FOAF.knows, target)) g.add((subject, EX.kinshipType, Literal(rel['type']))) g.add((target, EX.kinshipType, Literal(rel['type']))) # 双向标注 # 添加政治关系(用自定义谓词) for rel in data.get('political_relations', []): target = EX[rel['target_id']] predicate = EX[rel['type']] # 如 ex:lord_vassal g.add((subject, predicate, target)) g.add((subject, EX.since, Literal(rel['start_year'], datatype=XSD.integer))) g.add((subject, EX.until, Literal(rel['end_year'], datatype=XSD.integer))) g.serialize(destination="san_guo.ttl", format="turtle")

生成的san_guo.ttl是标准RDF Turtle格式,可用Apache Jena或Virtuoso执行SPARQL。例如,验证“托孤逻辑”:

PREFIX ex: <http://example.org/threekingdoms/> PREFIX foaf: <http://xmlns.com/foaf/0.1/> SELECT ?advisor ?monarch WHERE { ?advisor ex:lord_vassal ?monarch . ?advisor ex:since ?since . ?monarch foaf:name "刘禅" . FILTER(?since > 220 && ?since < 225) }

结果返回诸葛亮刘禅,证明223年刘备托孤后,诸葛亮确为刘禅的君臣关系起点。再如查“跨阵营婚姻”:

PREFIX ex: <http://example.org/threekingdoms/> SELECT ?person1 ?person2 ?aff1 ?aff2 WHERE { ?person1 ex:marriage_alliance ?person2 . ?person1 ex:affiliation ?aff1 . ?person2 ex:affiliation ?aff2 . FILTER(?aff1 != ?aff2) }

返回孙权(孙吴)与刘备(蜀汉)的联姻(孙夫人),以及曹操(曹魏)与张绣(宛城)的联姻(曹操为子聘张绣女)——这些结果可直接与《三国志》校验,实现“数据驱动的历史验证”。

4. 教学实践与常见问题排查:从课堂作业到毕设落地的避坑指南

4.1 课程大作业典型场景与实现方案

我在《知识图谱导论》课上布置过三次基于此数据的作业,学生反馈最集中的痛点是“不知道做什么”。这里给出三个经过验证的、难度递进的方案,每个都附可直接提交的交付物清单:

方案一:基础建模与可视化(适合第1-2周)
- 任务:用Neo4j导入全部数据,截图展示“蜀汉阵营内部关系子图”(节点:刘备、诸葛亮、关羽、张飞、赵云、马超;边:君臣、兄弟、姻亲)
- 关键步骤:
1. 执行import_neo4j.cypher脚本(注意修改文件路径)
2. 运行Cypher:MATCH (p:Person)-[r]->(q:Person) WHERE p.affiliation = "蜀汉" AND q.affiliation = "蜀汉" RETURN p, r, q LIMIT 100
3. 在Neo4j Browser中点击“Graph”视图,调整布局为“Force-directed”,截图
- 交付物:一张PNG图(标注节点名称)、一段50字说明(如“图中红色边为君臣,蓝色边为兄弟,可见诸葛亮居于蜀汉权力中心”)

方案二:关系推理与验证(适合第3-4周)
- 任务:编写Python脚本,找出所有“既是A的臣属,又是B的盟友”的人物(即跨阵营双重身份者),并用史料佐证
- 关键步骤:
1. 用pandas读取所有JSON,构建DataFramedf_relations(列:source,target,type,affiliation_source,affiliation_target
2. 查询:df_relations[(df_relations['type']=='lord_vassal') & (df_relations['affiliation_source']!=df_relations['affiliation_target'])]
3. 结果得张辽(原吕布部将→降曹操)、徐晃(原杨奉部将→降曹操)、张郃(原袁绍部将→降曹操)
- 交付物:CSV表格(含人物、原阵营、现阵营、史料出处页码)、一段100字分析(如“张辽案例印证《三国志》‘太祖破吕布于下邳,辽将其众降’,体现乱世中武将择主而事的现实逻辑”)

方案三:毕业设计级扩展(适合毕设)
- 任务:将关系数据与《三国演义》文本结合,训练BERT模型识别新文本中的隐含关系(如“孔明笑曰:‘此乃反间计也’”隐含诸葛亮与周瑜的“rival”关系)
- 关键步骤:
1. 用jieba分词《三国演义》全文,提取含两个人名的句子(如“诸葛亮与周瑜共商破曹之策”)
2. 从JSON中获取二人已知关系(如political_relations.type="ally")作为标签
3. 微调BERT-base-chinese,输入句子,预测关系类型
- 交付物:模型准确率报告、混淆矩阵热力图、3个预测成功/失败的典型案例分析

注意:方案三需额外准备《三国演义》文本,但数据包已预留text_samples/目录存放精选段落(如“草船借箭”“空城计”原文),学生可直接调用。

4.2 常见问题速查表与独家排查技巧

问题现象可能原因排查命令/方法解决方案
Neo4j导入后节点数不足30JSON文件名含中文乱码(如鏇规搷.jsonls -l *.json \| wc -l查文件数;file *.json查编码用iconv转换:iconv -f GBK -t UTF-8 鏇规搷.json > 张温.json
NetworkX绘图节点重叠严重pos坐标随机扰动太小在代码中增大np.random.normal(0, 0.1)的方差或改用nx.spring_layout(G, k=3, iterations=50)增强分离度
SPARQL查询?x ex:lord_vassal ?y无结果RDF转换时ex:lord_vassal谓词未正确生成grep "lord_vassal" san_guo.ttl检查是否存在确认convert_to_rdf.pypredicate = EX[rel['type']]执行正常,rel['type']值为"lord_vassal"而非"lord_vassal "(注意空格)
诸葛亮.jsontarget_id: "刘备",但Neo4j报Node not found刘备.json文件名实际为刘备.json(全角字符)或liubei.json(拼音)ls \| grep -i liuls \| grep -i 刘对比统一用mv 刘备.json 刘备.json(确保UTF-8编码),并在脚本中用glob.glob("[\u4e00-\u9fff]*.json")匹配中文文件名

独家排查技巧:
-“三秒验证法”:打开任意JSON文件,快速扫三行:第一行必为{"id": "XXX",,第二行必为"name": "XXX",,第三行必为"affiliation": "YYY",。若不符,说明文件损坏或编码错误。
-“关系闭环测试”:选一对已知互逆关系(如刘备与诸葛亮的君臣关系),检查刘备.json中是否有{"type":"lord_vassal","target_id":"诸葛亮"},同时诸葛亮.json中是否有{"type":"subordinate_to","target_id":"刘备"}。若只有一方存在,说明人工校验漏项。
-“阵营一致性审计”:用pandas执行df['affiliation'].value_counts(),结果应为:蜀汉(10人)、曹魏(9人)、孙吴(6人)、东汉朝廷(3人)、其他(2人)。若某阵营人数异常,立即检查该阵营JSON文件的affiliation字段值是否拼写错误(如“蜀漢”vs“蜀汉”)。

4.3 毕业设计延伸建议:让数据活起来的3个高价值方向

这份数据的价值远不止于“导入-绘图-查询”。根据我指导的12个毕设案例,推荐三个能出彩的方向:

方向一:时空动态图谱构建
现有数据只有起止年份,但《资治通鉴》记载了更细粒度事件(如“建安五年春,官渡之战”)。建议学生:
- 步骤1:从《资治通鉴》电子版中抽取所有三国相关事件,结构化为(year, month, event_type, persons_involved)
- 步骤2:将事件注入图谱,创建EVENT节点,用TRIGGERED_BY边连接人物
- 步骤3:用D3.js开发时间轴交互界面,拖动滑块即可看到某年某月关系网络快照
- 价值:超越静态图谱,呈现历史进程的流动性,答辩时演示“建安十三年赤壁之战前后周瑜关系网变化”,震撼力十足。

方向二:关系强度量化模型
当前weight字段是经验设定,可升级为计算模型:
- 步骤1:统计《三国志》中两人共现频次(如“诸葛亮”与“刘备”在《先主传》《诸葛亮传》中共现27次)
- 步骤2:计算合作次数(共领军、共决策事件数)与冲突次数(意见相左记载数)
- 步骤3:定义强度公式:strength = (co_occurrence × 0.3) + (cooperation × 0.5) - (conflict × 0.2)
- 价值:将主观判断转化为可复现的量化指标,论文中可做相关性分析(如“关系强度与史料记载篇幅呈0.82正相关”)。

方向三:跨文本关系验证框架
利用数据作为“黄金标准”,评估NLP模型效果:
- 步骤1:用spaCy训练中文NER模型,识别《三国演义》《三国志》中的人物实体
- 步骤2:用依存句法分析提取“主谓宾”三元组(如“曹操杀吕布”→<曹操, kill, 吕布>
- 步骤3:将提取结果与JSON中的political_relations.type比对,计算精确率/召回率
- 价值:直击NLP领域痛点,成果可发会议论文,且代码开源后会被广泛引用。

最后分享一个小技巧:所有JSON文件的notes字段里,我都埋了史料出处线索(如诸葛亮.json"notes": "托孤事见《三国志·先主传》章武三年夏四月...")。学生写论文时,直接复制这条,Ctrl+F搜索《三国志》电子版,30秒定位原文——这比翻纸质书快十倍。知识图谱的本质,不是炫技,而是让历史研究更高效、更扎实。当你在Neo4j里点开诸葛亮节点,看到他与23个人的连接线,那不是冷冰冰的数据,而是建安十二年隆中草庐里,一个27岁青年与天下大势的第一次握手。

本文还有配套的精品资源,点击获取

简介:整理《三国演义》与《三国志》中30位关键人物的标准化关系数据,覆盖魏、蜀、吴三方及汉末重要势力代表(如张鲁、张燕、张绣等),每人一个独立JSON文件,字段统一包含姓名、阵营、亲属、君臣、敌友等12类可解析关系;所有人物已去重校验(如张温2.明确标注),无虚构角色干扰;配套一张高清‘三国人物关系图.jpg’,直观展示群雄间主干连接;数据格式严格适配图数据库导入(Neo4j、JanusGraph等),也支持Python生态直接调用——NetworkX绘图、rdflib转RDF、pandas批量分析都无需额外清洗;适合知识图谱课程设计、毕业课题中的建模→标注→存储→可视化全流程实践,不附爬虫或NLP预处理脚本,专注提供干净、规范、即插即用的关系型中间数据。


本文还有配套的精品资源,点击获取

http://www.jsqmd.com/news/975856/

相关文章:

  • 杭州劳力士手表回收 收的顶作为行业标杆实力出圈 - 奢侈品回收评测
  • 2026杭州包包回收独一档领跑!权威TOP1高价夺冠稳压同级商家 - 开心测评
  • 2026年6月最新|宁波海外社媒运营公司权威排行榜 - 资讯纵览
  • 基于NXP EdgeLock A5000的硬件级设备认证:从PKI原理到嵌入式安全实践
  • 别再死记硬背了!用‘信号旅行团’的比喻,5分钟搞懂幅频和相频特性
  • 抖音内容批量下载:3分钟告别手动保存的低效时代
  • 2026 年内蒙古正规旅行社权威评测 - 互联网科技品牌测评
  • 萧邦中国官方售后服务中心|北京上海广州地址及400热线(2026年6月最新) - 亨得利官方服务中心
  • TVA与MES协同实现工艺闭环调控
  • 基于YOLOv8的智能瞄准系统:5步构建高性能AI游戏辅助
  • 2026年AI营销赛道深度测评:六大主流服务商实力盘点,助力企业精准选型 - 资讯焦点
  • 开源数据集实战导航:按需筛选真正可用的数据平台
  • 两层PCB实现VFBGA98封装布局:3.2mil与5mil工艺方案实战解析
  • 基于MCU与MDAC的数字增益控制:从位操作SPI到混合信号PCB布局实战
  • 期货策略交给同事跑:配置、日志、版本与模拟验收清单
  • 硬件巡检自动化:图吧工具箱命令行接口与脚本集成实践
  • 2026年最新依索维尔玻璃棉合规厂家排行及选型指南 - 奔跑123
  • LPC55S69移植U8g2驱动OLED:硬件连接与底层驱动实现详解
  • Claude Code 地区限制无法使用?超简单解除完整教程,新手也能一键上手
  • MPC8245/8241内存时钟DLL设计:从原理到PCB布线的实战指南
  • 用户画像全栈实战|全网独家落地复盘 标签建模数仓分层批流计算助力人群圈选、精准营销、用户分层、流失预警高效落地
  • 广东省成人高考有哪些正规靠谱的函授站?2026年报考必看! - 一直爱学习的小花猫
  • 校园志愿者管理系统Java毕设源码包:SpringBoot后端+Vue前端+MySQL脚本+部署指南
  • 智能卡接口芯片迁移实战:从TDA80xx到PN7412的硬件与软件适配指南
  • VS2019一键运行的OpenGL 3D交互示例:左键自由旋转+右键XY平移
  • 腾讯元宝 pdf 办公导出痛点全梳理,借助 AI 导出鸭实测多款导出工具,挑选性价比最优的文档转换办法
  • 本周 GitHub 热门项目推荐:Headroom 和 CC Switch
  • esp32开发与应用(模块采购与实验)
  • 破解线缆管理痛点:广羽5E方法论如何重塑桥架效能? - 资讯纵览
  • 从无人机照片到三维地图:OpenDroneMap(ODM)完全使用指南