前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于neo4j图数据库笔记二-py2neo使用

关于neo4j图数据库笔记二-py2neo使用

作者头像
python与大数据分析
发布2022-03-11 13:46:02
4840
发布2022-03-11 13:46:02
举报
文章被收录于专栏:python与大数据分析

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

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

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

代码语言:javascript
复制
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和计算

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-11-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 python与大数据分析 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
图数据库 KonisGraph
图数据库 KonisGraph(TencentDB for KonisGraph)是一种云端图数据库服务,基于腾讯在海量图数据上的实践经验,提供一站式海量图数据存储、管理、实时查询、计算、可视化分析能力;KonisGraph 支持属性图模型和 TinkerPop Gremlin 查询语言,能够帮助用户快速完成对图数据的建模、查询和可视化分析。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档