Bootstrap

【py2neo学习笔记】利用py2neo库来操作neo4j 知识图谱的创建、增加、删除、修改、查询、案例、参考博客

#!/usr/bin/env python
# -*- encoding: utf-8 -*-

# 参考文档1 从增删改角度: https://blog.csdn.net/qq_42644523/article/details/127438757
# 参考文档2 从常用方法介绍和与Cypher原语句对比: https://zhuanlan.zhihu.com/p/81175725
# 参考文档3 实例(用于检验前两个学习是否掌握): https://huaweicloud.csdn.net/63808884dacf622b8df89a37.html

# -----------------------
# ----  准备工作  -------
# -----------------------
# 导包
import py2neo
from py2neo import Graph, Node, Relationship, RelationshipMatcher, NodeMatcher

# -----------------------
# ---  节点与关系初始化  ---
# -----------------------
# 图的初始化
graph = Graph("http://localhost:7474",user ="",password='')
# 用pycharm打开neo4j工作台连接,默认的端口号就是7474,输入自己的账号密码


# 节点 = Noede(节点标签,属性名1=属性值1,属性名2,属性值2...)
# nodex = Node(*labels,**properties)
node1 = Node('Person', name='tony', age=25, weight=55)
node2 = Node('Person', name='tom', age=23, weight=50, hight=170)
node3 = Node('Person','male','Suspect', name='peter', age=22, weight=48, hight=165)
node4 = Node('Person','female',name='lisa', age=21, weight=46)
node5 = Node('Person')

# 关系规则
# relationx = Relationship(nodestart, "关系类型", nodeend, 属性1=属性值1,属性2,属性值2...)
relation1 = Relationship(node1, "KNOW", node2)
relation2 = Relationship(node1, 'KNOW', node3, strong=85)
relation3 = Relationship(node1, 'COUPLE', node4, value=90)
relation4 = Relationship(node4, 'MATE', node2, strong=40)
relation5 = Relationship(node2, 'KNOW', node3, strong=60)

# -----------------------
# ------    创    --------
# ------------------------

# 在图中添加节点
# graph.create(节点)
graph.create(node1)
graph.create(node2)
graph.create(node3)
graph.create(node4)
graph.create(node5)
# graph.create(Node(节点属性,属性1=属性值1))

# 在图中添加关系
# graph.create(关系)
graph.create(relation1)
graph.create(relation2)
graph.create(relation3)
graph.create(relation4)
graph.create(relation5)

# -----------------------
# --- 查看数据库基本属性 ---
# -----------------------
graph.schema.node_labels # 查看图结构中节点标签的类别 type(_) = frozenset
graph.schema.relationship_types # 查看图结构中关系的类型

# -----------------------
# ------    增    --------
# -----------------------

# 增加标签
# 节点.add_label(标签)
node1.add_label('male')
graph.push(node1)# 略

# 批量增加节点标签
node2.update_labels(['male','Suspect'])
graph.push(node2)# 略

# 增加节点属性
# 节点[属性名] = 属性值
# 增加本来没有的属性
# 初始状态node1 (标签:'Person', 属性1 name='tony', 属性2 age=25, 属性3 weight=55)
node1['hight'] = 190
# 修改后的状态,是在原来的基础上,增加了属性4?
# 修改原本已经有的属性(改的内容,放在一起看)
node1['age'] = 26
graph.push(node1)# 略

# 增加关系的属性
relation2['strong'] = 90
graph.push(relation2)# 略


# -----------------------
# ------    删    --------
# -----------------------

# 删除节点标签
# 节点.remove_label(标签)
node3.remove_label('Suspect')
graph.push(node3)# 略

# 删除节点属性
# del 节点[属性名]
del node1['age']
graph.push(node1)# 略

# 删除整个节点但不删除关系
# 注! 不等于把关系一同删除了,所以我觉得应该是很少用的
graph.delete(node5)
# 删完之后不用push

# 删除关系属性
# del 关系[属性名]
del relation3['value']
graph.push(relation3)# 略

# 删除关系组,例如:将与目标节点相关的节点的所有关系都删除掉
# relation = RelationshipMatcher(graph)
# 关系组 = relation.match(nodes=[节点1,节点2],r_type = 关系类型,limit=None)
# for 关系 in 关系组:
#     graph.separate(关系)

# 基于关系类型 删除所有关系
# 生成关系匹配器
relation_matcher = RelationshipMatcher(graph) # 生成关系匹配器
# 删除所有couple关系
relations = relation_matcher.match(r_type='COUPLE')  # 可迭代对象
for relation in relations:
    graph.separate(relation)

# 基于节点 删除node1和node2的关系
# 生成关系匹配器
relation_matcher = RelationshipMatcher(graph) # 生成关系匹配器
# 找到 node1 和node2 之间的关系
relations = relation_matcher.match([node1,node2])
# 遍历所有匹配到的关系
for relation in relations:
    graph.separate(relation)

# 删除关系与两端
# graph.delete(关系)
graph.delete(relation2)# 删除relation2这个关系以及相关节点

# -----------------------
# ------    改    --------
# -----------------------

# 修改节点属性值
# 节点[属性名] = 属性值
node1['age']=26
graph.push(node1)# 略

# 修改关系属性值
relation2['strong']=90
graph.push(relation2)# 略

# -----------------------
# ------    查    --------
# -----------------------

# 节点查询
# 根据属性值查询满足条件的节点
# node_matcher = NodeMatcher(graph)# 创建节点匹配器
# node_matcher(节点类型1,节点类型2,属性1=属性值1,属性2=属性值2)# 提取满足属性值的节点
node_matcher = NodeMatcher(graph) # 节点匹配器
a = node_matcher.match('female',age=21) # 在节点类型中,提取满足属性值的节点

# 更具复杂规则的属性值查询满足条件的节点
# nodes = node_matcher.match()
# for node in nodes:
#     规则
node_matcher = NodeMatcher(graph) # 节点匹配器
nodes = node_matcher.match()# 直接提取所有节点(就是没有筛选条件的情况下)
# 进行便利,输出所有满足属性值的节点
for node in nodes:
    # ... 可以多层次筛选复杂的属性值
    if node['weight'] < 50:
        print(node)

# 关系查询
# 根据关系类型和属性查询关系
# relation_matcher = RelationshipMatcher(graph)# 创建关系匹配器
# relations = relation_matcher.match(r_type=关系类型,属性1=属性值1,属性2=属性值2)# 在该关系类型中找到属性值满足条件的关系
relation_matcher = RelationshipMatcher(graph)# 关系匹配器
relations = relation_matcher.match(r_type='KNOW',strong=60)# 匹配结果为字典构成的可迭代

# 根据复杂关系进行匹配
# relation_matcher = RelationshipMatcher(graph)# 创建关系匹配器
# relations = relation_matcher.match()# 找到
# for relation in relations:
#     规则
relation_matcher = RelationshipMatcher(graph)# 创建关系匹配器
relations = relation_matcher.match()# 提取所有关系
for relation in relations:
    # ..可以多层筛选复杂的属性值
    if relation['strong'] > 20:
        print(relation)

# 节点+关系
# graph.match(nides=[节点1,节点2],r_type=关系类型,limit=None)
graph.match(nides=[node1,node3],r_type='KNOW',limit=None)
# 其中limit指的是,匹配关系的最大数量
# param limit: maximum number of relationships to match (:const:`None` means unlimited)

# -----------------------
# ------   案例   --------
# -----------------------

# 常见数据操作案例展示
# --------- 1 ---------
graph = Graph() # 初始化该图
tx = graph.begin() # 开始一个Transaction
node_1 = Node("Person",name="Peter") # 第一个节点是一个名字叫做Peter的人
tx.create(node_1)
tx.push(node_1) # 将其push到服务器
# or
tx.commit()# 将以上更改一次提交

# --------- 2 ---------
# Cypher 语句增加一个外壳
# 运行一个cypher 语句 graph.run('a cypher expression')
result = graph.run('match (p:Paper) return p.title, p.author limit 20')


# cursor 相当于结果一个游标((a cursor is a navigator for a stream of records)
cursor = graph.run() # 返回一个cursor对象,可以使用循环对cursor
# 循环方法1,使用 forward:
while cursor.forward():
    print(cursor.current['name'])

# 循环方法2,使用 for
for record in cursor:
    print(record["name"])

# 将graph run 的结果进行呈现,并可以转为其他格式
graph.run().data() # 基本格式是list of dictionary
graph.run().to_data_frame() # pd.DataFrame
graph.run().to_ndarray() # numpy.ndarray
graph.run().to_subgraph()
graph.run().to_subgraph()
graph.run().to_table()

# --------- 3 ---------
# py2neo创建

a = Node("Person",name="Alice")
b = Node("Person",name="Bob")
r = Relationship(a,"KNOWS",b)
s = a|b|r # 操作符(|)将节点和关系组合到一个子图(Subgraph)对象中,
# 子图对象可以一次性传递给图数据库进行创建。
graph = Graph()
graph.create(s)

# py2neo中慎用merge,可以先做存在判断,然后再用create语句.
# py2neo如果匹配上则用当前实体覆盖数据库中的已有实体(优先覆盖)
# 而不是Cypher中检测标签和属性,如果已存在就不创建(优先不创建)
graph.merge(node_1,"Person","name")       # 根据name属性对person结点进行merge

# 对应Cypher语句
# match (c:course)
# merge (t:teacher {name:c.teacher})
# return c.name,c.teacher

# --------- 3 ---------
# py2neo查询

matcher_1 = NodeMatcher(graph) # 创建节点匹配器
# 让它在year=2017的条件下,标签为paper,ID属性为09076的结果
# node的类型仍然是NodeMatcher对象
node = matcher_1.match("Paper",ID='09076').where(year=2017)

matcher_2 = RelationshipMatcher(graph) # 创建关系匹配器
# relation的类型仍然是RelationshipMatcher对象
relation = matcher_2.match(r_type="Cited").limit(50) # 匹配类型为Cited的关系,最多五十条记录

# 使用这两个模块后返回仍然是NodeMatche对象,将其转换为实体
node_1 = matcher_1.match("Paper",ID='09076').first() # 取第一个匹配到的节点,类型为列表
result_1 = list(node) # 转换为列表
result_2 = list(result)# 类型为列表


# node和relationship也自带匹配属性
graph.nodes.match("Person").first() # 但运行速度更慢

# Cypher的原生匹配,没有限定类型
# match g = (p1:Person) -[r:]->(p2:Paper)
# where p2.year>2008
# return g,p1.name,r.type,p2.title

# --------- 4 ---------
# py2neo.ogm (Object-Graph Mapping),ogm是基于Graphobject的
'''
class Movie(GraphObject):
    __primarylabel__ = 'Movie'# 基础标签 电影
    __primarykey__ = 'title' # key属性 title

    title = Property()  # 影片名
    tag_line = Property('tagline')
    release = Property()  # 发行时间
    restricted = Label()  # 是否限制级

    actors = RelatedFrom("Person", "ACTED_IN")  # 演员关系,与 "Person" 类的 "ACTED_IN" 关系相连
    directors = RelatedFrom("Person", "DIRECTED")  # 导演关系,与 "Person" 类的 "DIRECTED" 关系相连
    producers = RelatedFrom("Person", "PRODUCED")  # 制片人关系,与 "Person" 类的 "PRODUCED" 关系相连

class Person(GraphObject):
    __primarykey__ = "name" #  key属性 name

    name = Property()
    acted_in = RelatedTo(Movie)  # 演员关系,与 "Movie" 类的关系相连

release = Property() # 指定release为属性,则可以赋值
M = Movie()
M.release = 1995

'''
;