图数据库-1-【Neo4j】的安装及使用

使用neo4j存储树形无限级菜单
参考快速初步了解Neo4j与使用
参考neo4j python_Neo4j安装+Python操作Neo4j
参考Neo4j入门操作
参考图数据库neo4j通过py2neo的查询操作
参考py2neo在已有节点上批量创建关系

1 业务场景

(1)树形菜单单表存储
对于树形菜单这种业务数据,由于量小、关系复杂,所以在关系型数据库中,存储的格式一般都如下所示:

id,	 name,    pid
01,	 bigdata, 00
002, hadoop,  01
003, spark,   01
02,  search,  01
03,  lucene,  02
04,  es,      02

其关系图如下所示。
请添加图片描述

(2)为何不使用主外键表
为什么不使用主外键表来存储这种数据,非得只使用一张表来存储呢?
结果导致查询非常受限,通常只能递归出所有节点,然后对比找到指定数据。

如果使用主外键表存储,通常关系越复杂需要的外键表越多,假如有8层关系,意味着需要join到8个外键表,才能获取一条完整数据。这样一对比,大多数时候,还是将这种数据存储在一个表中,然后通过父字段找到上一级。当然这种场景下,通常数据量都不会太大,因为递归时间和数据量成正比。

(3)当数据量超级大时,应该怎么设计才能支持各种各样的查询,也能提供良好的性能呢?

这个时候用关系型数据库存储肯定不行,超过几十万的数据,递归都需要十几或者几十秒的遍历时间,这样的性能是远远不达标的。

而图形数据库的出现,则是解决这个问题的神器,图形数据库就是为了存储超级复杂的依赖关系和提供高效的查询性能而生的,比如社交网络,知识图谱,地图最优路径等等。

(4)树形菜单的数据,也可以存储在neo4j里面,从而提供强大的查询分析功能
neo4j的小数据下的例子与xmind的思维导图非常类似。

比如存储从小学到高中的课程里面的章节关系和知识点,如果我们用关系型数据库存储, 提供的分析查询能力非常有限,只能查某个确定节点的父节点,如果想找具体的任意一个节点需要递归遍历所有数据,或者想查某一个科目下,包含知识点路径最长的是哪个,等等就比较复杂了。

图形数据库里面描述数据,是通过节点和关系来描述的,关系必须有开始节点和结束节点 ,节点和关系都可以有属性。

下面说下将树形菜单,存储到neo4j的思路:

(1)递归的每行数据是一个节点,首先插入所有的节点。
(2)找到每个节点的父节点做为start节点,本身作为end节点,建立起关系。

上面的两个步骤既可以分开执行,也可以单独执行,具体可以参考使用neo4j的api。
导入完的几个效果图如下:(注意这里限制深度了,不限制这个图密度可能非常大)。

2 下载安装Neo4j

Neo4j是一个高性能的,NOSQL图形数据库,它将结构化数据存储在网络上而不是表中。

neo4j官网下载地址
官方提供了很多可选的下载项,企业版,社区版,桌面版。

2.1 安装

(1)下载桌面版
版本Neo4j Desktop Setup 1.4.8.exe,双击安装即可。
注意下载的时候复制秘钥。
安装位置D:\Program Files\Neo4j Desktop。
(2)首次打开
提示Please choose path where you want to store application data。
选择D:\neo4japplicationdata。
(3)输入注册信息
提示Use this key to activate your copy of Neo4j Desktop for use.
输入下载时显示的公钥信息。
(4)进入neo4j的页面
在这里插入图片描述

官方有两个例子,其中一个就是Movie的图关系建模。
编辑器文本框输入:play movies 就可以查看这个demo。

2.2 浏览器使用

(1)登陆浏览器的地址http://localhost:7474。
在这里插入图片描述
双击里面的节点,可以打开与其关联的关系节点。
(2)程序中连接Neo4j数据库,使用neo4j://localhost:7687。

3 使用

3.1 创建数据库

(1)新建project:mytest
(2)添加Local DBMS
Name:myDBMS
password:bigdata
(3)点击start启动数据库管理系统
系统里默认自建了system和neo4j数据库。

system数据库的作用:
The System database contains metadata for the databases within your DBMS, 
including the associated security model. It cannot be removed.

(4)新建数据库:mydb
(5)点击Neo4j Browser
进入一个Browser,这个建立的是一个本地的模式,所以可以在本地进行操作。
在这里插入图片描述
进入这个页面后,我们可以在最顶上写代码语句。

3.2 语法

(1)添加数据
指定想要成为图形的一部分的图形结构,标签和属性。

CREATE (:Movie { title:"The Matrix",released:1997 })
添加1个节点,1个标签和2个属性

(2)添加的同时返回创建的数据
使用RETURN子句,它引用我们分配给模式元素的变量。

CREATE (p:Person { name:"Keanu Reeves", born:1964 })
RETURN p

(3)创建更复杂的结构
创建多个元素,可以用逗号分隔元素或使用多个CREATE语句。
创建ACTED_IN与角色信息的关系,或者DIRECTED导演的关系。

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

在这里插入图片描述

(4)查询指定节点

查找标有Movie标签的所有节点
MATCH (m:Movie) RETURN m
查找标有LINE标签,并且name属性为"高一线"的节点
MATCH (L:LINE) where L.name="高一线" RETURN L

(5)删除所有数据

原理:匹配所有的节点,然后进行删除。
match (n) detach delete n

删除所有节点和关系
MATCH (n)
OPTIONAL MATCH (n)-[r]-()
DELETE n,r

4 python操作Neo4j

Neo4j 是目前最流行的图形数据库,支持完整的事务,图形数据库也就意味着它的数据并非保存在表或集合中,而是保存为节点以及节点之间的关系。

图是由顶点(Vertex),边(Edge)和属性(Property)组成的,顶点和边都可以设置属性,顶点也称作节点,边也称作关系,每个节点和关系都可以有一个或多个属性。
py2neo 是用来对接 Neo4j的 Python 库。

密切注意软件和库的版本,否则是无法创建成功的。重点在于新旧版本的问题,首先需要检查一下自己使用的neo4j的版本是多少,再看一下py2neo的版本是多少。只有py2neo版本支持的neo4j版本的情况下才能不报错。

CMD>pip install py2neo=2021.2.3
其余往上的版本在windows中会报以下错误
OverflowError: mktime argument out of range

在这里插入图片描述

Neo4j服务器具有一个集成的浏览器,在一个运行的服务器实例上访问 “http://localhost:7474/”,打开浏览器,显示启动页面。默认的用户是neo4j,其默认的密码是:neo4j,第一次成功登陆到Neo4j服务器之后,需要重置密码,修改成了bigdata。

4.1 连接默认数据库

默认连接neo4j。

from py2neo import Graph
from py2neo import Node
from py2neo import Relationship
# g = Graph('http://localhost:7474/',username='neo4j',password='bigdata')
g = Graph("bolt://localhost:7687", auth=("neo4j", "bigdata"))

4.2 连接指定数据库

from py2neo import Graph
from py2neo import Node
from py2neo import Relationship
from py2neo import Graph
g = Graph("http://localhost:7474/", auth=("neo4j", "bigdata"), name='mydb')

其中auth=(“用户名”,“密码”)
其中name=“数据库名”

4.3 插入数据

(1)方式一:一次次创建

from py2neo import Graph
from py2neo import Node
from py2neo import Relationship
g = Graph("bolt://localhost:7687", auth=("neo4j", "bigdata"))
a = Node('Person',name='bubu')
g.create(a)
b = Node('Person',name='kaka')
g.create(b)
r = Relationship(a,'KNOWS',b)
g.create(r)

(2)方式二:一次性创建

from py2neo import Graph
from py2neo import Node
from py2neo import Relationship
g = Graph("bolt://localhost:7687", auth=("neo4j", "bigdata"))

a = Node('Person',name='bubu')
b = Node('Person',name='kaka')
r = Relationship(a,'KNOWS',b)
s = a|b|r
g.create(s)

4.4 已有节点创建关系

from py2neo import Graph
from py2neo import Node
from py2neo import Relationship
g = Graph("bolt://localhost:7687", auth=("neo4j", "bigdata"))

a = g.nodes.match("Person",name='bubu').first()
b = g.nodes.match("Person", name='kaka').first()
r1 = Relationship(a, '包含', b)
g.create(r1)

生成类似如下的图形。
在这里插入图片描述

5 应用实例

5.1 写入图数据

产线数量 76
区域数量 460
设备数量 33999

产线下面有区域,区域下面有设备。

#encoding=utf8
import pandas as pd
from py2neo import Graph
from py2neo import Node
from py2neo import Relationship
g = Graph("bolt://localhost:7687", auth=("neo4j", "bigdata"))

# 1 数据整理,获取节点
filename = "设备信息表 many.xlsx"
df = pd.read_excel(filename)
line_list = []
area_list = []
devid_list = []
for index, row in df.iterrows():
    line = row["产线(deviceLine)"]
    area = row["设备区域(deviceArea)"]
    devid = row["设备编码(deviceCode)"]
    if line not in line_list:
        line_list.append(line)
    if area not in area_list:
        area_list.append(area)
    if devid not in devid_list:
        devid_list.append(devid)
print("产线数量",len(line_list))
print("区域数量",len(area_list))
print("设备数量",len(devid_list))
# 2 创建节点
for line in line_list:
    a = Node('LINE', name=line)
    g.create(a)
for area in area_list:
    b = Node('AREA', name=area)
    g.create(b)

for devid in devid_list:
    c = Node('DEVID',name=devid)
    g.create(c)

# 3 创建关系
for index, row in df.iterrows():
    line = row["产线(deviceLine)"]
    area = row["设备区域(deviceArea)"]
    devid = row["设备编码(deviceCode)"]
    a = g.nodes.match("LINE",name=line).first()
    b = g.nodes.match("AREA", name=area).first()
    c = g.nodes.match("DEVID", name=devid).first()
    r1 = Relationship(a, '包含', b)
    r2 = Relationship(b, '又包含', c)
    g.create(r1)
    g.create(r2)

5.2 查询产线节点

#encoding=utf8
from py2neo import Graph
from py2neo import Node
from py2neo import Relationship
g = Graph("bolt://localhost:7687", auth=("neo4j", "bigdata"))

# (1)获取所有产线
aa = g.nodes.match("LINE")
print("产线数量",len(aa))
for a in aa:
    print(a,a["name"])
# (2)获取指定产线
aa = g.nodes.match("LINE",name="计通室").first()
print(aa,aa["name"])

5.3 查询指定产线下的所有区域

#encoding=utf8
from py2neo import Graph
from py2neo import Node
from py2neo import Relationship
g = Graph("bolt://localhost:7687", auth=("neo4j", "bigdata"))

# (1)获取指定产线
a = g.nodes.match("LINE",name="计通室").first()
print(a,a["name"])
# (2)获取该产线下的所有区域
rr = g.relationships.match({a})
for r in rr:
    end = r.nodes[1]
    print(end["name"])

5.4 获取指定区域下的所有设备

原理:查询一个节点的所有连接关系和周围的节点。
g.relationships.match({node})

#encoding=utf8
from py2neo import Graph
from py2neo import Node
from py2neo import Relationship
g = Graph("bolt://localhost:7687", auth=("neo4j", "bigdata"))

# (1)获取指定产线
a = g.nodes.match("LINE",name="计通室").first()
# (2)获取该产线下的所有区域
rr = g.relationships.match({a})
for r in rr:
    end = r.nodes[1]
    # (3)获取指定区域下的设备
    if end["name"] == "炼铁":
        r3 = g.relationships.match({end})
        for k in r3:
            print(k.nodes[1])

在这里插入图片描述

5.5 转化为函数

#encoding=utf8
from py2neo import Graph
from py2neo import Node
from py2neo import Relationship
g = Graph("bolt://localhost:7687", auth=("neo4j", "bigdata"))


def get_area(line):
    # (1)获取指定产线
    a = g.nodes.match("LINE", name=line).first()
    # (2)获取该产线下的所有区域
    rr = g.relationships.match({a})
    area_list = []
    for r in rr:
        node = r.nodes[1]
        area = node["name"]
        area_list.append(area)
    return area_list

def get_devid(line,area):
    # (1)获取指定产线
    a = g.nodes.match("LINE", name=line).first()
    # (2)获取该产线下的所有区域
    rr = g.relationships.match({a})
    devid_list = []
    for r in rr:
        end = r.nodes[1]
        # (3)获取指定区域下的设备
        if end["name"] == area:
            r3 = g.relationships.match({end})
            for k in r3:
                node = k.nodes[1]
                if "DEVID" in node.labels:
                    devid = node["name"]
                    devid_list.append(devid)
    return devid_list

line = "计通室"
area = "炼铁"
print(get_area(line))
print(get_devid(line,area))

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皮皮冰燃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值