Neo4j是一个开源图数据库,使用Python语言访问Neo4j可以使用Py2neo。本文介绍如何使用Py2neo访问Neo4j,批量创建节点和关系。Py2neo提供了直接执行Cypher语句的方法,同时也提供了Node、Relationship、Path等一系列数据结构,可以在不同场景下灵活使用。本文使用的py2neo是2021.1之后的版本。手册请点这里:ThePy2neoHandbookInstallPy2neo使用pip安装Py2neo,执行:pipinstallpy2neo查看安装的是什么版本的Py2neo:pipshowpy2neoName:py2neoVersion:2021.1.5Summary:PythonclientlibraryandtoolkitforNeo4jHome-页面:https://py2neo.org/连接Neo4j数据库本文会用到各种数据类型,importnumpyasnpimportpandasaspdfrompy2neoimportNode,Relationship,Graph,Path,Subgraph配置访问地址,userNeo4j数据库的名称和密码neo4j_url='http://localhost:7474/'user='neo4j'pwd='admin'2021.1之前访问数据库的方式是:graph=Graph(neo4j_url,username=user,password=pwd)2021.1之后访问数据库的方式是(这就是不兼容的原因):graph=Graph(neo4j_url,auth=(user,pwd))1.使用graph.run执行Cypher语句创建节点如果你熟悉使用Cypher语句,你可以使用graph.run来执行Cypherstatements创建节点等操作。方法如下:cypher_="CREATE(:Person{name:'王王',age:35,work:'宇宙电子厂'}),\(:Person{name:'李李',age:20,work:'万能电子厂'})"graph.run(cypher_)这样在Neo4j中为Person节点创建了两个标签,第一个节点的name属性为“旺旺”,age属性为35,工作属性为“万能电子厂”,第二个节点的姓名属性为“李丽”,年龄属性为20,工作属性为“万能电子厂”。同样,可以通过调用graph.run来执行Cypher语句来创建关系。cypher_="MATCH(from:Person{name:'王王'}),\(to:Person{name:'李李'})MERGE(from)-[r:colleague]->(to)"graph.run(cypher_)这样在Neo4j中就有了两个具有同事关系的Person节点。2.使用Node数据结构创建节点Py2neo也提供了graph.create方法创建节点和关系node=Node("Person",name="李李",age=20,work="万能电子厂")graph.create(node)与执行Cypher语句效果相同,在Neo4j中创建了一个Person节点。需要注意的是,如果重复执行这两种创建方法,会在Neo4j中创建重复的节点,即多个节点的name、age、work属性完全相同,但在Neo4j中的id不同。3.使用节点、关系和子图数据结构来创建节点和关系。以上两种方法一次创建一个节点或一个关系。Py2neo还提供了一种批量创建节点和关系的方法,性能更好。我们以下图中的图为例,使用Py2neo提供Node、Relationship和Subgraph数据结构,在Neo4j中创建节点和关系。首先创建一些标签为Person的节点,即Node对象。第一个参数是label,属性按照key=value作为参数传入。如果节点有多个标签,您可以使用Node.add_label("label_text")附加标签。node1=Node("人",name="王王",age=35,work="宇宙电子厂")node2=Node("人",name="李李",age=20,work="宇宙电子厂")node3=Node("人",name="张张",age=30,work="万能电子厂")node4=Node("人",name="赵赵",age=45,work="月亮中学")node4.add_label("老师")node5=Node("人",name="刘刘",age=20,work="地球电商公司")并为LocationNodenode6=Node("Location",name="南京")node7=Node("Location",name="江宁区")node8=Node("Location",name="禄口机场")创建一些Person而Person节点之间的关系,Neo4j中的关系是有方向的,所以Relationship的第一个参数是起始节点,第三个参数是结束节点,第二个节点是关系的类型。这里营造的同事与邻里关系是双向的,师生关系是单向的。relationship1=关系(node1,“同事”,no??de2)relation2=关系(node2,“同事”,no??de1)relation3=关系(node2,“同事”,no??de3)relation4=关系(node3,“同事”,no??de2)relation5=Relationship(node3,"neighbor",node4)relation6=Relationship(node4,"neighbor",node3)relation7=Relationship(node4,"student",node5)relation8=Relationship(node5,"teacher",node4)创建一些位置和Location节点之间的关系和区域之间的包含关系是单向的。relation9=Relationship(node6,"contains",node7)relation10=Relationship(node7,"contains",node8)创建Person节点和Location节点的关系,其中“访问”关系有属性,日期代表arrival访问日期,stay_hours表示停留时间。可以使用key:value字典数据结构来保存属性,然后给关系赋值properties1={'date':'2021-7-16','stay_hours':1}relation11=Relationship(node2,"Visit",node8,**properties1)properties2={'date':'2021-7-19','stay_hours':4}relation12=Relationship(node5,"Visit",node8,**properties2)然后组合以上所有节点和关系Subgraphnode_ls=[node1,node2,node3,node4,node5,node6,node7,node8]relation_ls=[relation1,relation2,relation3,relation4,relation5,relation6,relation7,relation8,relation9,relation10,relation11,relation12]subgraph=Subgraph(node_ls,relation_ls)最后通过事务类Transaction提交,批量创建这些节点和关系。这里tx.create并没有真正创建节点和关系,直到graph.commit才提交给Neo4j创建。tx=graph.begin()tx.create(subgraph)graph.commit(tx)重复上面的命令,不要创建重复的节点和关系。这一点在手册中是这样解释的:“子图中已经绑定数据库的实体将保持不变,未绑定的将新建并绑定到数据库。"create(subgraph)创建与本地子图中的节点和关系相对应的远程节点和关系。子图中已经绑定到远程实体的任何实体将保持不变,那些未绑定到它们新创建的对应实体的实体将保持不变。性能比较做一个简单的实验,大致对比一下逐个创建和批量创建的时间开销,在一个空的Neo4j数据库的情况下,通过逐个创建和批量创建创建10000个节点,每个节点有两个属性:name和age,是随机生成的,使用jupyternotebook的%%time命令计算时间开销。importrandomN=10000逐个创建节点%%timeforiinrange(N):random_name="P"+str(round(random.random()*N*2))random_age=round(random.random()*15)node=Node("Person",name=random_name,age=random_age)graph.create(node)CPUtimes:user50.3s,sys:4.19s,total:54.5sWalltime:5min16s批量创建节点%%timenode_ls=[]foriinrange(N):random_name="P"+str(round(random.random()*N*2))random_age=round(random.random()*15)node=Node("Person",name=random_name,age=random_age)node_ls.append(node)subgraph=Subgraph(node_ls,[])tx=graph.begin()tx.create(subgraph)graph.commit(tx)CPU时间:用户448ms,sys:75.5ms,total:523msWalltime:1.46s实验中还发现,如果只创建节点,批量创建方式的时间开销几乎呈线性增长。一次性提交创建100000个节点的任务时,时间开销在4.5秒左右。小结使用Py2neo建图时,尽量使用批量创建的方式。先创建Node对象和Relationship对象,然后形成子图,最后使用事务类一次性提交创建。下一篇文章将介绍如何使用Py2neo查询节点、关系和路径。我的Python版本>>>importsys>>>print(sys.version)3.7.6(默认,2020年1月8日,13:42:34)[Clang4.0.1(tags/RELEASE_401/final)]
