py2neo 快速上手
py2neo 快速上手
py2neo简介
neo4j
是目前最流行的图数据库,在建立知识图谱的时候经常用于数据的存储和检索,neo4j
相较mysql
等其他关系型数据库最大的特点就是非常容易查看数据与数据之间的联系,它将所有数据转换成图的形式,让使用者能够快速发现蕴含的联系。下面是neo4j
的主要界面和相应的数据图例(射雕英雄传人物知识图谱)。
但是,直接地对neo4j
操作,虽然有相应的cypher
语句,却并不适合在编程的过程中操作。py2neo
就是一个连接了python
到neo4j
数据库的库,它不仅让程序本身可以直接执行cypher
语句创建图数据库,也提供了更人性化的操作,符合面向对象编程的思想。
neo4j
在进入使用py2neo
之前,还是要先安装好neo4j
,了解一些基础的cypher
语句用法(虽然我自己基本不怎么用它),然而neo4j
的介绍不是本文的重点,网上已有大篇幅的文章去讲述怎么使用它。因此,这里我会给出必要的操作步骤(避免再去看冗长的文档)和我个人推荐的博客文章(包含更为详细的说明)。
安装与启动
- 安装
wget https://neo4j.com/artifact.php?name=neo4j-community-3.4.1-unix.tar.gz
tar -zxvf neo4j-community-3.4.1.tar.gz
安装的环境建议放在linux系统下,这是我个人的爱好也是一个建议(所有部署的服务、数据库等东西都放到linux系统中),不仅仅是安装更加方便,同时也可以避免后续许多的不便,如果你主力系统是windows,那么虚拟机+网络桥接模式是一个不错的选择
- 启动
cd bin/
./neo4j start # console | start | stop | restart | status
当发现启动成功后,进入http://localhost:7474
py2neo使用
py2neo支持直接执行
cypher
语句,如果你对cypher
语句熟悉的话,将你要执行的操作转换成cypher
语句,再让py2neo
执行或许是不错的选择,否则,我更推荐你使用py2neo
提供的接口
连接数据库
from py2neo import *
NEO4J_URL = 'http://localhost:7474'
NEO4J_USERNAME = 'neo4j'
NEO4J_PASSWORD = '123456'
graph = Graph(NEO4J_URL, username=NEO4J_USERNAME, password=NEO4J_PASSWORD)
节点
创建节点
节点的定义由 Node
实现,要将其添加到 neo4j
数据库中则可通过 create
或 merge
方法实现,两者都可创建节点,但有些许的不同:
create(node)
:即便是属性值相同的同一节点,在调用create
之后也会创建一个新节点merge(node, "node_label", "main_attr")
:主要是main_attr
(主属性)一样,就视作同一节点,对改节点做的任何更改在merge
的时候都会覆盖已有的节点
node0 = Node('Person', name='Alice') # 直接指定属性
# 通过属性dict创建
person_info = {
'name':'Jhon'
}
node1 = Node('Person', **person_info)
graph.create(node0) # create创建节点,如果不做检查,总是会创建新节点
graph.merge(node1,'Person', 'name') # 如果节点已存在则覆盖(只要同一key),需要指定primarykey和primarylabel
查找节点
- 精确查找(根据指定属性)
matcher = NodeMatcher(graph)
matcher.match("Person", name="Alice").first() # 返回node
描述 | 后缀 | 表达式 | 示例 | cypher语句 |
---|---|---|---|---|
相等 | __exact | = | matcher.match(“Person”, name__exact=”Kevin Bacon”) | MATCH (:Person) WHERE name = “Kevin Bacon” RETURN |
不等 | __not | <> | matcher.match(“Person”, name__not=”Rick Astley”) | MATCH (:Person) WHERE .name <> “Rick Astley” RETURN _ |
大于 | __gt | > | matcher.match(“Person”, born__gt=1985) | MATCH (:Person) WHERE .born > 1985 RETURN _ |
大于等于 | __gte | >= | matcher.match(“Person”, born__gte=1965) | MATCH (:Person) WHERE .born >= 1965 RETURN _ |
小于 | __lt | < | matcher.match(“Person”, born__lt=1965) | MATCH (:Person) WHERE .born < 1965 RETURN _ |
小于等于 | __lte | <= | matcher.match(“Person”, born__lte=1965) | MATCH (:Person) WHERE .born <= 1965 RETURN _ |
以…开头 | __startswith | STARTS WITH | matcher.match(“Person”, name__startswith=”Kevin”) | MATCH (:Person) WHERE .name STARTS WITH “Kevin” RETURN _ |
以…结尾 | __endswith | ENDS WITH | matcher.match(“Person”, name__endswith=”Smith”) | MATCH (:Person) WHERE .name ENDS WITH “Smith” RETURN _ |
包含 | __contains | CONTAINS | matcher.match(“Person”, name__contains=”James”) | MATCH (:Person) HWERE .name CONTAINS “James” RETURN _ |
- 模糊查找(根据正则表达式)
list(matcher.match("Person").where("_.name =~ 'K.*'")) # _指代节点,~代表采用正则表达式
- 查找结果排序与限制
list(matcher.match("Person").where("_.name =~ 'K.*'").order_by("_.name").limit(3))
- 查找结果个数
len(matcher.match("Person").where("_.name =~ 'K.*'"))
- 跳过前n个查找结果
list(matcher.match("Person").where("_.name =~ 'K.*'").skip(3))
节点属性与标签
- 属性操作
node[key] = value # 给节点属性赋值
del node[key] # 删除节点属性
len(node) # 节点属性的个数
dict(node) # 返回字典,包括了该节点的所有属性
node.identity # 返回节点id
- 标签操作
node.labels # 返回节点的所有标签
labelA in node.labels # 如果节点具有标签labelA,返回True
node.labels.add(labelB) # 给节点增加标签labelB
node.labels.discard(labelC) # 删除节点标签labelC
node.labels.remove(labelC) # 同上,但是如果labelC不存在的话会返回ValueError
node.labels.clear() # 清除节点所有标签
node.labels.update(manylabels) # 从可迭代对象manylabels中给节点增加多个标签
关系
创建关系
properties = {
'year' : 1999
}
ab = Relationship(node_a,'knows', node_b, ) # 后面还可以传入关系的属性字典
aa = Relationship(node_a,'like')
ab['time'] = '2019/01/01' # 给关系添加属性
查找关系
- 查找所有指定类型的关系
matcher=RelationshipMatcher(graph)
list(matcher.match(r_type='KNOWS'))
- 查找指定起始节点或终点的关系
relation_matcher = RelationshipMatcher(graph)
result = relation_matcher.match((node,), '父亲').first() # 注意这里的node需要先按照nodematcher.match得到
(node,) 也可以是{node}
关系属性
relationshipA == relationshipB
relationshipA != relationshipB # 判断两个关系是否相等,但是和节点不同,这里只要起始、终止节点和关系类型相同,就判定两个关系相等
del relationship[key] # 删除属性
len(relationship) # 返回属性个数
dict(relationship) # 返回字典,包括所有属性
type(relationship) # 返回关系的类型
relationship.nodes # 返回关系中的所有节点
OGM
from py2neo.ogm import GraphObject, RelatedTo, RelatedFrom
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() # Property(key='姓名', default='Tom')
born = Property()
acted_in = RelatedTo(Movie) # RelatedTo(Movie,relationship_type='ACTED_IN'), 类名引号可用可不用
directed = RelatedTo(Movie)
produced = RelatedTo(Movie)
查找节点
Person.match(graph, "Alice").first()
list(Person.match(graph).where("_.name =~ 'A.*'"))
属性&操作
alice = Person()
alice.name = "Alice Smith"
graph.push(alice) # 不需要create/merge
创建关系
cp = Person()
cp.name = 'cp'
m1 = Movie()
m1.title = '煎饼侠'
cp.acted_in.add(m1) # 添加cp->acted_in ->m1, add有参数,可用于传入关系的属性,直接传入字典或**dict
# cp.acted_in.remove(m1) # 移除关系
graph.push(cp)
graph.push(m1)
# add
def add(self, obj, properties=None, **kwproperties):
""" Add or update a related object.
:param obj: the :py:class:`.Model` to relate
:param properties: dictionary of properties to attach to the relationship (optional)
:param kwproperties: additional keyword properties (optional)
"""
RelatedTo是主动的,RelatedFrom是被动的,因此只需要添加RelatedTo关系(cp.acted_in.add(m1)),就可用查询相应m1.actors
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!