#!/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
'''