基于python3.11将postgresql-15的表结构维护到neo4j-5.8.1

问题背景

  • 数据库表的相互依赖关系复杂,重构不知道怎么追踪
  • 有些业务需要通过图数据库来完成,通过库表将技术落地
  • 熟悉一下postgresql数据库
  • 体验一下高版本python的一些工具包的新特性
  • 了解neo4j的一些特新

实现逻辑

读取配置文件工具类

import yaml
import os

os.chdir(os.path.dirname(__file__))
# 读取服务的配置文件
def get_config(yaml_file="service.yaml") -> dict:
    with open(yaml_file, 'r') as file:
        data = file.read()
        result = yaml.load(data, Loader=yaml.FullLoader)
        return result

其中的service.yaml文件中定义数据库表的账号信息:

demo:
  db:
    postgresql:
      user: 您设置的账号
      password:您设置的密码
      port: 您设置的端口
      host: 您的postgresql的服务器地址
      db: postgres
    neo4j:
        user: neo4j的用户名
        password: neo4j的登录密码
        uri: neo4j的地址

postgresql数据库连接工具类

import os

from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker

from common import ConfigHelper

class PostgresqlHelper(object):
    def __init__(self):
        self.db_type = "postgresql"
        self.config = ConfigHelper.get_config()['demo']

    def get_config(self):
        return self.config

    # 获取数据库连接引擎
    def get_db_engine(self):
        db_json = self.config["db"][self.db_type]
        engine = create_engine(
            'postgresql://{}:{}@{}:{}/{}'.format(db_json['user'], db_json['password'],
                                                 db_json['host'], db_json['port'],
                                                 db_json['db']), echo=False)
        return engine

    def get_db_connect(self):
        return self.get_db_engine().connect()

    # 获取session会话
    def get_session(self) -> Session:
        db_session = sessionmaker(bind=self.get_db_engine(), future=True)
        return db_session()

上述的工具类,通过sqlalchemy这个orm工具包完成对数据库的连接,方便后面对数据库表的操作。如果大家还不知道怎么安装postgresql数据库,可以查看基于Centos7系统安装postgresql-15(简单操作)这一篇,操作简单。

neo4j图数据库操作的工具类

from py2neo import Graph, Node, Relationship, NodeMatcher, RelationshipMatcher

from common import ConfigHelper


class Neo4jHelper(object):
    """
    实现Neo4j数据库连接功能,具体实现由实现者自行选择。
    实现时应尽可能避免使用外部库中的连接库,而是将其他方法(例如执行SQL查询、连接到外部库等)用于外部库。
    这些方法负责创建和使用连接,而不是从实现者自行选择。
    """

    def __init__(self):
        config_json = ConfigHelper.get_config()['demo']["db"]["neo4j"]
        self.graph = Graph(config_json["uri"], auth=(config_json["user"], config_json["password"]))
        self.node_matcher = NodeMatcher(self.graph)
        self.relationship_matcher = RelationshipMatcher(self.graph)

    def create_node(self, label, name, data):
        """
        创建一个节点,具有指定的label和数据
        :param label: 要创建的节点类型
        :param name: 要创建的节点的名称
        :param data: 要创建的节点的数据(不包含name,也就是节点的名称)
        :return:
        """
        node = Node(label, name=name, **data)
        self.graph.create(node)
        return node

    def create_rel(self, start_node, end_node, type_, data):
        """
        创建一个关系,具有指定的类型和数据
        :param start_node: 要创建的关系的起始节点
        :param end_node: 要创建的关系的结束节点
        :param type_: 要创建的关系的类型
        :param data: 要创建的关系的数据
        :return:
        """
        return self.graph.create(Relationship(start_node, type_, end_node, **data))

    def find_node(self, label: str, properties: dict):
        """
        寻找一个节点,具有指定的类型和条件的数据
        :param label: 要寻找的节点的类型
        :param properties: 要寻找的节点的条件数据
        :return:
        """
        nodes = list(self.node_matcher.match(label, **properties))
        return nodes

    def find_relationship(self, rel_type, properties):
        """
        寻找一个关系,具有指定的类型和条件的数据
        :param rel_type: 要寻找的关系的类型
        :param properties: 要寻找的关系的条件数据
        :return:
        """
        relationships = list(self.relationship_matcher.match(r_type=rel_type, **properties))
        return relationships

    def update_node(self, node, **properties):
        """
        更新一个节点,具有指定的类型和条件的数据
        :param node: 要更新的节点
        :param properties: 要更新的节点的条件数据
        :return:
        """
        for key, value in properties.items():
            node[key] = value
        self.graph.push(node)

    def delete_node(self, node):
        """
        删除一个节点
        :param node: 要删除的节点
        :return:
        """
        incoming_rels = self.relationship_matcher.match(nodes=[node], r_type=None)
        outgoing_rels = self.relationship_matcher.match(nodes=None, r_type=None, end_node=node)

        for rel in incoming_rels:
            self.graph.separate(rel)
        for rel in outgoing_rels:
            self.graph.separate(rel)

        # Delete the node
        self.graph.delete(node)

    def delete_relationship(self, relationship):
        """
        删除一个关系
        :param relationship: 要删除的关系
        :return:
        """
        self.graph.separate(relationship)

上述代码通过py2neo这个工具包实现了对图数据库的增删改查逻辑的实现。当然如果大家对neo4j数据库的安装不熟悉,或者安装不顺利,可以参考一下Centos7在线安装neo4j-5.6.0这一篇,简单易懂。

业务逻辑实现

import json

from sqlalchemy import inspect

from common.Neo4jHelper import Neo4jHelper
from common.PostgresqlHelper import PostgresqlHelper

if __name__ == '__main__':
    db = PostgresqlHelper()
    eng = db.get_db_engine()
    inspector = inspect(eng)
    # 需要建立图关系的表(课程表,得分表,学生表)
    table_name_list = ["course", "score", "user"]
    schema_name = "new_browser"
    # 表的基本信息(描述)
    data = {
    
    }
    for t in table_name_list:
        table_data = {
    
    }
        comment = inspector.get_table_comment(table_name=t, schema=schema_name)
        table_data["comment"] = comment["text"]
        columns = inspector.get_columns(table_name=t, schema=schema_name)
        columns_info = {
    
    }
        for column in columns:
            columns_info[column['name']] = str(column['type'])
        table_data["columns_info"] = json.dumps(columns_info)
        data[t] = table_data
    app = Neo4jHelper()
    label = "Table"
    node_data = {
    
    }
    for t in table_name_list:
        # 创建表的节点
        table_comment = data[t]["comment"]
        node_data[t] = app.create_node(name=f"{
      
      t}({
      
      table_comment})", label=label, data=data[t])
    # 创建关系
    app.create_rel(node_data["score"], node_data["user"], "user_name", {
    
    "info": "学生的名称依赖与学生表"})
    app.create_rel(node_data["score"], node_data["course"], "course_name", {
    
    "info": "课程名称依赖于课程表"})

上面的代码主要是通过sqlalchemy获取表的结构信息,作为图数据库的节点的信息,表名+表注释作为节点的name,上述通过psql中的三张表(学生信息表、课程信息表和得分信息表)之间的关系,给图数据库中的节点之间创建关系。因为三张都是数据库表,所以节点的label为“Table”,节点信息中包含所含的字段信息(包括类型),大家也可以按照自己的需要保存自己想要的信息,运行的结果,在Neo4j Desktop中查看:

在这里插入图片描述

可以看出得分表中的用户信息、课程信息分别与用户表和课程表对应,点击对应的节点,可以查看节点的详细信息:

在这里插入图片描述

点击考试成绩表,可以看到对应的column_info、comment、name的信息。整个开发工程结束了,大家可以下载我的完整代码。希望大家多多交流!

猜你喜欢

转载自blog.csdn.net/longaili520/article/details/130833123
今日推荐