Neo4j是一款开源图数据库,应用Python语言拜访Neo4j能够应用Py2neo。本文介绍了应用Py2neo拜访Neo4j,批量创立节点和关系的办法。
Py2neo提供了间接执行Cypher语句的办法,也提供了诸如Node、Relationship、Path一系列的数据结构,在不同的场景下能够灵便应用。
本文应用的Py2neo是2021.1之后的版本,手册请戳这里:
The Py2neo Handbook
装置Py2neo
应用pip装置Py2neo,执行:
pip install py2neo
查看已装置的Py2neo是什么版本的:
pip show py2neoName: py2neoVersion: 2021.1.5Summary: Python client library and toolkit for Neo4jHome-page: https://py2neo.org/
连贯Neo4j数据库
本文中会用到多种数据类型,在此一并援用
import numpy as npimport pandas as pdfrom py2neo import Node,Relationship,Graph,Path,Subgraph
配置Neo4j数据库的拜访地址、用户名和明码
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执行Cypher语句来实现创立节点等操作,办法如下所示:
cypher_ = "CREATE (:Person {name:'王王', age:35, work:'宇宙电子厂'}),\(:Person {name:'李李', age:20, work:'宇宙电子厂'})"graph.run(cypher_)
这样就在Neo4j中创立了两个label为Person的节点,第一个节点的name属性为“王王”,age属性为35,work属性为“宇宙电子厂”,第二个节点的name属性为“李李”,age属性为20,work属性为“宇宙电子厂”。
同样,能够通过调用graph.run执行Cypher语句创立关系。
cypher_ = "MATCH (from:Person{name:'王王'}),\(to:Person{name:'李李'}) MERGE (from)-[r:共事]->(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. 应用Node、Relationship和Subgraph数据结构创立节点和关系
下面两种办法都是一次创立一个节点或者一个关系,Py2neo也提供了批量创立节点和关系的办法,而且性能更优。上面就以下图中的图谱为例,应用Py2neo提供Node、Relationship和Subgraph数据结构在Neo4j中创立节点和关系。
首先创立一些label为Person的节点,即Node对象,第一个参数是label,属性按key=value顺次作为参数传入。如果节点有多个label,能够用Node.add_label("label_text")来追加label。
node1 = Node("Person", name="王王", age=35, work="宇宙电子厂")node2 = Node("Person", name="李李", age=20, work="宇宙电子厂")node3 = Node("Person", name="张张", age=30, work="宇宙电子厂")node4 = Node("Person", name="赵赵", age=45, work="月亮中学")node4.add_label("Teacher")node5 = Node("Person", name="刘刘", age=20, work="地球电子商务公司")
再创立一些label为Location的节点
node6 = Node("Location", name="南京") node7 = Node("Location", name="江宁区") node8 = Node("Location", name="禄口机场")
建设一些Person和Person节点之间的关系,Neo4j中的关系是有方向的,所以Relationship第一个参数为起始节点,第三个参数是完结节点,而第二个节点为关系的类型。这里创立的共事、街坊的关系为双向的,老师、学生的关系为单向。
relation1 = Relationship(node1, "共事", node2)relation2 = Relationship(node2, "共事", node1)relation3 = Relationship(node2, "共事", node3)relation4 = Relationship(node3, "共事", node2)relation5 = Relationship(node3, "街坊", node4)relation6 = Relationship(node4, "街坊", node3)relation7 = Relationship(node4, "学生", node5)relation8 = Relationship(node5, "老师", node4)
创立一些Location和Location节点之间的关系,地区之间的蕴含关系为单向。
relation9 = Relationship(node6, "蕴含", node7)relation10 = Relationship(node7, "蕴含", node8)
创立Person节点和Location节点之间的关系,这里“到访”的关系是有属性的,date示意到访的日期,stay_hours示意停留的工夫。能够应用一个key:value的字典数据结构保留属性,再赋予关系
properties1={'date':'2021-7-16','stay_hours':1}relation11 = Relationship(node2, "到访", node8, **properties1)properties2={'date':'2021-7-19','stay_hours':4}relation12 = Relationship(node5, "到访", node8, **properties2)
而后将以上所有节点和关系组成Subgraph
node_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)
反复执行下面的命令,不会发明出反复的节点和关系。这一点手册中有阐明:“subgraph中的曾经和数据库绑定的实体将放弃不变,那些没有绑定的将在数据库中新建并绑定上。”
create(subgraph) Create remote nodes and relationships that correspond to those in a local subgraph. Any entities in subgraph that are already bound to remote entities will remain unchanged, those which are not will become bound to their newly-created counterparts.
性能比照
做一个简略的试验粗略地比照一一创立和批量创立的工夫开销。在Neo4j为空数据库的状况下,别离采纳一一创立和批量创立的办法创立10000个节点,每个节点有name和age两个属性,都是随机生成的,应用jupyter notebook的%%time命令计算工夫开销。
import randomN = 10000
一一创立节点
%%timefor i in range(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)CPU times: user 50.3 s, sys: 4.19 s, total: 54.5 sWall time: 5min 16s
批量创立节点
%%timenode_ls = []for i in range(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 times: user 448 ms, sys: 75.5 ms, total: 523 msWall time: 1.46 s
试验中也发现,只是创立节点的话,批量创立办法的工夫开销简直是线性增长的,当一次性提交10万个节点的创立工作时,工夫开销大概在4.5秒。
小结
在应用Py2neo构建图谱时,尽可能应用批量创立办法。先创立节点(Node)对象、关系(Relationship)对象,再形成子图(Subgraph),最初利用事务类一次提交创立。
下一篇将介绍如何使用Py2neo查问节点、关系和门路。
我的Python版本
>>> import sys>>> print(sys.version)3.7.6 (default, Jan 8 2020, 13:42:34) [Clang 4.0.1 (tags/RELEASE_401/final)]