图数据库Neo4j学习笔记系列
发布日期:2021-06-30 13:36:56 浏览次数:2 分类:技术文章

本文共 12739 字,大约阅读时间需要 42 分钟。

作者简介: 20年IT工作经验,曾在华为、HP、移动、电网等国内外知名IT企业任职;关注领域包括证券、航空、制造、电信、电网等。在数据库开发和优化、数据仓库、系统架构、大中型项目管理、部门管理、数据挖掘和分析、数据治理、大数据方面有一定研究。

 

关于Neo4j图数据库

一、关于neo4j图数据库的下载、安装和配置

1、下载,建议从官网下载社区版本

ftp://neo4j.55555.io/neo4j/3.5.12/neo4j-community-3.5.12-windows.zip

ftp://neo4j.55555.io/neo4j-doc/3.5/

2、预安装,确保java已安装

执行java –version命令,检查java是否已安装

3、安装步骤,很简单,不必赘述

4、安装后的环境变量配置

SET NEO4J_HOME=c:\neo4j

SET PATH=% NEO4J_HOME %\BIN

5、以管理员身份在命令窗口执行neo4j.bat console

6、通过IE打开http://localhost:7474/,建议打开http://127.0.0.1:7474/

7、设置用户名和密码

8、打开主页面

9、neo4j的几个命令

neo4j install-service neo4j start neo4j stop neo4j restart neo4j status

10、部分问题和困扰

问题1、好像neo4j.batconsole和neo4j start无法共存

启动了neo4j.bat console,就无法启动neo4j start,反之亦然

问题2、另外访问neo4j首页,建议通过IP地址访问http://127.0.0.1:7474/browser/,否则无法正常连接neo4j数据库

二、关于neo4j图数据库的一些粗浅认识

A graph database can store any kind of data usinga few simple concepts:

1.Nodes - graph data records

2.Relationships - connect nodes

3.Properties - named data values

图数据库包括节点、关系和属性。

节点由标签和一系列属性构成,

#neo4j代码 CREATE (ee:Person { name: "Emil", from:"Sweden", klout: 99 }) #Python代码 a = Node("Person", name="Alice",createdate=’2019-02-02’)标签等同于数据库中的表,name意味着值的名称,在这里姑且认为是主键值吧,可以想想如何确保数据表中的数据的唯一性吧,后面的属性可以根据需要进行定制

关于关系,是节点和节点之间的连接,当然关系也可以设置很多明细的属性

#neo4j代码 CREATE (ee)-[:KNOWS {
since: 2001}]->(js),(ee)-[:KNOWS{
rating: 5}]->(ir) #Python代码 ab = Relationship(a, "KNOWS", b) ab=Relationship(test_node_2,'妻子',test_node_1)

关系查找,如果一个系统只存储而不能查找,这个系统大概是没什么价值的,neo4j是通过match来进行查找的。

#neo4j代码 MATCH (ee:Person) WHERE ee.name = "Emil" RETURNee; #Python代码 list(matcher.match("Person").where("_.name =~ 'K.*'"))

三,我要做的事情,是把各系统架构类的东西以图的形式呈现出来,形成所谓的知识图谱,可以基于业务视角呈现各系统之间的耦合关系,可以基于数据库的视角,能够查看各业务系统之间的相互依赖,也可以以机房机柜角度查看,当然这只是初衷,也许会随着对图数据库的知识的认识深度变化而变化。这只是个开始。

py2neo使用

neo4j是个图数据库,所有的数据库都要通过语言去访问,一个封闭的系统是没有意义的,在python里也提供了基于neo4j的package,不过使用最广的还是py2neo,提供对图库的连接和增删改查操作,本文也遵循这个思路,先从基本语法做起,后面才慢慢丰富完善,至少先看到一些成果。

还是一句话,网上的材料看似很丰富,但良莠不齐,有的缺乏深度有的是抄袭有的甚至无法运行,所有的材料要自己看过试过,所以非常感谢下面链接的仁兄的做事态度,对相关代码略作修改,完善并使用起来。

https://www.cnblogs.com/Bw98blogs/p/10946569.html

from py2neo import Graph, Node, Relationship, NodeMatcher class Neo4jDao:     #初始化用户名密码     def __init__(self, username='neo4j', password='Wbq197711'):         self.username = username         self.password = password         self.my_graph = self.connectNeo4j(username=self.username, password=self.password)     @staticmethod     def connectNeo4j(username:str, password: str):         #初始化图数据库连接         my_graph = Graph(             "http://localhost:7474",             username=username,             password=password         )         return my_graph     def createNode(self, label: str, properties:dict):         #创建结点,如果结点有类型和属性的话,也一起创建         #:param label: 结点的类型         #:param properties: 多个属性键值对组成的字典,用于初始化结点的属性         #:return:创建好的结点,类型为Node         node = Node(label, **properties)         self.my_graph.create(node)         return node     def createRelationship(self, start_node: Node, relation_type: str, end_node: Node, relation_properties=None):         #创建关系,如果有关系上属性的话就一起创建         #:param start_node: 起始结点         #:param relation_type: 关系类型         #:param end_node: 结束结点         #:param relation_properties: 属性字典,如果有传入的话,则在关系上添加多个形如"属性名:属性值"的键值对         #:return: 创建好的关系对象         new_relation = Relationship(start_node, relation_type, end_node)         new_relation.update(relation_properties)         self.my_graph.create(new_relation)         return new_relation     def updateProperty(self, node_or_relation, aProperty: tuple):         #更新节点和关系的属性         #:param node_or_relation: 一个结点或关系对象         #:param aProperty: 需要更新的"属性名:属性值"键值对组成的字典         #:return:         # 判断节点和关系是否正确,如果更新属性         if (not isinstance(node_or_relation, Node)) and (not isinstance((node_or_relation, Relationship))):             raise TypeError('node_or_relation 需要是 Node 或 Relationship 类型')         node_or_relation[aProperty[0]] = aProperty[1]  # tuple的第一位存属性名,第二位存属性值         self.my_graph.push(node_or_relation)     @staticmethod     def updateMultipleProperty(node_or_relation, properties: dict):         #同时更新多个属性         #:param node_or_relation: 一个结点或关系对象         #:param properties: 多个需要更新的"属性名:属性值"键值对组成的字典         #:return:         #判断节点和关系是否正确,如果更新属性         if (not isinstance(node_or_relation, Node)) and (not isinstance((node_or_relation, Relationship))):             raise TypeError('node_or_relation 需要是 Node 或 Relationship 类型')         node_or_relation.update(properties)     def findOneNode(self, node_type=None, properties=None, where=None):         #查找一个结点         #:param node_type:结点类型,即 label,类型是str         #:param properties: 多个"属性名: 属性值"键值对组成的字典,类型是dict         #:param where: 查询子句,类型是str         #:return: 一个Node类型的结点         #初始化节点匹配实例         matcher = NodeMatcher(self.my_graph)         #节点判断         if not (isinstance(node_type, str)):             raise TypeError('查询的结点的类型必须要指定,而且node_type必须是字符串类型')         #属性字典判断         if not (properties is None):             if not (isinstance(properties, dict)):                 raise TypeError('properties是多个属性键值对组成的字典,它必须是dict类型')         #where条件判断         if not (where is None):             if not (isinstance(where, str)):                 raise TypeError('where表示的是查询条件,它必须是字符串类型')         #组合条件判断,以匹配相关match函数,并返回单一节点         if (where is None) and (properties is None):             return matcher.match(node_type).first()         elif (not (properties is None)) and (where is None):             return matcher.match(node_type, **properties).first()         elif (properties is None) and (not (where is None)):             return matcher.match(node_type).where(where).first()     def findAllNode(self, node_type=None, properties=None, where=None):         #查找多个结点         #:param node_type: node_type:结点类型,即 label,类型是str         #:param properties: 多个"属性名: 属性值"键值对组成的字典,类型是dict         #:param where: 查询子句,类型是str         #:return: 多个Node类型的结点组成的list,类型是list         #初始化节点匹配实例         matcher = NodeMatcher(self.my_graph)         #节点判断         if not (isinstance(node_type, str)):             raise TypeError('查询的结点的类型必须要指定,而且node_type必须是字符串形式')         #where条件判断         if not (where is None):             if not (isinstance(where, str)):                 raise TypeError('where表示的是查询条件,它必须是字符串形式')         #组合条件判断,以匹配相关match函数,并返回节点list         #如果属性和where均为None         if (properties is None) and (where is None):             res = matcher.match(node_type)             if len(list(res)) > 0:                 return list(res)             else:                 return None         #属性不为None,where为None         elif (not (properties is None)) and (where is None):             res = matcher.match(node_type, **properties)             if len(list(res)) > 0:                 return list(res)             else:                 return None         ##属性为None,where不为None         elif (properties is None) and (not (where is None)):             res = matcher.match(node_type).where(where)             if len(list(res)) > 0:                 return list(res)             else:                 return None     def findOneRelationship(self, nodes=None, r_type=None):         #查找一条关系         #:param nodes: 要查找的结点集合,比如[起点,终点],这个参数可以没有         #:param r_type: 要查找的关系的类型         #:return:  None 或者 一条查询结果         #组合条件判断,以匹配相关match_one函数,并返回关系         if (nodes is None) and (r_type is None):             raise TypeError('nodes 和 r_type 必须有一个是非空')         elif (not (nodes is None)) and (not (r_type is None)):             return self.my_graph.match_one(nodes=nodes, r_type=r_type)         elif (not (nodes is None)) and (r_type is None):             return self.my_graph.match_one(nodes=nodes)         elif (nodes is None) and (not (r_type is None)):             return self.my_graph.match_one(r_type=r_type)     def findAllRelationship(self, nodes=None, r_type=None):         #查找多条关系         #:param nodes: 要查找的结点集合,比如[起点,终点],这个参数可以没有         #:param r_type: 要查找的关系的类型         #:return:  None 或者 多条查询结果组成的list         # 组合条件判断,以匹配相关match_one函数,并返回关系         if (nodes is None) and (r_type is None):             res = self.my_graph.match()             return list(res)             #raise TypeError('nodes 和 r_type 必须有一个是非空')         elif (not (nodes is None)) and (not (r_type is None)):             res = self.my_graph.match(nodes=nodes, r_type=r_type)             if res is None:                 return None             else:                 return list(res)         elif (not (nodes is None)) and (r_type is None):             res = self.my_graph.match(nodes=nodes)             if res is None:                 return None             else:                 return list(res)         elif (nodes is None) and (not (r_type is None)):             res = self.my_graph.match(r_type=r_type)             if res is None:                 return None             else:                 return list(res)     def isExist(self, node=None, relationship=None):         #判断节点和关系是否存在         #组合条件判断,返回节点和关系是否存在         if (node is None) and (relationship is None):             raise TypeError('要查询的 node 和 relationship 之中必须有一个存在值')         if (not (node is None)) and isinstance(node, Node):             return self.my_graph.exists(node)         elif (not (relationship is None)) and isinstance(relationship, Relationship):             return self.my_graph.exists(relationship)         else:             raise TypeError('要查询的 node 或 relationship 的类型并不是 Node 或 Relationship')     def deleteall(self):         #删除所有节点         self.my_graph.delete_all()     def delete(self, node=None, relationship=None):         #根据节点和关系进行删除         # 组合条件判断,返回节点和关系是否存在         if (node is None) and (relationship is None):             raise TypeError('要查询的 node 和 relationship 之中必须有一个存在值')         if (not (node is None)) and isinstance(node, Node):             return self.my_graph.delete(node)         elif (not (relationship is None)) and isinstance(relationship, Relationship):             return self.my_graph.delete(relationship)         else:             raise TypeError('要查询的 node 或 relationship 的类型并不是 Node 或 Relationship') if __name__ == '__main__':     dao = Neo4jDao(username='neo4j', password='Wbq197711')     dao.deleteall()     node1 = dao.createNode(label='WH',properties={
'name': 'test_node_1', 'ip': '10.*.*.1', 'servicename': 'XXX系统'})     node2 = dao.createNode(label='WH',properties={
'name': 'test_node_2', 'ip': '10.*.*.2', 'servicename': 'XXX系统'})     node3 = dao.createNode(label='WH',properties={
'name': "test_node_3', 'ip': '10.*.*.3', 'servicename': 'XXX系统'"})     relation = dao.createRelationship(start_node=node1, end_node=node2, relation_type='VISIT')     relation = dao.createRelationship(start_node=node2, end_node=node1, relation_type='VISIT')     relation = dao.createRelationship(start_node=node1, end_node=node3, relation_type='VISIT')     relation = dao.createRelationship(start_node=node2, end_node=node3, relation_type='VISIT',relation_properties={
'port':'8080'})     nodes=dao.findAllNode(node_type='WH')     print(nodes)     #[(_487:WH {ip: '10.*.*.1', name: 'test_node_1', servicename: 'XXX\u7cfb\u7edf'}),     # (_580:WH {name: "test_node_3', 'ip': '10.*.*.3', 'servicename': 'XXX\u7cfb\u7edf'"}),     # (_645:WH {ip: '10.*.*.2', name: 'test_node_2', servicename: 'XXX\u7cfb\u7edf'})]     node1=dao.findOneNode(node_type='WH')     print(node1)     #(_487:WH {ip: '10.*.*.1', name: 'test_node_1', servicename: 'XXX\u7cfb\u7edf'})     relations = dao.findAllRelationship()     print(relations)     #[(test_node_1)-[:VISIT {}]->(test_node_3', 'ip': '10.*.*.3', 'servicename': 'XXX系统'),     # (test_node_1)-[:VISIT {}]->(test_node_2),     # (test_node_2)-[:VISIT {port: '8080'}]->(test_node_3', 'ip': '10.*.*.3', 'servicename': 'XXX系统'),     # (test_node_2)-[:VISIT {}]->(test_node_1)]     relations=dao.findAllRelationship(r_type='VISIT')     print(relations)     #[(test_node_1)-[:VISIT {}]->(test_node_3', 'ip': '10.*.*.3', 'servicename': 'XXX系统'),     # (test_node_1)-[:VISIT {}]->(test_node_2),     # (test_node_2)-[:VISIT {port: '8080'}]->(test_node_3', 'ip': '10.*.*.3', 'servicename': 'XXX系统'),     # (test_node_2)-[:VISIT {}]->(test_node_1)]     relations = dao.findAllRelationship(nodes=[node1,node2])     print(relations)     #[(test_node_1)-[:VISIT {}]->(test_node_2)]     dao.delete(node1)     node1 = dao.findAllNode(node_type='WH')     print(node1)     #[(_580:WH {name: "test_node_3', 'ip': '10.*.*.3', 'servicename': 'XXX\u7cfb\u7edf'"}),     # (_645:WH {ip: '10.*.*.2', name: 'test_node_2', servicename: 'XXX\u7cfb\u7edf'})]
打开http://127.0.0.1:7474/browser/,运行 MATCH (n) RETURN n,即可返回以下图。

后续要完善的:

1、进一步封装,把节点和关系以类的方式封装

2、关于节点和关系的加载,以neo4j和py2neo方式进行加载

3、关于图库的展现问题

4、关于neo4j的高级语法,包括group,sort和计算

王老师的公众号为:追梦IT人,欢迎关注。

近期热文:

转载热文:

QQ群号:763628645

QQ群二维码如下, 添加请注明:姓名+地区+职位,否则不予通过

在看,让更多人看到

转载地址:https://jeanron100.blog.csdn.net/article/details/103249201 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:MySQL的主键命名挺任性,就这么定了
下一篇:医院门诊透视的生活万花筒

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2024年04月28日 00时19分19秒