一.从关系数据库加载

1.描述:

在项目中,我们加载数据是从关系数据库中(mysql)抽取相关数据,通过jdbc的方式导入neo4j,如果数据源为非关系型数据库,我们也会通过脚本清洗成关系数据库的样式,然后统一从mysql导入neo4j,当然也可以从neo4j所支持的其他关系数据库进行数据集成,我们项目开始时用pg,后来转成了MySQL,下面内容也以MySQL为主。

2.安装方式:

在neo4j通过apoc jdbc连接导入数据,在这里需要加载两个jar包,一个是neo4j 的apoc库,另一个是MySQL的驱动。neo4j的apoc库集成了很多函数和过程,可以帮助完成数据集成、图形算法或数据转换等领域的许多不同任务。建议收藏网址:https://neo4j.com/labs/apoc/4.3/introduction/,后面会出章节来详细描述在实际项目apoc经常使用的语法。

需要在neo4j的plugin文件下,放入相应的jar包,通用的jdbc的jar包即可,可以去官网下载。

(1)mysql驱动

在MySQL官网下载:https://dev.mysql.com/downloads/connector/j/

下载zip包之后解压:取出里面的jar包,放在neo4j的plugin文件下:

neo4j 与MySQL转化_jar包

(2)apoc库安装

neo4j 与MySQL转化_jar包_02

 

 需根据neo4不同的版本下载对应版本的apoc库,我们这里用的是3.5x的neo4j,所以下载的是3.5.0.11的apoc,同样也是放在neo4j的plugin文件下:下载网址:https://github.com/neo4j-contrib/neo4j-apoc-procedures/releases/3.5.0.11

neo4j 与MySQL转化_neo4j 与MySQL转化_03

 

neo4j 与MySQL转化_neo4j 与MySQL转化_04

 下载完后,重启neo4j 即可

3.实操见真知

描述:建立实体一:学生Student, 实体二:科目Course,两者关系为选修:ELECTIVE

注意:一般实体是驼峰命名,然后关系名为全部大写,多个词汇则用_连接,如:PART_OF

(1)为了使加载更快,建议先在neo4j进行索引建立,这样在加载数据,尤其是量大的数据,比不加索引快的非常多,如之前项目有个几十万数据的实体导入,如果没加索引,可能要半小时左右,但是加了索引就几分钟内就完成了。

create index on :Course(id);
create index on :Student(id)

(2) 在mysql建立数据表,在项目中,我们写了自动导入neo4j的python脚本,我们对于实体和关系表在mysql有指定的规范,如实体表是以类型名命名,然后单独一张表,关系表,一般为两个实体的关联的id字段,因为实际中,我们的数据开始是从不同的局点采集到的,而且不同局点所用的时间基本是当地服务器的时间,而且我们有实时入图以及周期脚本入图的方案设计,所以在关系表上,如果是有实时入图的数据,我们需要加上update_time和source字段(后面会出实时与周期方案设计的章节,后面可以详细看下这一章节,这里不展开说)。

(2.1)实体数据

mysql数据:

neo4j 与MySQL转化_neo4j 与MySQL转化_05

 

执行语句:

WITH "jdbc:mysql://localhost:3306/neo4j?user=root&password=123456" as connstr //mysql连接串

WITH 'select * from student' as query,connstr //select 语句

CALL apoc.periodic.iterate(//CALL apoc.periodic.iterate 批量提交,如果数据很大,建议使用批量提交
"call apoc.load.jdbc($connstr,$query) yield row",
//将mysql中的每一行行记录映射成map,value值为null的赋值为""空字符串,在mysql进来的连接id最好不要null值进来,尤其在建立关系时,不然到时候建立关系时,如果为null值,会将该实体类型下所有实体关联,造成错误
'with apoc.map.fromPairs([key in keys(row)|[key,case row[key] when null then "" else trim(toString(row[key]))end]]) as row
merge (n:Student{id:row.id}) set n=row
',
{batchSize:1000,//batchSize 每1000个提交依次,可根据自己的需求设置
params:{connstr:connstr,query:query}}
//params:{connstr:connstr,query:query} 传参,apoc.periodic.iterate才可引用
)yield batch,operations return  batch,operations

执行结果:

neo4j 与MySQL转化_neo4j_06

 (2.2)关系数据

mysql数据:

neo4j 与MySQL转化_neo4j 与MySQL转化_07

执行语句:

//mysql连接串
WITH "jdbc:mysql://localhost:3306/neo4j?user=root&password=123456" as connstr
//select 语句
WITH 'select * from student_course_rlt' as query,connstr
//CALL apoc.periodic.iterate 批量提交,如果数据很大,建议使用批量提交
CALL apoc.periodic.iterate(
"call apoc.load.jdbc($connstr,$query) yield row",
//将mysql中的每一行行记录映射成map,value值为null的赋值为""空字符串,在mysql进来的连接id最好不要null值进来,尤其在建立关系时,不然到时候建立关系时,如果为null值,会将该实体类型下所有实体关联,造成错误
'with apoc.map.fromPairs([key in keys(row)|[key,case row[key] when null then "" else trim(toString(row[key]))end]]) as row
match (n:Student{id:row.student_id}),(m:Course{id:row.course_id}) 
merge (n)-[r:ELECTIVE]->(m) set r=row
',
//batchSize 每1000个提交依次,可根据自己的需求设置
//params:{connstr:connstr,query:query} 传参,apoc.periodic.iterate才可引用
{batchSize:1000,params:{connstr:connstr,query:query}}
)yield batch,operations return  batch,operations

执行结果为:

 

neo4j 与MySQL转化_neo4j 与MySQL转化_08

二.在代码中拉取数据加载:

1.描述:

在实际项目中除了从关系数据库取的数据,有时候是从别人的接口,或者是消息获得的数据,如果不想经过数据库落地,想直接拉到数据后,直接批量入图。在项目中,我们用的是spring boot框架与neo4j整合,这里插播一段痛苦又很有成就感的经历,不想看的可以跳过:从没经验,对neo4j毫无了解到一步步实现上线需求,中间踩过很多坑,有时候觉得过不了了,但还是坚持下来,与团队一起克服,第一次引用了一个jar包,比较老的与neo4j的jar包,第一版代码的框架是从git下面参考的,运行时可以的,但是工程启动久了,如果多并发的话,运行时间久的话,就会报session的错,试过很多方法,都是不行,我觉得不应该会这么不成熟,就换了一个新的jar包,这个错误就好了,有时候就是这么不可思议,哈哈,但是引入jar包后,我们采取的是bean 的session,这个时候也会遇到一个问题时,如果是有个接口占用这个session太长时间的话,会影响其他接口的性能,甚至,这个接口查询neo4j过长时间,直接这个session就会抛错误,导致整个包必须重启,所以当时我们解决这个局面,是在写cypher的时候尽量优化,执行时间尽量缩短,长cypher如果没有性能要求,就分段执行,确保每个接口或者任务都能尽量短时间完成,避免占用session,但这个只能是临时方案,后面,通过采取配置transactionConfig 以及 driver config较好的解决这个问题,实现了查询超过指定时间,session关闭,并且不占用同个session,不同session接口不会相互占用,效果还是很好,这个具体配置什么的,可以见下文。

2.安装方式:

待续。。。。。。