今天我将深入解析一段使用Neo4j图数据库进行关系查询的Python代码。这段代码实现了人物关系查询、知识图谱问答等功能,是图数据库应用的典型示例。我会用最详细的方式讲解每一部分,确保完全理解!
这段代码主要包含四个核心功能:
Zquery()
- 查询指定人物的所有关系
Zget_json_data()
- 将查询结果转换为可视化所需的JSON格式
Zget_KGQA_answer()
- 实现知识图谱问答功能
Zget_answer_profile()
- 获取人物简介信息
让我们逐行深入解析!
from neo_db.Zconfig import graph, CA_LIST, similar_words
from spider.Zshow_profile import get_profile
import codecs
import os
import json
import base64
neo_db.Zconfig:自定义模块,包含:
graph
:Neo4j数据库连接对象
CA_LIST
:人物类别字典(如{'叶圣陶': '作家'})
similar_words
:同义词映射字典(如{'朋友': 'friend'})
spider.Zshow_profile:自定义爬虫模块,get_profile()
函数用于获取人物简介
标准库:
codecs
:文件编码处理
os
:操作系统接口
json
:JSON数据处理
base64
:Base64编码(虽然未使用,但可能用于后续扩展)
def Zquery(name):
# 构建Cypher查询语句
query = """
match(p)-[r]->(n:Person{Name:'%s'})
return p.Name, r.relation, n.Name, p.cate, n.cate
Union all
match(p:Person {Name:'%s'})-[r]->(n)
return p.Name, r.relation, n.Name, p.cate, n.cate
""" % (name, name)
# 执行查询并转换为列表
data = list(graph.run(query))
# 处理并返回JSON格式数据
return Zget_json_data(data)
功能说明:
查询与指定人物name
相关的所有关系
包含两部分查询(使用UNION ALL
合并):
查找指向该人物的所有关系(谁与TA有关系)
查找该人物指向其他人的所有关系(TA与谁有关系)
Cypher查询解析:
match(p)-[r]->(n:Person{Name:'叶圣陶'})
:找到所有指向"叶圣陶"的关系
match(p:Person{Name:'叶圣陶'})-[r]->(n)
:找到"叶圣陶"指向他人的关系
return
返回:起点名称、关系类型、终点名称、起点类别、终点类别
def Zget_json_data(data):
# 初始化JSON结构
json_data = {'data': [], "links": []}
d = [] # 临时存储节点信息
# 第一步:收集所有唯一节点
for record in data:
# 格式:节点名称_类别
d.append(record['p.Name'] + "_" + record['p.cate'])
d.append(record['n.Name'] + "_" + record['n.cate'])
# 去重并排序
d = list(set(d))
# 第二步:创建节点索引映射
name_dict = {} # 节点名称->索引的映射
count = 0
for item in d:
parts = item.split("_")
node_name = parts[0]
# 为每个节点创建唯一ID
name_dict[node_name] = count
count += 1
# 构建节点数据
node_data = {
'name': node_name,
'category': CA_LIST.get(node_name, 0) # 从类别字典获取类别
}
json_data['data'].append(node_data)
# 第三步:构建关系数据
for record in data:
relation = {
'source': name_dict[record['p.Name']], # 起点索引
'target': name_dict[record['n.Name']], # 终点索引
'value': record['r.relation'] # 关系类型
}
json_data['links'].append(relation)
return json_data
转换过程详解:
节点收集与去重:
遍历所有关系记录
提取每条关系的起点和终点(格式:名称_类别
)
使用set
去重,得到所有唯一节点
节点映射创建:
为每个节点分配唯一ID(从0开始递增)
构建节点字典:{节点名称: 索引ID}
创建节点数据:包含名称和类别
关系数据构建:
遍历原始关系数据
使用节点字典将名称转换为索引ID
构建关系对象:起点ID、终点ID、关系类型
最终JSON结构:
{
"data": [
{"name": "叶圣陶", "category": "作家"},
{"name": "朱自清", "category": "作家"},
...
],
"links": [
{"source": 0, "target": 1, "value": "朋友"},
...
]
}
这种格式特别适合前端可视化库(如ECharts)展示知识图谱!
def Zget_KGQA_answer(array):
data_array = [] # 存储查询结果
# 示例:['叶圣陶', '朋友', '的']
# 表示查询:叶圣陶的朋友
for i in range(len(array) - 2):
# 确定当前查询的起点
if i == 0:
current_name = array[0] # 第一次使用数组第一个元素
else:
# 后续使用上一步查询结果的起点
current_name = data_array[-1]['p.Name']
# 获取关系词的同义词(如'朋友'->'friend')
relation = similar_words[array[i + 1]]
# 构建查询:查找具有特定关系指向当前人物的节点
query = """
match(p)-[r:%s{relation: '%s'}]->(n:Person{Name:'%s'})
return p.Name, n.Name, r.relation, p.cate, n.cate
""" % (relation, relation, current_name)
# 执行查询
result = list(graph.run(query))
data_array.extend(result)
# 返回结果:知识图谱数据 + 最终节点简介
return [
Zget_json_data(data_array), # 转换为可视化格式
get_profile(str(data_array[-1]['p.Name'])), # 获取简介
]
功能解析:
实现多跳关系查询(如"叶圣陶的朋友的朋友")
输入数组格式:[起点, 关系1, 关系2, ...]
处理流程:
第一跳:查询与起点有"关系1"的所有人
第二跳:以上一步结果作为新起点,查询有"关系2"的人
返回最终结果和最后一个人的简介
示例查询:
Zget_KGQA_answer(['叶圣陶', '朋友', '的'])
等价于:查找"叶圣陶"的所有"朋友"
def Zget_answer_profile(name):
return [get_profile(str(name))]
简洁的函数,调用爬虫模块获取指定人物的简介信息。
主程序入口
if '__main__' == __name__:
# 测试知识图谱问答功能
Zget_KGQA_answer(['叶圣陶', '朋友', '的'])
当直接运行脚本时,会执行测试查询:"叶圣陶的朋友"
假设我们查询"叶圣陶",可能得到如下知识图谱:
叶圣陶(作家)
│
├── 朋友 → 朱自清(作家)
│
├── 学生 → 钱钟书(作家)
│
└── 合作 → 夏丏尊(教育家)
使用这段代码返回的JSON数据,前端可以轻松渲染出这样的关系图!
Neo4j基础:
学习Cypher查询语言
理解图数据库的节点、关系、属性概念
知识图谱构建:
如何设计合理的节点和关系类型
数据建模最佳实践
应用扩展:
添加更多查询功能(如关系路径查询)
集成自然语言处理,实现智能问答
结合前端框架实现交互式可视化
这段代码展示了知识图谱应用的几个核心功能:
使用Cypher进行复杂关系查询
将图数据转换为可视化友好的JSON格式
实现多跳关系查询(知识图谱问答)
整合外部数据源获取详细信息
希望这篇解析对你有帮助!如果有任何问题,欢迎留言讨论。