py2neo V4 极简使用指南:Python操作Neo4j图数据库

Neo4j的介绍可以参考这篇文章:《知识图谱技术与应用指南(转)》

其实,Python操作Neo4j,既可以用neo4j也可以用py2neo,前者是Neo4j官方的api,但是py2neo开发地更早,已经到V4了。

官方文档地址:https://py2neo.org/v4/


0、安装

下载Neo4j:https://neo4j.com/download/

使用pip安装: pip install py2neo

从github源码安装:pip install git+https://github.com/technige/py2neo.git#egg=py2neo


1、数据类型

1.1 节点Node和关系Relationship对象

图数据库,最重要的就是节点、边和属性,py2neo中最重要的就是类NodeRelationship

from py2neo.data import Node, Relationship
a = Node("Person", name="Alice")
b = Node("Person", name="Bob")
ab = Relationship(a, "KNOWS", b)
print(ab)
# (Alice)-[:KNOWS]->(Bob)

如果没有指定节点之间的关系,则默认为TO。也可以自建类Relationship的子类,如下:

c = Node("Person", name="Carol")
class WorksWith(Relationship): pass
ac = WorksWith(a, c)
print(type(ac))
# 'WORKS_WITH'

1.2 子图Subgraph对象

集合操作是创建子图最简便的方法:

s = ab | ac
print(s)
# {(alice:Person {name:"Alice"}),  (bob:Person {name:"Bob"}),  (carol:Person {name:"Carol"}),  (Alice)-[:KNOWS]->(Bob),  (Alice)-[:WORKS_WITH]->(Carol)}
print(s.nodes())
# frozenset({(alice:Person {name:"Alice"}), (bob:Person {name:"Bob"}), (carol:Person {name:"Carol"})})
print(s.relationships())
# frozenset({(Alice)-[:KNOWS]->(Bob), (Alice)-[:WORKS_WITH]->(Carol)})

1.3 路径Path对象和可遍历Walkable类型

可遍历对象是添加了遍历信息的子图。

w = ab + Relationship(b, "LIKES", c) + ac
print(w)
# (Alice)-[:KNOWS]->(Bob)-[:LIKES]->(Carol)<-[:WORKS_WITH]-(Alice)

1.4 记录Record对象

Record对象是值的有序有键的集合,和具名元组很像。

1.5 表格Table对象

Table对象是包含Record对象的列表。


2 图数据库

Graph对象是最重要的和Neo4j交互的类。

from py2neo import Graph
graph = Graph(password="password")
print(graph.run("UNWIND range(1, 3) AS n RETURN n, n * n as n_sq").to_table())
#    n | n_sq
# -----|------
#    1 |    1
#    2 |    4
#    3 |    9

2.1 数据库Database

用于连接图数据库

from py2neo import Database
db = Database("bolt://camelot.example.com:7687")

默认值是bolt://localhost:7687

default_db = Database()
>>> default_db
<Database uri='bolt://localhost:7687'>

2.2 图Graph

Graph类表示Neo4j中的图数据存储空间。

>>> from py2neo import Graph
>>> graph_1 = Graph()
>>> graph_2 = Graph(host="localhost")
>>> graph_3 = Graph("bolt://localhost:7687")

match匹配:

for rel in graph.match((alice, ), r_type="FRIEND"):
    print(rel.end_node["name"])

merge融合:

>>> from py2neo import Graph, Node, Relationship
>>> g = Graph()
>>> a = Node("Person", name="Alice", age=33)
>>> b = Node("Person", name="Bob", age=44)
>>> KNOWS = Relationship.type("KNOWS")
>>> g.merge(KNOWS(a, b), "Person", "name")

再创建第三个节点:

>>> c = Node("Company", name="ACME")
>>> c.__primarylabel__ = "Company"
>>> c.__primarykey__ = "name"
>>> WORKS_FOR = Relationship.type("WORKS_FOR")
>>> g.merge(WORKS_FOR(a, c) | WORKS_FOR(b, c))

nodes方法,找到所有符合条件的节点:

>>> graph = Graph()
>>> graph.nodes[1234]
(_1234:Person {name: 'Alice'})
>>> graph.nodes.get(1234)
(_1234:Person {name: 'Alice'})
>>> graph.nodes.match("Person", name="Alice").first()
(_1234:Person {name: 'Alice'})

2.3 事务Transactions

commit() 提交事务

create(subgraph) 创建节点和关系

>>> from py2neo import Graph, Node, Relationship
>>> g = Graph()
>>> tx = g.begin()
>>> a = Node("Person", name="Alice")
>>> tx.create(a)
>>> b = Node("Person", name="Bob")
>>> ab = Relationship(a, "KNOWS", b)
>>> tx.create(ab)
>>> tx.commit()
>>> g.exists(ab)
True

2.4 查询结果

Cursor

前进一个节点,打印节点的名字:

while cursor.forward():
    print(cursor.current["name"])

因为Cursor是可迭代对象,也可以这样:

for record in cursor:
    print(record["name"])

只关心一个节点,则:

if cursor.forward():
    print(cursor.current["name"])

或:

print(next(cursor)["name"])

从单条记录只返回一个值:

print(cursor.evaluate())

data(),提取出所有数据:

>>> from py2neo import Graph
>>> graph = Graph()
>>> graph.run("MATCH (a:Person) RETURN a.name, a.born LIMIT 4").data()
[{'a.born': 1964, 'a.name': 'Keanu Reeves'},
 {'a.born': 1967, 'a.name': 'Carrie-Anne Moss'},
 {'a.born': 1961, 'a.name': 'Laurence Fishburne'},
 {'a.born': 1960, 'a.name': 'Hugo Weaving'}]

evaluate(field=0),从下条记录返回第一个字段:

>>> from py2neo import Graph
>>> g = Graph()
>>> g.run("MATCH (a) WHERE a.email={x} RETURN a.name", x="bob@acme.com").evaluate()
'Bob Robertson'

stats(),返回查询统计:

>>> from py2neo import Graph
>>> g = Graph()
>>> g.run("CREATE (a:Person) SET a.name = 'Alice'").stats()
constraints_added: 0
constraints_removed: 0
contained_updates: True
indexes_added: 0
indexes_removed: 0
labels_added: 1
labels_removed: 0
nodes_created: 1
nodes_deleted: 0
properties_set: 1
relationships_created: 0
relationships_deleted: 0

to_data_frame(index=None, columns=None, dtype=None),将数据返回为pandas的DataFrame:

>>> from py2neo import Graph
>>> graph = Graph()
>>> graph.run("MATCH (a:Person) RETURN a.name, a.born LIMIT 4").to_data_frame()
   a.born              a.name
0    1964        Keanu Reeves
1    1967    Carrie-Anne Moss
2    1961  Laurence Fishburne
3    1960        Hugo Weaving

3 py2neo.matching – 实体匹配

3.1 节点匹配

使用NodeMatcher匹配节点:

>>> from py2neo import Graph, NodeMatcher
>>> graph = Graph()
>>> matcher = NodeMatcher(graph)
>>> matcher.match("Person", name="Keanu Reeves").first()
(_224:Person {born:1964,name:"Keanu Reeves"})

使用where子句匹配:

>>> list(matcher.match("Person").where("_.name =~ 'K.*'"))
[(_57:Person {born: 1957, name: 'Kelly McGillis'}),
 (_80:Person {born: 1958, name: 'Kevin Bacon'}),
 (_83:Person {born: 1962, name: 'Kelly Preston'}),
 (_224:Person {born: 1964, name: 'Keanu Reeves'}),
 (_226:Person {born: 1966, name: 'Kiefer Sutherland'}),
 (_243:Person {born: 1957, name: 'Kevin Pollak'})]

排序order_by()和数量limit()限制:

>>> list(matcher.match("Person").where("_.name =~ 'K.*'").order_by("_.name").limit(3))
[(_224:Person {born: 1964, name: 'Keanu Reeves'}),
 (_57:Person {born: 1957, name: 'Kelly McGillis'}),
 (_83:Person {born: 1962, name: 'Kelly Preston'})]

只统计数量,用len():

>>> len(matcher.match("Person").where("_.name =~ 'K.*'"))
6

3.2 关系匹配RelationshipMatcher

使用的方法和节点匹配很相似:

first()

order_by(*fields)

where(*conditions, **properties)

4 对象图映射Object-Graph Mapping

用于绑定Python对象和底层图数据

class Movie(GraphObject):
    __primarykey__ = "title"

    title = Property()
    tag_line = Property("tagline")
    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)

4.1 图对象

GraphObject,用作基类

4.2 属性Property()

>>> class Person(GraphObject):
...     name = Property()
...
>>> alice = Person()
>>> alice.name = "Alice Smith"
>>> alice.name
"Alice Smith"

4.3 标签Label()

标签是布尔值,默认是False

>>> class Food(GraphObject):
...     hot = Label()
...
>>> pizza = Food()
>>> pizza.hot
False
>>> pizza.hot = True
>>> pizza.hot
True

4.4 关联对象

class Person(GraphObject):
    __primarykey__ = "name"

    name = Property()

    likes = RelatedTo("Person")
for friend in person.likes:
    print(friend.name)

4.5 对象匹配

>>> Person.match(graph, "Keanu Reeves").first()
<Person name='Keanu Reeves'>
>>> list(Person.match(graph).where("_.name =~ 'K.*'"))
[<Person name='Keanu Reeves'>,
 <Person name='Kevin Bacon'>,
 <Person name='Kiefer Sutherland'>,
 <Person name='Kevin Pollak'>,
 <Person name='Kelly McGillis'>,
 <Person name='Kelly Preston'>]

4.6 对象操作

>>> alice = Person()
>>> alice.name = "Alice Smith"
>>> graph.push(alice)
>>> alice.__node__
(_123:Person {name: 'Alice Smith'})
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345