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

news/2024/12/22 14:56:20/

文章目录

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

背景描述

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

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

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

分析

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

解决

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

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

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

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

代码参考

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

neo4j__31">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.ppmy.cn/news/1452757.html

相关文章

[Linux][守护进程]详细讲解 + 自主实现

目录 0.预备知识1.守护进程概念2.进程组概念3.会话概念4.守护进程化的方式5.实现daemon() 0.预备知识 **前台进程:**和终端关联的进程任何一次会话,只允许有一个前台进程和多个后台进程守护进程不能直接向显示器打印消息,一旦打印&#xff0…

爱已无可救药

【爱的极限挑战】《爱已无可救药》—— 破晓前最暗的夜,恋人间最深的痴迷 在这个信息爆炸的时代,爱情故事千千万,但真正能触达心灵深处的,寥若晨星。《爱已无可救药》这部短剧,如同夜空中最耀眼的流星,划破…

Sqli-labs第一关到第四关

目录 一,了解PHP源代码 二,破解第一关 2.1在了解完源码之后,我们重点看一下 2.2破解这道题表中有几列 2.3查看表中哪一列有回显 2.4查询库,表,列信息 三,总结 前提: 之所以把1234关…

【算法系列】哈希表

目录 哈希表总结 leetcode题目 一、两数之和 二、判定是否互为字符重排 三、存在重复元素 四、存在重复元素 II 五、字母异位词分组 六、在长度2N的数组中找出重复N次的元素 七、两个数组的交集 八、两个数组的交集 II 九、两句话中的不常见单词 哈希表总结 1.存储数…

深度学习之基于Unet肺部CT图像分割项目

欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 肺部CT图像分割在医学诊断中占据重要地位,它有助于医生快速、准确地识别和分析肺部病变。…

【JAVA项目】基于SSM的【电动车智能充电服务平台】

技术简介:采用SSM技术、MYSQL等技术实现。 系统简介:电动车智能充电服务平台实现了首页、个人中心、用户管理、充电桩管理、电池商品管理、托送服务管理、我的钱包管理、充值信息管理、消费信息管理、购买订单管理、配送信息管理、服务订单管理、系统管理…

wordpress子比主题美化-为图文列表封面添加动态缩略图特效 多种效果演示

wordpress子比主题-为图文列表文章封面添加动态缩略图特效 给自己子比主题加一个列表文章封面添加动态缩略图 直接复制以下代码,添加到主题自定义CSS代码中即可,下图为效果演示 wordpress子比主题-为图文列表文章封面添加动态缩略图特效 给自己子比主题…

【后端】RabbitMQ的常见使用问题

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、RabbitMQ 常见问题二、RabbitMQ 常见报错三、总结 前言 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很…