文章目录

  • 一、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
  • neo4j程序架构 neo4j项目_py2neo


  • 编辑Path变量,在Path变量值的最后添加:%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;
  • neo4j程序架构 neo4j项目_py2neo_02


验证配置是否成功

  • 运行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}

neo4j程序架构 neo4j项目_Neo4j_03

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},属性有 idname.

三、示例1:药材供应链图谱实现

1、导入数据创建实体

步骤如下

  • 点击 Project,然后点击 Add Graph ,然后点击 Create a Local Graph 按钮,创建一个本地的图。
  • 设置新创建图的名字及密码,如 Graph0905123456,点击创建。
  • 启动数据库服务器:点击 Graph00905 中的 Start 按钮。
  • 运行:点击 Manage 管理页面,接着点击 Open Browser 打开浏览器。

2、导入数据创建关系

(1)示例图谱

假设该药材的供应链如下图所示,现在需要建立对应的简单图谱。

neo4j程序架构 neo4j项目_neo4j程序架构_04

(2)数据导入与显示

数据传送门:

链接1:https://pan.baidu.com/s/110rgkojcbEPdOzeRBZpeWA 提取码:sgio
链接2:

注意:为了防止出现显示的时候出现中文乱码,建议采用记事本打开CSV文件,将文件编码方式从ASC-II修改为UTF-8

neo4j程序架构 neo4j项目_neo4j程序架构_05

数据显示(前几行):

  • 企业 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 表示按行读取文件内容,包括两个值:idname,抽象的实体概念名字为Enterprise(企业)。

LOAD CSV WITH HEADERS  FROM "file:///entity-01.csv" AS line
MERGE (p:Enterprise{id:line.id,name:line.name})

neo4j程序架构 neo4j项目_neo4j程序架构_06


③ 显示所有实体

MATCH (n) 
RETURN n

显示结果如下:

neo4j程序架构 neo4j项目_neo4j程序架构_07


同时,可以编辑节点的颜色、大小,显示指定的双属性,如下所示。

neo4j程序架构 neo4j项目_py2neo_08


④ 导入药材 entity-02.csv 数据

抽象的实体概念名字为Medicinal(药材),包括两个属性:idname

LOAD CSV WITH HEADERS  FROM "file:///entity-02.csv" AS line
MERGE (p:Medicinal{id:line.id,name:line.name})

结果显示:

neo4j程序架构 neo4j项目_知识图谱_09


⑤ 插入关系,包括三种:

  • 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

neo4j程序架构 neo4j项目_Neo4j_10


⑥ 获取实体关系的顶层概念关系。

call db.schema

neo4j程序架构 neo4j项目_neo4j程序架构_11

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()

结果展示:

neo4j程序架构 neo4j项目_知识图谱_12

参考

  1. https://mp.weixin.qq.com/s/R0iLCDD0jQww7c0jwZzIbw