文章目录
- 一、Neo4j介绍
- 1、安装Java JRE
- 2、安装Neo4j
- 二、Cypher基本语句
- 1、基本CQL语句
- 2、MATCH
- 3、Cypher 导入CSV数据
- 三、示例1:药材供应链图谱实现
- 1、导入数据创建实体
- 2、导入数据创建关系
- (1)示例图谱
- (2)数据导入与显示
- 3、完整代码
- 四、示例2:python与neo4j
- 1、准备工作
- (1)安装 py2neo
- (2)py2neo连接neo4j
- 2、构建知识图谱
- (1)清空数据库结点和边
- (2)结点创建
- (3)关键创建
- 3、完整代码
- 参考
知识图谱中的每一条数据或事实一般会采用
<实体,属性,属性值>
、
<实体, 关系, 实体>
的
三元组形式来表示。Neo4j 是目前最流行的图形数据库,支持完整的事务,在属性图中,图是由顶点(Vertex),边(Edge)和属性(Property)组成的,顶点和边都可以设置属性,顶点也称作节点,边也称作关系,每个节点和关系都可以由一个或多个属性。Neo4j创建的图是用顶点和边构建一个有向图,其查询语言cypher已经成为事实上的标准。
Neo4j 图数据库安装初识及药材供应图谱实例
一、Neo4j介绍
在安装neo4j之前,需要安装Java JRE,并配置Java开发环境,然后安装neo4j服务。
1、安装Java JRE
Neo4j是基于Java运行环境的图形数据库,因此,必须向系统中安装JAVA SE(Standard Editon)的JRE。
- JDK和JRE是有区别的:JDK(Java Development Kit)是包括Java运行环境(JRE)和Java开发工具;而JRE(Java Runtime
Environment)是运行Java程序时必须安装的环境。- 如果只是运行Java程序,那么只需要安装JRE即可;如果希望开发Java程序,那么必须安装JDK。
下载地址:https://www.oracle.com/technetwork/java/javase/downloads/index.html
安装:正常安装,省略…
环境配置
- 新建
JAVA_HOME
变量,值为 jdk 的安装路径,默认安装路径为C:\Program Files\Java\jdk1.8.0_201
- 编辑Path变量,在Path变量值的最后添加:
%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;
验证配置是否成功。
- 运行cmd,输入
java -version
,如果显示java的版本信息,说明Java的安装和配置成功。
2、安装Neo4j
下载地址:https://neo4j.com/download-center/
- 该地址包含:企业版、社区版、桌面版
桌面版:比社区版功能多,此处使用桌面版本。
- 直接下载安装即可。
- 运行软件并初始化,如下图所示。
- 成功运行后的软件如下图所示。
二、Cypher基本语句
Cypher是 Neo4j 的数据库语言,既然是数据库语言,最基本的语句也是增删改查。
本节关注如何实现基本的增删改查、导入数据。
更多请移步官网
1、基本CQL语句
--创建节点
CREATE (p:Person { name:"Keanu Reeves", born:1964 })
--创建节点和关系
CREATE (p:Person{name:"kay"})-[:KNOWS]->(:Person{name:"Keanu Reeves"}) return p
--查询
MATCH (p:Person) WHERE p.name="kay" return p
--或者
MATCH (p:Person{name:"kay"}) return p
--查询关系路径
MATCH path=(p:Person{name:"kay"})-[:KNOWS]->(p:Person) return path
--修改
MATCH (p:Person) WHERE p.name="kay" set p.name="fen" return p
--删除
MATCH (p:Person) WHERE p.name="kay" delete p
--彻底删除(清空数据库,包括关系)
MATCH (n) DETACH DELETE n
示例:
- 知识图谱创建:创建 2 个
Person节点
,一个Movie节点
,建立关系,节点的属性以键值对的形式存储{key:value}
CREATE (a:Person { name:"Tom Hanks",
born:1956 })-[r:ACTED_IN { roles: ["Forrest"]}]->(m:Movie { title:"Forrest Gump",released:1994 })
CREATE (d:Person { name:"Robert Zemeckis", born:1951 })-[:DIRECTED]->(m)
RETURN a,d,r,m
- 结果为:
- 查询
--查询
MATCH (nineties:Movie) WHERE nineties.released >= 1990 AND nineties.released < 2000 RETURN nineties.title
--查询 Tom Hanks 演过的所有电影
MATCH (tom:Person {name: "Tom Hanks"})-[:ACTED_IN]->(tomHanksMovies) RETURN tom,tomHanksMovies
--谁导演了 Forrest Gump
MATCH (movie {title: "Forrest Gump"})<-[:DIRECTED]-(directors) RETURN directors.name
--Tom Hanks' co-actors...
MATCH (tom:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors) RETURN coActors.name
--How people are related to "Forrest Gump"...
MATCH (people:Person)-[relatedTo]-(:Movie {title: "Forrest Gump"}) RETURN people.name, Type(relatedTo), relatedTo
2、MATCH
Match 类似与SQL中的Select ,用来匹配一种搜索模式
查询所有节点
MATCH (n)
RETURN n
查询所有电影 Movie 标签
MATCH (movie:Moive)
RETURN movie.title
3、Cypher 导入CSV数据
导入Person数据,新建Person节点:
LOAD CSV WITH HEADERS FROM "https://neo4j.com/docs/developer-manual/3.4/csv/import/persons.csv" AS csvLine
CREATE (p:Person { id: toInteger(csvLine.id), name: csvLine.name })
person.csv
格式如下:
id,name
1,Charlie Sheen
2,Oliver Stone
3,Michael Douglas
4,Martin Sheen
5,Morgan Freeman
如此便导入5个Person节点,Person{id,name}
,属性有 id
和 name
.
三、示例1:药材供应链图谱实现
1、导入数据创建实体
步骤如下:
- 点击
Project
,然后点击Add Graph
,然后点击Create a Local Graph
按钮,创建一个本地的图。 - 设置新创建图的名字及密码,如
Graph0905
、123456
,点击创建。 - 启动数据库服务器:点击
Graph00905
中的Start
按钮。 - 运行:点击
Manage
管理页面,接着点击Open Browser
打开浏览器。
2、导入数据创建关系
(1)示例图谱
假设该药材的供应链如下图所示,现在需要建立对应的简单图谱。
(2)数据导入与显示
数据传送门:
链接1:https://pan.baidu.com/s/110rgkojcbEPdOzeRBZpeWA 提取码:sgio
链接2:
注意:为了防止出现显示的时候出现中文乱码,建议采用记事本打开CSV文件,将文件编码方式从ASC-II修改为UTF-8。
数据显示(前几行):
- 企业
entity-01.csv
id,name,label
1,威门药业, 企业
2,东莞焱兴实业, 企业
3,银川塞外杞香, 企业
4,安徽亳州药业, 企业
- 药材
entity-02.csv
id,name,label
13,北沙参,药材
14,枸杞子,药材
15,麦冬,药材
① 数据集的存放位置:放在该数据库的 import文件夹
下
- 位置:
\Neo4jData\neo4jDatabases\database-d037fa02-eb2c-4b32-964c-8fca89293883\installation-3.5.6\import
,需要根据自己情况进行调整。
② 数据导入
导入企业 entity-01.csv
文件:从import文件夹中载入CSV文件,AS line
表示按行读取文件内容,包括两个值:id
和 name
,抽象的实体概念名字为Enterprise
(企业)。
LOAD CSV WITH HEADERS FROM "file:///entity-01.csv" AS line
MERGE (p:Enterprise{id:line.id,name:line.name})
③ 显示所有实体
MATCH (n)
RETURN n
显示结果如下:
同时,可以编辑节点的颜色、大小,显示指定的双属性,如下所示。
④ 导入药材 entity-02.csv
数据
抽象的实体概念名字为Medicinal(药材),包括两个属性:id
和 name
LOAD CSV WITH HEADERS FROM "file:///entity-02.csv" AS line
MERGE (p:Medicinal{id:line.id,name:line.name})
结果显示:
⑤ 插入关系,包括三种:
- rela-11.csv:企业与企业的关系,企业买卖交易。
- 数据示例:
from_id,pro1,pro2,pro3,pro4,pro5,pro6,pro7,to_id
1,交易,北沙参,威门药业股份有限公司,东莞市焱兴实业发展有限公司,936,10,9360,2
1,交易,枸杞子,威门药业股份有限公司,银川塞外杞香科贸有限公司,159,6,954,3
1,交易,麦冬,威门药业股份有限公司,安徽亳州药业集团,938,9,8442,4
- 代码实现:需要注意 from_id(关系起始) 和 to_id(关系介绍),包含的属性需要和CSV表格一致。
LOAD CSV WITH HEADERS FROM "file:///rela-11.csv" AS line
match (from:Enterprise{id:line.from_id}),(to:Enterprise{id:line.to_id})
merge (from)-[r:rel{pro1:line.pro1,pro2:line.pro2,pro3:line.pro3,pro4:line.pro4,pro5:line.pro5,pro6:line.pro6,pro7:line.pro7}]->(to)
- 显示:企业之间交易关系
match(n) return n
- rela-12.csv:企业与药品的关系,威门药业购入药品。
- 数据示例:
from_id,pro1,pro2,pro3,pro4,to_id
1,买入,药品,威门药业股份有限公司,东莞市焱兴实业发展有限公司,13
1,买入,药品,威门药业股份有限公司,银川塞外杞香科贸有限公司,14
1,买入,药品,威门药业股份有限公司,安徽亳州药业集团,15
1,买入,药品,威门药业股份有限公司,安徽亳州药业集团,16
- 代码实现
LOAD CSV WITH HEADERS FROM "file:///rela-12.csv" AS line
match (from:Enterprise{id:line.from_id}),(to:Medicinal{id:line.to_id})
merge (from)-[r:rel{pro1:line.pro1,pro2:line.pro2,pro3:line.pro3,pro4:line.pro4}]->(to)
- 显示:企业药材之间关系
match(n) return n
- rela-21.csv:企业与药品的关系,from_id企业卖出to_id药品。
- 数据示例:
from_id,pro1,pro2,to_id
2,药品,卖出,13
3,药品,卖出,14
4,药品,卖出,15
- 代码实现
LOAD CSV WITH HEADERS FROM "file:///rela-21.csv" AS line
match (from:Enterprise{id:line.from_id}),(to:Medicinal{id:line.to_id})
merge (from)-[r:卖出{pro1:line.pro1,pro2:line.pro2}]->(to)
- 显示:企业药材之间关系
match(n) return n
⑥ 获取实体关系的顶层概念关系。
call db.schema
3、完整代码
--载入实体
LOAD CSV WITH HEADERS FROM "file:///entity-01.csv" AS line
MERGE (p:Enterprise{id:line.id,name:line.name})
LOAD CSV WITH HEADERS FROM "file:///entity-02.csv" AS line
MERGE (p:Medicinal{id:line.id,name:line.name})
--显示节点
match(n) return n
match(n) return n limit 9
--删除节点及关系
MATCH (n)-[r]-()
DELETE n,r
match(n) return n
--删除关系
MATCH (n)-[r]-()
DELETE r
--单纯删除所以节点:
match (n)
delete n
--查询指定节点
match (tom {id: "1"}) return tom
--载入关系1
LOAD CSV WITH HEADERS FROM "file:///rela-11.csv" AS line
match (from:Enterprise{id:line.from_id}),(to:Enterprise{id:line.to_id})
merge (from)-[r:rel{pro1:line.pro1,pro2:line.pro2,pro3:line.pro3,pro4:line.pro4,pro5:line.pro5,pro6:line.pro6,pro7:line.pro7}]->(to)
match(n) return n
--载入关系2
LOAD CSV WITH HEADERS FROM "file:///rela-12.csv" AS line
match (from:Enterprise{id:line.from_id}),(to:Medicinal{id:line.to_id})
merge (from)-[r:rel{pro1:line.pro1,pro2:line.pro2,pro3:line.pro3,pro4:line.pro4}]->(to)
match(n) return n
--载入关系3
LOAD CSV WITH HEADERS FROM "file:///rela-21.csv" AS line
match (from:Enterprise{id:line.from_id}),(to:Medicinal{id:line.to_id})
merge (from)-[r:卖出{pro1:line.pro1,pro2:line.pro2}]->(to)
MATCH p=()-[r:`卖出`]->() RETURN p LIMIT 25
match(n) return n
--显示顶层概念
call db.schema
四、示例2:python与neo4j
官方文档:https://py2neo.org/v3/index.html
1、准备工作
(1)安装 py2neo
pip install py2neo
(2)py2neo连接neo4j
def __init__(self):
# 建立连接
link = Graph("http://localhost:7474", username = "neo4j", password = "123456")
self.graph = link
报错:ProtocolError: Server certificate does not match known certificate for ‘localhost’; check details in file ‘C:\Users\XXXXX\.neo4j\known_hosts’
解决方法:清空 “knonw_hosts” 文件中的内容
2、构建知识图谱
(1)清空数据库结点和边
def clean_node(self):
# 清空数据库
self.graph.delete_all()
(2)结点创建
class Node(*labels, **properties)
定义中 label
的理解:标记一簇结点的信息。
from py2neo import Node
def create_node(self):
# 疾病、临床表现、药物等结点定义
for each_dis in dis_list:
dis_node=Node(dis_label,name=each_dis)
self.graph.create(dis_node)
for each_cli in cli_list:
cli_node = Node(cli_label, name=each_cli)
self.graph.create(cli_node)
for each_sdef in drug_list:
drug_node = Node(dru_label, name=each_sdef)
self.graph.create(drug_node)
for each_sdef in sdef_list:
sdef_node=Node(side_effect_label,name=each_sdef)
self.graph.create(sdef_node)
for each_zd in zd_method_list:
zd_node=Node(diagnostic_label,name=each_zd)
self.graph.create(zd_node)
(3)关键创建
选取结点:使用 find_one()
方法,通过指定 label,property_key,property_value 获取相应的结点。示例如下所示。
hyp = self.graph.find_one(
label = dis_label,
property_key = "name",
property_value = "高血压"
)
结点关系方法封装
from py2neo import Relationship
def create_Rel(self):
"""
建立关系
高血压疾病与临床表现之间的双向关系定义
:return:
"""
# 获取高血压与糖尿病结点,然后通过循环,建立这两个疾病与临床表现的关系
hyp_node = self.graph.find_one(
label=dis_label,
property_key="name",
property_value="高血压"
)
tnb_node = self.graph.find_one(
label=dis_label,
property_key="name",
property_value="糖尿病"
)
# 建立疾病与临床表现的关系
for cli_name in cli_list:
cli_node = self.graph.find_one(
label=cli_label,
property_key="name",
property_value=cli_name
)
hyp_to_cli = Relationship(hyp_node, '产生', cli_node)
self.graph.create(hyp_to_cli)
tnb_to_cli = Relationship(tnb_node, '产生', cli_node)
self.graph.create(tnb_to_cli)
# 建立疾病与诊断方法之间的关系
for diag_name in zd_method_list:
diag_node = self.graph.find_one(
label=diagnostic_label,
property_key="name",
property_value=diag_name
)
if diag_name=="血糖" and diag_name=="血脂" and diag_name=="胆固醇":
diag_to_dis = Relationship(diag_node, '辅助检查', tnb_node)
else:
diag_to_dis = Relationship(diag_node, '辅助检查', hyp_node)
self.graph.create(diag_to_dis)
# 建立疾病与药物关系
for drug_name in drug_list:
drug_node = self.graph.find_one(
label=dru_label,
property_key="name",
property_value=drug_name
)
if drug_name=="胰岛素" or drug_name=="胰高血糖素":
drug_to_disease=Relationship(drug_node,'治疗',tnb_node)
else:
drug_to_disease= Relationship(drug_node, '治疗', hyp_node)
self.graph.create(drug_to_disease)
# 建立药物与副作用之间的关系
for drug_name in drug_list:
drug_node = self.graph.find_one(
label=dru_label,
property_key="name",
property_value=drug_name
)
for sdef_name in sdef_list:
sdef_node = self.graph.find_one(
label=side_effect_label,
property_key="name",
property_value=sdef_name
)
if drug_name == "利尿药" and sdef_name == "尿酸升高":
drug_to_sdef = Relationship(drug_node, '引发', sdef_node)
self.graph.create(drug_to_sdef)
elif drug_name == "钙拮抗药" and sdef_name == "血钾降低":
drug_to_sdef = Relationship(drug_node, '引发', sdef_node)
self.graph.create(drug_to_sdef)
elif drug_name == "胰岛素" and (sdef_name == "恶心" or sdef_name == "呕吐"):
drug_to_sdef = Relationship(drug_node, '引发', sdef_node)
self.graph.create(drug_to_sdef)
elif drug_name == "胰高血糖素" and (sdef_name == "头晕" or sdef_name == "眼花"):
drug_to_sdef = Relationship(drug_node, '引发', sdef_node)
self.graph.create(drug_to_sdef)
3、完整代码
# -*- coding: utf-8 -*-
"""
Created on Fri Sep 6 13:47:39 2019
@author: 杰
"""
from py2neo import Graph,Node,Relationship #,NodeSelector
# 疾病
dis_list = ["糖尿病", "高血压"]
# 临床表现
cli_list = ["肾脏损害", "心脏损害", "脑部损害", "大小动脉损害"]
# 药物
drug_list = ["利尿药", "钙拮抗药", "胰岛素", "胰高血糖素"]
# 诊断方法
zd_method_list = ["血脂", "血糖", "胆固醇", "超声心动图", "心电图", "肝功能", "肾功能"]
# 副作用
sdef_list = ["恶心", "呕吐", "头晕", "眼花","血钾降低","尿酸升高"]
# 定义三个label
dis_label = "疾病" # 定义疾病label
cli_label = "临床表现" # 定义临床表现label
dru_label = "药物" # 定义药物label
side_effect_label = "副作用"# 定义副作用label
diagnostic_label = "诊断方法"# 定义诊断label
class createBHPData(object):
def __init__(self):
# 建立连接
link = Graph("http://localhost:7474", username="neo4j", password="123456")
self.graph = link
def clean_node(self):
# 清空数据库
self.graph.delete_all()
def create_node(self):
# 疾病、临床表现、药物等结点定义
for each_dis in dis_list:
dis_node = Node(dis_label,name=each_dis)
self.graph.create(dis_node)
for each_cli in cli_list:
cli_node = Node(cli_label, name=each_cli)
self.graph.create(cli_node)
for each_sdef in drug_list:
drug_node = Node(dru_label, name=each_sdef)
self.graph.create(drug_node)
for each_sdef in sdef_list:
sdef_node = Node(side_effect_label,name=each_sdef)
self.graph.create(sdef_node)
for each_zd in zd_method_list:
zd_node = Node(diagnostic_label,name=each_zd)
self.graph.create(zd_node)
def create_Rel(self):
"""
建立关系
高血压疾病与临床表现之间的双向关系定义
:return:
"""
# 获取高血压与糖尿病结点,然后通过循环,建立这两个疾病与临床表现的关系
hyp_node = self.graph.find_one(
label = dis_label,
property_key = "name",
property_value = "高血压"
)
tnb_node = self.graph.find_one(
label = dis_label,
property_key = "name",
property_value = "糖尿病"
)
# 建立疾病与临床表现的关系
for cli_name in cli_list:
cli_node = self.graph.find_one(
label=cli_label,
property_key="name",
property_value=cli_name
)
hyp_to_cli = Relationship(hyp_node, '产生', cli_node)
self.graph.create(hyp_to_cli)
tnb_to_cli = Relationship(tnb_node, '产生', cli_node)
self.graph.create(tnb_to_cli)
# 建立疾病与诊断方法之间的关系
for diag_name in zd_method_list:
diag_node = self.graph.find_one(
label = diagnostic_label,
property_key = "name",
property_value = diag_name
)
if diag_name == "血糖" and diag_name == "血脂" and diag_name == "胆固醇":
diag_to_dis = Relationship(diag_node, '辅助检查', tnb_node)
else:
diag_to_dis = Relationship(diag_node, '辅助检查', hyp_node)
self.graph.create(diag_to_dis)
# 建立疾病与药物关系
for drug_name in drug_list:
drug_node = self.graph.find_one(
label = dru_label,
property_key = "name",
property_value = drug_name
)
if drug_name == "胰岛素" or drug_name == "胰高血糖素":
drug_to_disease = Relationship(drug_node,'治疗',tnb_node)
else:
drug_to_disease = Relationship(drug_node, '治疗', hyp_node)
self.graph.create(drug_to_disease)
# 建立药物与副作用之间的关系
for drug_name in drug_list:
drug_node = self.graph.find_one(
label = dru_label,
property_key = "name",
property_value = drug_name
)
for sdef_name in sdef_list:
sdef_node = self.graph.find_one(
label = side_effect_label,
property_key = "name",
property_value = sdef_name
)
if drug_name == "利尿药" and sdef_name == "尿酸升高":
drug_to_sdef = Relationship(drug_node, '引发', sdef_node)
self.graph.create(drug_to_sdef)
elif drug_name == "钙拮抗药" and sdef_name == "血钾降低":
drug_to_sdef = Relationship(drug_node, '引发', sdef_node)
self.graph.create(drug_to_sdef)
elif drug_name == "胰岛素" and (sdef_name == "恶心" or sdef_name == "呕吐"):
drug_to_sdef = Relationship(drug_node, '引发', sdef_node)
self.graph.create(drug_to_sdef)
elif drug_name == "胰高血糖素" and (sdef_name == "头晕" or sdef_name == "眼花"):
drug_to_sdef = Relationship(drug_node, '引发', sdef_node)
self.graph.create(drug_to_sdef)
c = createBHPData()
c.clean_node()
c.create_node()
c.create_Rel()
结果展示:
参考