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'})]复制
后续要完善的:
1、进一步封装,把节点和关系以类的方式封装
2、关于节点和关系的加载,以neo4j和py2neo方式进行加载
3、关于图库的展现问题
4、关于neo4j的高级语法,包括group,sort和计算
文章转载自python与大数据分析,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
相关阅读
喜报!华为云GES完成中国信通院图数据库产品测试
数据库应用创新实验室
321次阅读
2025-03-21 10:02:38
全国首部图数据库国家标准发布!达梦数据深度参与!
达梦数据
140次阅读
2025-04-02 09:34:13
萌新轻松上手 NebulaGraph 的三种方案
严少安
96次阅读
2025-03-18 18:23:30
2025w11 | 图数据库了解一下
严少安
76次阅读
2025-03-21 16:51:24
多维解读丨悦数图数据库助力互联网金融风控再升级
悦数图数据库
39次阅读
2025-03-18 10:49:52
诡异宕机,为何分区表会匹配到错误的表名?
爱可生开源社区
37次阅读
2025-03-25 10:37:40
PostgreSQL逻辑复制槽功能
AustinDatabases
32次阅读
2025-03-18 10:45:59
图查询语言GQL(Graph Query Language)语法概览
蜉蝣与海
31次阅读
2025-04-01 15:06:06
mysql分表后用pt-table-checksum检查数据一致性方法
qtiger
30次阅读
2025-03-19 11:21:03
GB/T 45346-2025《信息技术 图数据库管理系统技术要求》国家标准正式发布
数据库标准工作组
29次阅读
2025-03-14 16:49:56