neo4j 的插入速度为什么越来越慢,可能是使用了过多图谱查询操作

文章目录

    • 背景描述
    • 分析
    • 解决
    • 代码参考
    • neo4j 工具类
      • Neo4jDriver
      • 知识图谱构建效果
      • GuihuaNeo4jClass

背景描述

使用 tqdm 显示,处理的速度;

笔者使用 py2neo库,调用 neo4j 的API 完成节点插入;
有80万条数据需要插入到neo4j图数据中,在前期处理速度200条每秒,随着程序的运行处理速度越来越慢,200 -> 100 -> 50 -> 30,速度一直降低到每秒处理30条数据;

如果保持原来的速度,1个小时就处理完了,现在就得花费8个小时才能处理完成;

分析

那么到底是什么原因导致速度会越来越慢?
笔者分析之后是因为:笔者会给节点创建关系,首先需要在neo4j图数据库中查询到该节点,再给该节点创建关系。随着图数据库中的节点数量越来越多,就导致查询时间过长,从而形成了随着程序运行插入节点速度变慢的现象。

解决

有很多种办法解决这个问题:

  • 记忆背包
    采用记忆背包的办法,将已经创建过的节点,保存在字典中。再给该节点创建关系或者属性时,不再从图谱中查询,而是直接从字典中获取;

  • 减少重复查询操作
    尽量减少多次重复的查询操作。
    假如有一个实体的属性表、有一个关系表;为了保证代码的低耦合,通常咱们先往知识图谱中,插入完成属性表;再查询节点,再给该实体插入关系。很明显第二次的节点查询就是重复的查询。
    完全可以考虑,一次性就完成节点属性添加和关系链接操作,这就能减少了一次查询操作;

  • 是否需要创建新实体
    通常创建实体时,先在图谱中查询是否有该节点,如果图谱中有则不创建,使用查询得到的节点;
    如果咱们只是想表示某个节点他有哪些关系,那么节点不唯一也可以考虑,那么便不再理会图谱中是否已有该节点,直接创建该节点,然后建立关系即可。

代码参考

我使用下述代码,一次性完成属性添加、孩子节点创建与关系链接;从而实现减少图谱的查询操作;
实现了将原本需要耗费8个小时以上的时间,缩短到2个小时完成neo4j图数据库的插入;

neo4j 工具类

我写的neo4j 工具类如下

  • Neo4jDriver: 可以直接拿去使用;
  • GuihuaNeo4jClass: 笔者自己项目的一个类,无法直接供大家使用,供大家参考;

Neo4jDriver

import json
from dataclasses import dataclassfrom py2neo import Graph, Node, NodeMatcher, RelationshipMatcher, Relationshipfrom settings import domain_class_name, summary_class_name, ner_schema# 连接到Neo4j数据库
class Neo4jDriver:def __init__(self, url, username, password):self.graph = Graph(url, auth=(username, password))self.node_matcher = NodeMatcher(self.graph)self.relationship_matcher = RelationshipMatcher(self.graph)def query_node(self, class_, **kwargs):if node := self.node_matcher.match(class_, **kwargs):# 节点存在,则获取return node.first()def create_query_node(self, class_, **kwargs):"""不创建重复节点"""# 节点存在,则获取if node := self.query_node(class_, **kwargs):return node# 节点不存在,则创建node = Node(class_, **kwargs)self.graph.create(node)return nodedef create_node(self, class_, **kwargs):node = Node(class_, **kwargs)self.graph.create(node)return nodedef query_relationship(self, start_node, rel, end_node):r = self.relationship_matcher.match([start_node, end_node], r_type=rel)return r.first()def create_query_relationship(self, start_node, rel, end_node):if r := self.query_relationship(start_node, rel, end_node):return rself.graph.create(Relationship(start_node, rel, end_node))def create_relationship(self, start_node, rel, end_node):self.graph.create(Relationship(start_node, rel, end_node))

知识图谱构建效果

请添加图片描述上图的schema如下:

保山市: file
加快建...是:sentence
最右侧的一列节点是sentence的下面的实体

GuihuaNeo4jClass

简要给大家分享一下,编写GuihuaNeo4jClass的思路:

all_file_node = {}
all_sents_node = {}
all_ner_node = {} # key: (ner_class, name)

如下字典为所有 GuihuaNeo4jClass 实例共有(都可以访问)的字典,用于存储在构建neo4j的过程中,创建的一些节点,这样就无需走neo4j的查询,直接走本地字典的查询,速度会快一点;

下述为创建GuihuaNeo4jClass类,初始化时,需要传入的一些参数:

driver: Neo4jDriver
text: str
prov: str
city: str
filename: str

方法讲解:
get_file_node

def get_file_node(self):# 首先在self.all_file_node,查询是否已经有该节点,如果有则直接从字典获取该节点if self.filename in self.all_file_node.keys():return self.all_file_node[self.filename]# 字典中没有该节点,表示该节点还没有创建过,准备创建该节点# data 字典里面存储的是该节点的一些属性信息data = {"name": self.filename, "prov": self.prov, "city": self.city}self.file_node = self.driver.create_node("file", **data)# 新节点创建完成,将该节点保存到 GuihuaNeo4jClass 的文件字典 self.all_file_node中;# self.all_file_node 是每个实例共享的一个类字典;self.all_file_node[self.filename] = self.file_nodereturn self.file_node

get_sentence_node: 与get_file_node 类似;
add_class: 创建sentence节点,并创建 file -> sentence的关系;
add_ner: 创建在schema定义的一些实体节点,并创建 sentence -> ner_node 的关系;

@dataclass()
class GuihuaNeo4jClass:all_file_node = {}all_sents_node = {}all_ner_node = {} # key: (ner_class, name)driver: Neo4jDrivertext: strprov: strcity: strfilename: strdef get_file_node(self):if self.filename in self.all_file_node.keys():return self.all_file_node[self.filename]data = {"name": self.filename, "prov": self.prov, "city": self.city}self.file_node = self.driver.create_node("file", **data)# saveself.all_file_node[self.filename] = self.file_nodereturn self.file_nodedef get_sentence_node(self, **kwargs):if self.text in self.all_sents_node.keys():return self.all_sents_node[self.text]for key in kwargs.keys():assert key in [domain_class_name, summary_class_name]data = {"sentence": self.text,}data.update(kwargs)node = self.driver.create_node("sentence", **data)self.sent_node = node# saveself.all_sents_node[self.text] = self.sent_nodereturn self.sent_nodedef add_class(self, domain_info, summary_info):self.file_node = self.get_file_node()# 给file下面添加text, rel: has_reldomain_output = domain_info.outputs[0].textsummary_output = summary_info.outputs[0].textclass_data = {domain_class_name: domain_output,summary_class_name: summary_output,}self.sent_node = self.get_sentence_node(**class_data)self.driver.create_relationship(self.file_node, "has_sentence", self.sent_node)def add_ner(self, ner_info):"""给文本句创建节点建立一个静态的 llm_ner_label"""try:llm_ner_label = ner_info.outputs[0].textllm_ner_label = json.loads(llm_ner_label)except:returnif not isinstance(llm_ner_label, dict):returnfor key, values in llm_ner_label.items():if not key in ner_schema:continuefor name in values:if (key, name) in self.all_ner_node.keys():ner_node = self.all_ner_node[(key, name)]else:ner_node = self.driver.create_node(key, name=name)# saveself.all_ner_node[(key, name)] = ner_nodeself.driver.create_relationship(self.sent_node, 'has_ner', ner_node)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/319343.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手机恢复出厂设置ip地址会变吗

当我们对手机进行恢复出厂设置时,很多人会担心手机的IP地址是否会发生变化。IP地址对于手机的网络连接至关重要,它决定了手机在网络中的身份和位置。那么,手机恢复出厂设置后,IP地址到底会不会发生变化呢?虎观代理小二…

华为鸿蒙系统(Huawei HarmonyOS)

华为鸿蒙系统(华为技术有限公司开发的分布式操作系统) 华为鸿蒙系统(HUAWEI HarmonyOS),是华为公司在2019年8月9日于东莞举行的华为开发者大会(HDC.2019)上正式发布的分布式操作系统。 华为鸿蒙…

进程控制【Linux】

文章目录 进程终止进程等待 创建一批子进程 #include <stdio.h> #include <unistd.h> #include <stdlib.h> #define N 5void runChild() {int cnt 10;while (cnt ! 0){printf("i am a child : %d , ppid:%d\n", getpid(), getppid());sleep(1);c…

MySQL:飞腾2000+Centos7.6 aarch64 部署MySQL8.0.36

目录 1.硬件环境 2.MySQL选择 Bundle版本【全部文件】​编辑 3.下载并安装 4.安装完成后检查mysql 5.初始化MySQL 6.那就问了&#xff0c;都初始化了啥&#xff1f; 7.尝试启动MySQL 8.给mysql文件授权 9.再次尝试启动正常 10.mysql初始化目录出现了mysql.sock 11.找…

buuctf-misc-30.被劫持的神秘礼物1

30.被劫持的神秘礼物1 题目&#xff1a;http数据流追踪&#xff0c;MD5哈希一下账户名和密码 MD5在线加密/解密/破解—MD5在线 (sojson.com)

C语言 | Leetcode C语言题解之第61题旋转链表

题目&#xff1a; 题解&#xff1a; struct ListNode* rotateRight(struct ListNode* head, int k) {if (k 0 || head NULL || head->next NULL) {return head;}int n 1;struct ListNode* iter head;while (iter->next ! NULL) {iter iter->next;n;}int add n…

NASA数据集——NOAA 气溶胶和海洋科学考察数据(AEROSE)

Saharan Dust AERosols and Ocean Science Expeditions 简介 NOAA 气溶胶和海洋科学考察&#xff08;AEROSE&#xff09;是一种基于测量的综合方法&#xff0c;用于了解热带海洋上空气溶胶长程飘移的影响&#xff08;Morris 等人&#xff0c;2006 年&#xff1b;Nalli 等人&a…

GitHub显示无法在此仓库中合并不相关的历史记录

你好,我是Qiuner. 为记录自己编程学习过程和帮助别人少走弯路而写博客 这是我的 github gitee 如果本篇文章帮到了你 不妨点个赞吧~ 我会很高兴的 &#x1f604; (^ ~ ^) 想看更多 那就点个关注吧 我会尽力带来有趣的内容 GitHub显示无法在此仓库中合并不相关的历史记录 场景&…

C++初阶之模板初阶

一、泛型编程 如何实现一个通用的交换函数呢&#xff1f; void Swap(int& left, int& right) {int temp left;left right;right temp; } void Swap(double& left, double& right) {double temp left;left right;right temp; } void Swap(char& left,…

分类规则挖掘(一)

目录 一、分类问题概述&#xff08;一&#xff09;分类规则挖掘&#xff08;二&#xff09;分类规则评估&#xff08;三&#xff09;分类规则应用 二、k-最近邻分类法 一、分类问题概述 动物分类&#xff1a;设有动物学家陪小朋友林中散步&#xff0c;若有动物突然从小朋友身边…

详解SDRAM基本原理以及FPGA实现读写控制(一)

文章目录 一、SDRAM简介二、SDRAM存取结构以及原理2.1 BANK以及存储单元结构2.2 功能框图2.3 SDRAM速度等级以及容量计算 三、SDRAM操作命令3.1 禁止命令&#xff1a; 4b1xxx3.2 空操作命令&#xff1a;4b01113.3 激活命令&#xff1a;4b00113.4 读命令&#xff1a;4b01013.5 写…

llama_index微调BGE模型

微调模型是为了让模型在特殊领域表现良好,帮助其学习到专业术语等。 本文采用llama_index框架微调BGE模型,跑通整个流程,并学习模型微调的方法。 已开源:https://github.com/stay-leave/enhance_llm 一、环境准备 Linux环境,GPU L20 48G,Python3.8.10。 pip该库即可。…

新型直膨式光伏光热热泵/动力热管复合循环系统

太阳能光伏光热热泵&#xff08;即PVT热泵&#xff09;技术是建筑领域内实现碳中和的有效技术手段&#xff0c;该技术具有优越的热电冷联产能力。然而&#xff0c;现有的PVT热泵在良好的室外工况下能耗较高。为了解决这一问题&#xff0c;本文提出了一种新型的DX-PVT热泵/动力热…

【c++】模板编程解密:C++中的特化、实例化和分离编译

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本篇文章我们来学习模版的进阶部分 目录 1.非类型模版参数按需实例化 2.模版的特化函数模版特化函数模版的特化类模版全特化偏特化 3.分离编译模版分离编译 1.非类…

ubuntu搭建kms服务器

1.下载kms开源包(如果提示找不到wget命令的话:apt install wget): wget https://github.com/Wind4/vlmcsd/releases/download/svn1111/binaries.tar.gz2.解压: tar -xzvf binaries.tar.gz接着cd 进入 Linux/intel/static/ 文件夹下: 3.选择对应的文件&#xff0c;这里我们选…

力扣每日一题104:二叉树的最大深度

题目 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3示例 2&#xff1a; 输入&#xff1a;root [1,null,2…

OpenCV(二)—— 车牌定位

从本篇文章开始我们进入 OpenCV 的 Demo 实战。首先&#xff0c;我们会用接下来的三篇文章介绍车牌识别 Demo。 1、概述 识别图片中的车牌号码需要经过三步&#xff1a; 车牌定位&#xff1a;从整张图片中识别出牌照&#xff0c;主要操作包括对原图进行预处理、把车牌从整图…

飞书API(7):MySQL 入库通用版本

一、引入 在上一篇介绍了如何使用 pandas 处理飞书接口返回的数据&#xff0c;并将处理好的数据入库。最终的代码拓展性太差&#xff0c;本篇来探讨下如何使得上一篇的最终代码拓展性更好&#xff01;为什么上一篇的代码拓展性太差呢&#xff1f;我总结了几点&#xff1a; 列…

Ubuntu编译安装MariaDB并进行初始化配置

Ubuntu编译安装MariaDB并进行初始化配置 1. 编译安装MariaDB2. 配置MariaDB3. Docker安装MariaDB 1. 编译安装MariaDB MariaDB官方安装文档&#xff1a;https://mariadb.com/kb/en/Build_Environment_Setup_for_Linux/    下载MariaDB源码&#xff1a;https://mariadb.org/ma…

022、Python+fastapi,第一个Python项目走向第22步:ubuntu 24.04 docker 安装mysql8集群、redis集群(三)

这次来安装mysql8了&#xff0c;以前安装不是docker安装&#xff0c;这个我也是第一次&#xff0c;人人都有第一次嚒 前言 前面的redis安装还是花了点时间的&#xff0c;主要是网上教程&#xff0c;各有各的好&#xff0c;大家千万别取其长处&#xff0c;个人觉得这个环境影响…