求助,节点与关系的批量创建优化 (java)
发布于 3 年前 作者 neo4jsibalaxi 560 次浏览 来自 问答

Neo4j相关环境配置

Neo4j建立在虚拟机上的,给虚拟机分了4G内存 Neo4j版本:4.1.5 Community neo4j的堆内存配置:

dbms.memory.heap.initial_size=2048M
dbms.memory.heap.max_size=2048M

硬盘: 固态硬盘

总数据量

节点总数:5400+ 关系总数:12000+

思路:

数据量不是很大,但是数据来源mysql,里边儿的数据不能直接用,需要经过一些处理。所以没有用import从mysql直接导入到Neo4j,所以想着一个一个create,于是有了以下两个方案。

方案一:

利用Spring-Data Neo4j,根据业务逻辑,节点与关系一个一个save的形式创建节点与关系。当时为了避免重复创建,过程中还包含某些节点的查询类似findByName(String name)这种。 耗时基本在1分半的样子,磁盘写入大概在1.7M/s

因为最近闲着没事儿,觉得这种方法就是大家普遍说的低效的方式:每一个更新都通过一个Transaction发送一个请求 虽然量不大,但是本着探索的精神开始在网上搜罗方法。然后我就找到了一篇关于批量插入优化的文章,再加上俞博士的实现复杂和高性能的图遍历优化分享开始倒腾起了方案二

方案二:


// 节点插入
CALL apoc.periodic.iterate("UNWIND [jsonArray] as row return row" ,  
                                      "create (n: label1{name:row.name}) " , 
									  {batchSize: 300, parallel: false , iterateList:true});
// 关系插入,关系的json包含from节点和to节点,还有同层的关系属性
CALL apoc.periodic.iterate("UNWIND [jsonArray] as re return re" ,  
                                      "match (from: label1{name:re.from.name}), (to:label2{name:re.to.name}) merge (from)-[:Re{name:re.name, time:re.time}]->(to) " , 
									  {batchSize: 300, parallel: false , iterateList:true});

主要采用的是如上方法,为了保证结构的一致性,先初始化节点,再初始化关系,通过UNWIND一个特别大的JSON数组作为apoc.periodic.iterate()的数据源——cypherIterate做批量插入,不用频繁提交事务变得更快。 但是事实好像并非如此,我也不知道哪里出了问题,这么做会占满虚拟机的cpu,磁盘的写入也很诡异,大部分都在几十或几百kb的样子。总共耗时大概在30分钟的样子。 刚学习Neo4j不久,这个地方暂时不知道怎么优化了,如果有帅气无比的神仙帮忙指点迷津,我定会痛哭流涕,感激不尽,Skr!

回到顶部