更多可以阅读https://blog.csdn.net/column/details/23835.html
图数据库neo4j(二)python 连接neo4j
pip install py2neo
在完成安装之后,在python中调用py2neo即可,常用的有Graph,Node,
Relationship。
from py2neo import Graph,Node,Relationship
下面通过Python来演示下Node & Relationship
Neo4j 里面最重要的两个数据结构就是节点和关系,即 Node 和 Relationship,可以通过 Node 或 Relationship 对象创建,实例如下:
from py2neo import Node, Relationship
a = Node('Person', name='Alice')
b = Node('Person', name='Bob')
r = Relationship(a, 'KNOWS', b)
print(a, b, r)
输出结果:
(:Person {name: 'Alice'}) (:Person {name: 'Bob'}) (Alice)-[:KNOWS {}]->(Bob)
这样我们就成功创建了两个 Node 和两个 Node 之间的 Relationship。
Node 和 Relationship 都继承了 PropertyDict 类,它可以赋值很多属性,类似于Python字典的形式,例如可以通过如下方式对 Node 或 Relationship 进行属性赋值,接着上面的代码,实例如下:
a['age'] = 20
b['age'] = 21
r['time'] = '2017/08/31'
print(a, b, r)
注意:以上代码必须在创建了node与relationship下进行添加dict形式才有效。
运行结果:
(alice:Person {age:20,name:"Alice"}) (bob:Person {age:21,name:"Bob"}) (alice)-[:KNOWS {time:"2017/08/31"}]->(bob)
可见通过类似字典的操作方法就可以成功实现属性赋值。
另外还可以通过 setdefault() 方法赋值默认属性,例如:
a.setdefault('location', '北京')
print(a)
运行结果
(alice:Person {age:20,location:"北京",name:"Alice"})
可见没有给 a 对象赋值 location 属性,现在就会使用默认属性。
但如果赋值了 location 属性,则它会覆盖默认属性,例如:
a['location'] = '上海'
a.setdefault('location', '北京')
print(a)
运行结果:
(alice:Person {age:20,location:"上海",name:"Alice"})
另外也可以使用 update() 方法对属性批量更新,接着上面的例子实例如下:
data = {
'name': 'Amy',
'age': 21
}
a.update(data)
print(a)
运行结果:
(alice:Person {age:21,location:"上海",name:"Amy"})
可以看到这里更新了 a 对象的 name 和 age 属性,没有更新 location 属性,则 name 和 age 属性会更新,location 属性则会保留。
Subgraph,子图,是 Node 和 Relationship 的集合,最简单的构造子图的方式是通过关系运算符,实例如下:
from py2neo import Node, Relationship
a = Node('Person', name='Alice')
b = Node('Person', name='Bob')
r = Relationship(a, 'KNOWS', b)
s = a | b | r
print(s)
运行结果:
({(alice:Person {name:"Alice"}), (bob:Person {name:"Bob"})}, {(alice)-[:KNOWS]->(bob)})
这样就组成了一个 Subgraph。
另外还可以通过 nodes() 和 relationships() 方法获取所有的 Node 和 Relationship,实例如下:
print(s.nodes())
print(s.relationships())
运行结果:
frozenset({(alice:Person {name:"Alice"}), (bob:Person {name:"Bob"})})
frozenset({(alice)-[:KNOWS]->(bob)})
可以看到结果是 frozenset 类型。
另外还可以利用 & 取 Subgraph 的交集,例如:
s1 = a | b | r
s2 = a | b
print(s1 & s2)
运行结果:
({(alice:Person {name:"Alice"}), (bob:Person {name:"Bob"})}, {})
可以看到结果是二者的交集。
另外我们还可以分别利用 keys()、labels()、nodes()、relationships()、types() 分别获取 Subgraph 的 Key、Label、Node、Relationship、Relationship Type,实例如下:
s = a | b | r
print(s.keys())
print(s.labels())
print(s.nodes())
print(s.relationships())
print(s.types())
运行结果:
frozenset({'name'})
frozenset({'Person'})
frozenset({(alice:Person {name:"Alice"}), (bob:Person {name:"Bob"})})
frozenset({(alice)-[:KNOWS]->(bob)})
frozenset({'KNOWS'})
另外还可以用 order() 或 size() 方法来获取 Subgraph 的 Node 数量和 Relationship 数量,实例如下:
from py2neo import Node, Relationship, size, order
s = a | b | r
print(order(s))
print(size(s))
运行结果:
2
1
Walkable 是增加了遍历信息的 Subgraph,我们通过 + 号便可以构建一个 Walkable 对象,例如:
from py2neo import Node, Relationship
a = Node('Person', name='Alice')
b = Node('Person', name='Bob')
c = Node('Person', name='Mike')
ab = Relationship(a, "KNOWS", b)
ac = Relationship(a, "KNOWS", c)
w = ab + Relationship(b, "LIKES", c) + ac
print(w)
运行结果:
(alice)-[:KNOWS]->(bob)-[:LIKES]->(mike)<-[:KNOWS]-(alice)
这样我们就形成了一个 Walkable 对象。
另外我们可以调用 walk() 方法实现遍历,实例如下:
from py2neo import walk
for item in walk(w):
print(item)
运行结果:
(alice:Person {name:"Alice"})
(alice)-[:KNOWS]->(bob)
(bob:Person {name:"Bob"})
(bob)-[:LIKES]->(mike)
(mike:Person {name:"Mike"})
(alice)-[:KNOWS]->(mike)
(alice:Person {name:"Alice"})
可以看到它从 a 这个 Node 开始遍历,然后到 b,再到 c,最后重新回到 a。
另外还可以利用 start_node()、end_node()、nodes()、relationships() 方法来获取起始 Node、终止 Node、所有 Node 和 Relationship,例如:
print(w.start_node())
print(w.end_node())
print(w.nodes())
print(w.relationships())
运行结果:
(alice:Person {name:"Alice"})
(alice:Person {name:"Alice"})
((alice:Person {name:"Alice"}), (bob:Person {name:"Bob"}), (mike:Person {name:"Mike"}), (alice:Person {name:"Alice"}))
((alice)-[:KNOWS]->(bob), (bob)-[:LIKES]->(mike), (alice)-[:KNOWS]->(mike))
可以看到本例中起始和终止 Node 都是同一个,这和 walk() 方法得到的结果是一致的。
在 database 模块中包含了和 Neo4j 数据交互的 API,最重要的当属 Graph,它代表了 Neo4j 的图数据库,同时 Graph 也提供了许多方法来操作 Neo4j 数据库。
Graph 在初始化的时候需要传入连接的 URI,初始化参数有 bolt、secure、host、http_port、https_port、bolt_port、user、password,详情说明可以参考:http://py2neo.org/v3/database.html#py2neo.database.Graph。
初始化的实例如下:
from py2neo import Graph
graph_1 = Graph()
graph_2 = Graph(host="localhost")
graph_3 = Graph("http://localhost:7474/db/data/")
另外我们还可以利用 create() 方法传入 Subgraph 对象来将关系图添加到数据库中,实例如下:
from py2neo import Node, Relationship, Graph
a = Node('Person', name='Alice')
b = Node('Person', name='Bob')
r = Relationship(a, 'KNOWS', b)
s = a | b | r
graph = Graph(password='123456')
graph.create(s)
另外还可以利用 data() 方法来获取查询结果:
from py2neo import Graph
graph = Graph(password='123456')
data = graph.data('MATCH (p:Person) return p')
print(data)
运行结果:
[{'p': (e0d0f96:Person {name:"Alice"})}, {'p': (cfe57d0:Person {name:"Bob"})}]
这里是通过 CQL 语句实现的查询,输出结果即 CQL 语句的返回结果,是列表形式。
另外输出结果还可以直接转化为 DataFrame 对象,实例如下:
from py2neo import Graph
from pandas import DataFrame
graph = Graph(password='123456')
data = graph.data('MATCH (p:Person) return p')
df = DataFrame(data)
print(df)
运行结果:
p
0 {'name': 'Alice'}
1 {'name': 'Bob'}
另外可以使用 find_one() 或 find() 方法进行 Node 的查找,可以利用 match() 或 match_one() 方法对 Relationship 进行查找:
from py2neo import Graph
graph = Graph(password='123456')
node = graph.find_one(label='Person')
print(node)
relationship = graph.match_one(rel_type='KNOWS')
print(relationship)
运行结果:
(c7402c7:Person {age:21,name:"Alice"})
(c7402c7)-[:KNOWS]->(e2c42fc)
如果想要更新 Node 的某个属性可以使用 push() 方法,例如:
from py2neo import Graph, Node
graph = Graph(password='123456')
a = Node('Person', name='Alice')
node = graph.find_one(label='Person')
node['age'] = 21
graph.push(node)
print(graph.find_one(label='Person'))
运行结果:
(a90a763:Person {age:21,name:"Alice"})
如果想要删除某个 Node 可以使用 delete() 方法,例如:
from py2neo import Graph
graph = Graph(password='123456')
node = graph.find_one(label='Person')
relationship = graph.match_one(rel_type='KNOWS')
graph.delete(relationship)
graph.delete(node)
在删除 Node 时必须先删除其对应的 Relationship,否则无法删除 Node。
另外我们也可以通过 run() 方法直接执行 CQL 语句,例如:
from py2neo import Graph
graph = Graph(password='123456')
data = graph.run('MATCH (p:Person) RETURN p LIMIT 5')
print(list(data))
运行结果:
[('p': (b6f61ff:Person {age:20,name:"Alice"})), ('p': (cc238b1:Person {age:20,name:"Alice"})), ('p': (b09e672:Person {age:20,name:"Alice"}))]
NodeSelector
Graph 有时候用起来不太方便,比如如果要根据多个条件进行 Node 的查询是做不到的,在这里更方便的查询方法是利用 NodeSelector,我们首先新建如下的 Node 和 Relationship,实例如下:
from py2neo import Graph, Node, Relationship
graph = Graph(password='123456')
a = Node('Person', name='Alice', age=21, location='广州')
b = Node('Person', name='Bob', age=22, location='上海')
c = Node('Person', name='Mike', age=21, location='北京')
r1 = Relationship(a, 'KNOWS', b)
r2 = Relationship(b, 'KNOWS', c)
graph.create(a)
graph.create(r1)
graph.create(r2)
在这里我们用 NodeSelector 来筛选 age 为 21 的 Person Node,实例如下:
from py2neo import Graph, NodeSelector
graph = Graph(password='123456')
selector = NodeSelector(graph)
persons = selector.select('Person', age=21)
print(list(persons))
运行结果:
[(d195b2e:Person {age:21,location:"广州",name:"Alice"}), (eefe475:Person {age:21,location:"北京",name:"Mike"})]
另外也可以使用 where() 进行更复杂的查询,例如查找 name 是 A 开头的 Person Node,实例如下:
from py2neo import Graph, NodeSelector
graph = Graph(password='123456')
selector = NodeSelector(graph)
persons = selector.select('Person').where('_.name =~ "A.*"')
print(list(persons))
运行结果:
[(bcd8072:Person {age:21,location:"广州",name:"Alice"})]
在这里用了正则表达式匹配查询。
另外也可以使用 order_by() 进行排序:
f
rom py2neo import Graph, NodeSelector
graph = Graph(password='123456')
selector = NodeSelector(graph)
persons = selector.select('Person').order_by('_.age')
print(list(persons))
运行结果:
[(e3fc3d7:Person {age:21,location:"广州",name:"Alice"}), (da0179d:Person {age:21,location:"北京",name:"Mike"}), (cafa16e:Person {age:22,location:"上海",name:"Bob"})]
前面返回的都是列表,如果要查询单个节点的话,可以使用 first() 方法,实例如下:
from py2neo import Graph, NodeSelector
graph = Graph(password='123456')
selector = NodeSelector(graph)
person = selector.select('Person').where('_.name =~ "A.*"').first()
print(person)
运行结果:
(ea81c04:Person {age:21,location:"广州",name:"Alice"})
更详细的内容可以查看:http://py2neo.org/v3/database.html#cypher-utilities
OGM 类似于 ORM,意为 Object Graph Mapping,这样可以实现一个对象和 Node 的关联,例如:
from py2neo.ogm import GraphObject, Property, RelatedTo, RelatedFrom
class Movie(GraphObject):
__primarykey__ = 'title'
title = Property()
released = Property()
actors = RelatedFrom('Person', 'ACTED_IN')
directors = RelatedFrom('Person', 'DIRECTED')
producers = RelatedFrom('Person', 'PRODUCED')
class Person(GraphObject):
__primarykey__ = 'name'
name = Property()
born = Property()
acted_in = RelatedTo('Movie')
directed = RelatedTo('Movie')
produced = RelatedTo('Movie')
我们可以用它来结合 Graph 查询,例如:
from py2neo import Graph
from py2neo.ogm import GraphObject, Property
graph = Graph(password='123456')
class Person(GraphObject):
__primarykey__ = 'name'
name = Property()
age = Property()
location = Property()
person = Person.select(graph).where(age=21).first()
print(person)
print(person.name)
print(person.age)
运行结果:
<Person name='Alice'>
Alice
21
这样我们就成功实现了对象和 Node 的映射。
我们可以用它动态改变 Node 的属性,例如修改某个 Node 的 age 属性,实例如下:
person = Person.select(graph).where(age=21).first()
print(person.__ogm__.node)
person.age = 22
print(person.__ogm__.node)
graph.push(person)
运行结果:
(ccf5640:Person {age:21,location:"北京",name:"Mike"})
(ccf5640:Person {age:22,location:"北京",name:"Mike"})
另外我们也可以通过映射关系进行 Relationship 的调整,例如通过 Relationship 添加一个关联 Node,实例如下:
from py2neo import Graph
from py2neo.ogm import GraphObject, Property, RelatedTo
graph = Graph(password='123456')
class Person(GraphObject):
__primarykey__ = 'name'
name = Property()
age = Property()
location = Property()
knows = RelatedTo('Person', 'KNOWS')
person = Person.select(graph).where(age=21).first()
print(list(person.knows))
new_person = Person()
new_person.name = 'Durant'
new_person.age = 28
person.knows.add(new_person)
print(list(person.knows))
运行结果:
[<Person name='Bob'>]
[<Person name='Bob'>, <Person name='Durant'>]
这样我们就完成了 Node 和 Relationship 的添加,同时由于设置了 primarykey 为 name,所以不会重复添加。
但是注意此时数据库并没有更新,只是对象更新了,如果要更新到数据库中还需要调用 Graph 对象的 push() 或 pull() 方法,添加如下代码即可:
graph.push(person)
也可以通过 remove() 方法移除某个关联 Node,实例如下:
person = Person.select(graph).where(name='Alice').first()
target = Person.select(graph).where(name='Durant').first()
person.knows.remove(target)
graph.push(person)
graph.delete(target)
这里 target 是 name 为 Durant 的 Node,代码运行完毕后即可删除关联 Relationship 和删除 Node。
以上便是 OGM 的用法,查询修改非常方便,推荐使用此方法进行 Node 和 Relationship 的修改。
更多内容可以查看:http://py2neo.org/v3/ogm.html#module-py2neo.ogm。
from py2neo import Graph, Node, Relationship
# 连接neo4j数据库
graph = Graph("http://127.0.0.1:7474";,username="neo4j",password="123456")
# 创建结点:label结点,方便以后的结点查找操作
temp_node1 = Node(lable="Person",name="node1")
temp_node2 = Node(lable="Person",name="node2")
graph.create(temp_node1)
graph.create(temp_node2)
# 建立关系
node_1_call_node_2 = Relationship(temp_node1,'CALL',temp_node2)
node_1_call_node_2['count'] = 1
node_2_call_node_1 = Relationship(temp_node2,'CALL',temp_node1)
graph.create(node_2_call_node_1)
graph.create(node_1_call_node_2)
# 更新关系或节点的属性 push提交
node_1_call_node_2['count']+=1
graph.push(node_1_call_node_2)
# 通过属性值来查找节点和关系find_one
find_code = graph.find_one(
label="明教",
property_key="name",
property_value="张无忌"
)
print(find_code['name'])
# find方法已被弃用:通过属性值来查找所有节点和关系find替换为:NodeSelector
find = NodeSelector(graph).select('明教')
for f in find:
print(f['name'])