Datawhale 知识图谱组队学习 之 Task 3 Neo4j图数据库导入数据
目录
一、Neo4j简介
1.1 基本概念
Neo4j使用图相关的概念来描述数据模型,把数据保存为图中的节点以及节点之间的关系。数据主要由三部分构成:
- 节点。节点表示对象实例,每个节点有唯一的ID区别其它节点,节点带有属性;
- 关系。就是图里面的边,连接两个节点,另外这里的关系是有向的并带有属性;
- 属性。key-value对,存在于节点和关系中
1.2 索引
- 动机:Neo4j使用遍历操作进行查询。为了加速查询,Neo4j会建立索引,并根据索引找到遍历用的起始节点;
- 介绍:默认情况下,相关的索引是由Apache Lucene提供的。但也能使用其他索引实现来提供。
- 操作:用户可以创建任意数量的命名索引。每个索引控制节点或者关系,而每个索引都通过key/value/object三个参数来工作。其中object要么是一个节点,要么是一个关系,取决于索引类型。另外,Neo4j中有关于节点(关系)的索引,系统通过索引实现从属性到节点(关系)的映射。
- 作用:
- 查找操作:系统通过设定访问条件比如,遍历的方向,使用深度优先或广度优先算法等条件对图进行遍历,从一个节点沿着关系到其他节点;
- 删除操作:Neo4j可以快速的插入删除节点和关系,并更新节点和关系中的属性。
1.3 Neo4j的优势
Neo4j 查询的高性能表现、易于使用的特性及其设计的灵活性和开发的敏捷性,以及坚如磐石般的事务管理特性,都充分说明了使用Neo4j是一个不错的选择。有关它的所有优点,总结起来,主要表现在以下几个方面。
- 闪电般的读/写速度,无与伦比的高性能表现;
- 非结构化数据存储方式,在数据库设计上具有很大的灵活性;
- 能很好地适应需求变化,并适合使用敏捷开发方法;
- 很容易使用,可以用嵌入式、服务器模式、分布式模式等方式来使用数据库;
- 使用简单框图就可以设计数据模型,方便建模;
- 图数据的结构特点可以提供更多更优秀的算法设计;
- 完全支持ACID完整的事务管理特性;
- 提供分布式高可用模式,可以支持大规模的数据增长;
- 数据库安全可靠,可以实时备份数据,很方便恢复数据;
- 图的数据结构直观而形象地表现了现实世界的应用场景。
二、Neo4j 数据导入
2.1 数据集简介
-
数据源:39健康网。包括15项信息,其中7类实体,约3.7万实体,21万实体关系。
-
本次组队学习搭建的系统的知识图谱结构如下:
图 2 知识图谱结构
- 知识图谱实体类型
图 3 知识图谱实体类型
- 知识图谱实体关系类型
图 4 知识图谱实体关系类型
- 知识图谱疾病属性
图 5 知识图谱疾病属性
- 基于特征词分类的方法来识别用户查询意图
图 6 基于特征词分类的方法来识别用户查询意图
2.2 数据导入
该项目是使用下方链接里的github项目文件运行的,数据均存放在data文件夹中,
本节主要分析的build_graph.py文件导入使用的是disease.csv文件
由于该代码是使用for循环读入的,因此需要导入数据的时间较慢
除了windows环境下的导入约需2h,mac和linux系统下导入完成约小于1h
2.2.1 Neo4j 账号密码设置
要将 数据 导入 Neo4j 图数据库,首先需要 进入 build_graph.py 类中,在 类 MedicalGraph 中 的加入 本地 Neo4j 图数据库 的 账号和密码;
class MedicalGraph:
def __init__(self):
...
self.graph = Graph("http://localhost:7474", username="neo4j", password="自己的")
...
2.2.2 导入 数据
运行 以下命令:
python build_graph.py
2.3 知识图谱展示
运行介绍之后,打开浏览器进入网址:http://localhost:7474/browser/,可以看到我们导入的数据的知识图谱
2.4 主体类 MedicalGraph 介绍
class MedicalGraph:
def __init__(self):
pass
# 读取文件,获得实体,实体关系
def read_file(self):
psss
# 创建节点
def create_node(self, label, nodes):
pass
# 创建疾病节点的属性
def create_diseases_nodes(self, disease_info):
pass
# 创建知识图谱实体
def create_graphNodes(self):
pass
# 创建实体关系边
def create_graphRels(self):
pass
# 创建实体关系边
def create_relationship(self, start_node, end_node, edges, rel_type, rel_name):
pass
2.5 主体类 MedicalGraph 中关键代码讲解
-
- 获取数据路径
-
- 链接 Neo4j 图数据库
self.graph = Graph("http://localhost:7474", username="neo4j", password="自己设定的密码")
-
- for循环读取文件,获得实体,实体关系
这部分代码的核心就是读取 disease.csv 数据文件,使用的是文件列的信息,以此获取实体和实体关系信息。
- 抽取的实体信息(列):
- diseases 疾病
- aliases 别名
- symptoms 症状
- parts 部位
- departments 科室
- complications 并发症
- drugs 药品
- 由函数建立实体之间的关系:
- disease_to_symptom 疾病与症状关系
- disease_to_alias 疾病与别名关系
- diseases_to_part 疾病与部位关系
- disease_to_department 疾病与科室关系
- disease_to_complication 疾病与并发症关系
- disease_to_drug 疾病与药品关系
- disease 实体 属性信息:
- name
- age 年龄
- infection 传染性
- insurance 医保
- checklist 检查项
- treatment 治疗方法
- period 治愈周期
- rate 治愈率
- money 费用
def read_file(self)
分析:用pandas读取完整文件,for循环处理DataFrame每一行的数据,取出每一行中各列的内容,如果属于disease的实体及其属性,统一存放在disease_dict字典中,最后将disease_dict一行的所有属性(key)对应的值(value)都存放在diseases_infos,其他抽取的实体信息单独存放在与疾病相关的关系列表中
- 4.创建节点
这部分代码主要是为了创建不包含属性的 节点
def create_node(self, label, nodes):
使用graph.create()函数创建不同实体的node节点(diseases, aliases, symptoms, parts,departments, complications, drugs)
其中,Neo4j CQL的CREATE命令<==>graph.create(node)
- 5.创建带有属性节点
def create_diseases_nodes(self, disease_info):
取出read_file()函数返回的diseases_info中disease相关的属性,创建属性的node节点
- 6.创建知识图谱实体
def create_graphNodes(self)
调用create_node()函数创建实体节点
- 7.创建知识图谱关系
def create_graphRels(self)
调用create_relationship函数创建实体之间的关系
- 8.创建实体关系边
def create_relationship(self, start_node, end_node, edges, rel_type, rel_name):
"""
创建实体关系边
:param start_node:
:param end_node:
:param edges:
:param rel_type:
:param rel_name:
:return:
"""
count = 0
# 去重处理
set_edges = []
for edge in edges:
set_edges.append('###'.join(edge))
all = len(set(set_edges))
for edge in set(set_edges):
edge = edge.split('###')
p = edge[0]
q = edge[1]
query = "match(p:%s),(q:%s) where p.name='%s'and q.name='%s' create (p)-[rel:%s{name:'%s'}]->(q)" % (
start_node, end_node, p, q, rel_type, rel_name)
try:
self.graph.run(query)
count += 1
print(rel_type, count, all)
except Exception as e:
print(e)
return
Neo4j CQL MATCH命令<===>graph.run(MATCH命令) 查找
针对该函数的说明:
- 传入的参数
- start_node:“Disease”,
- end_node:如"Alias"的相关实体,
- edges: 如rel_alias, 其中拆取的q代表"Disease", p代表如"Alias"的相关实体,
- rel_type:如"ALIAS_IS"的连接关系,rel_name:"别名"为连接的关系实体名
- query = “match(p:%s),(q:%s) where p.name=’%s’and q.name=’%s’ create §-[rel:%s{name:’%s’}]->(q)”
相当于match(p:‘disease’),(q:‘alias’) where p.name='disease’and q.name=‘alias’ create §-[rel:‘ALIAS_IS’{name:‘别名’}]->(q)