本文简介
通过 desktop 创建一个新的项目 wilson,它会要求输入密码,并会自动创建一个 neo4j 数据库
启动这个数据库之后,使用 python API 进行连接
连接方法:
# Import the neo4j dependency
from neo4j import GraphDatabase
# Create a new Driver instance
driver = GraphDatabase.driver("neo4j://localhost:7687",
auth=("neo4j", "al*****0"))
# Verify the connection details
driver.verify_connectivity()
对于连接参数
neo4j
:未加密连接,neo4j+s
:加密连接blot
:用于直接连接到单个 DBMS (在集群环境或独立环境中)。如果您只配置了一台用于数据科学或分析的服务器,那么这将非常有用。
增加一个驱动 Driver
- neo4j 的 python 驱动就是
pip install neo4j
提供 - 创建驱动实例
-
neo4j 的
GraphDatabase
创建驱动实例# Import the neo4j dependency from neo4j import GraphDatabase # Create a new Driver instance driver = GraphDatabase.driver("neo4j://localhost:7687", auth=("neo4j", "neo")) driver.verify_connectivity()
-
session 和 transaction 事务
- 创建一个会话
with driver.session(database="people") as session:
一个会话可以有多个和数据库的 socket 连接
- 事务 transaction
事物是原子的、一致的、隔离和持久的。驱动公开了三种类型的事务:
- 自动提交的事务 auto-commit
- read
- write
- auto-commit transaction
- 一个单独的工作单元,可以针对 DBMS 立即执行并立即得到确认
-
可通过 session 上的 run() 进行连接
session.run( "MATCH (p:Person {name: $name}) RETURN p", # Query name="Tom Hanks" # Named parameters referenced ) # in Cypher by prefixing with a $
4. read transaction
-
session 有
execute_read()
方法session.execute_read(get_movies, title="Arthur") def get_movies(tx, title): return tx.run(""" MATCH (p:Person)-[:ACTED_IN]->(m:Movie) WHERE m.title = $title // (1) RETURN p.name AS name LIMIT 10 """, title=title)
5. write transaction
session.execute_write(create_person, name="Michael")
def create_person(tx, name):
return tx.run( "CREATE (p:Person {name: $name})", name=name)
- 手动创建事务 transaction
- 通过 session 上的
start_action
创建事务对象
with session.begin_transaction() as tx:
- 手动创建的事务,要手动进行commit或roll_back回溯,而 `execute_read/write` 不用
try: # Run a query tx.run(query, **params) # Commit the transaction tx.commit() except: # If something goes wrong in the try block, # then rollback the transaction tx.rollback()
- 通过 session 上的
- 关闭会话
session.close()
事务处理结果
# Unit of work
def get_actors(tx, movie): # (1)
result = tx.run("""
MATCH (p:Person)-[:ACTED_IN]->(:Movie {title: $title})
RETURN p
""", title=movie)
# Access the `p` value from each record
return [ record["p"] for record in result ]
# Open a Session
with driver.session() as session:
# Run the unit of work within a Read Transaction
actors = session.execute_read(get_actors, movie="The Green Mile") # (2)
for record in actors:
print(record["p"])
session.close()
get_actors
是在事务中执行的工作单元-
actors
是一个迭代器,可以用peek()
方法检查peek = result.peek() print(peek)
- 获取结果中每条记录,可以用
result.keys()
- 只需要一要记录,可以用:
result.single()
-
只需要提取单个值:
result.value()
def get_actors_values(tx, movie): result = tx.run(""" MATCH (p:Person)-[r:ACTED_IN]->(m:Movie {title: $title}) RETURN p.name AS name, m.title AS title, r.roles AS roles """, title=movie) return result.value("name", False) # Returns the `name` value, or False if unavailable
-
提取多个条目,用
result.values()
def get_actors_values(tx, movie): result = tx.run(""" MATCH (p:Person)-[r:ACTED_IN]->(m:Movie {title: $title}) RETURN p.name AS name, m.title AS title, r.roles AS roles """, title=movie) return result.values("name", "title", "roles")
- 消耗
consume()
把结果剩余部分返回到ResultSummary
中-
“结果摘要”包含有关服务器、查询、执行时间和计数器对象的信息,计数器对象提供有关查询的统计信息。
def get_actors_consume(tx, name): result = tx.run(""" MERGE (p:Person {name: $name}) RETURN p """, name=name) info = result.consume() # The time it took for the server to have the result available. (milliseconds) print(info.result_available_after) # The time it took for the server to consume the result. (milliseconds) print(info.result_consumed_after) print("{0} nodes created".format(info.counters.nodes_created)) print("{0} properties set".format(info.counters.properties_set))
-
neo4j 的类型系统
node & relationships
result = tx.run("""
MATCH path = (person:Person)-[actedIn:ACTED_IN]->(movie:Movie {title: $title})
RETURN path, person, actedIn, movie
""", title=movie)
查询为每个 :Persion
和 :Movie
节点返回一条记录,它们之间的关系是 :ACTED_IN
节点 Nodes
-
从结果中检索出
movie
的值for record in result: node = record["movie"] print(node.id) # (1) print(node.labels) # (2) print(node.items()) # (3) # (4) print(node["name"]) print(node.get("name", "N/A"))
- 分配给 python 节点变量
node
的值是 neo4j 的Node
类型的实例 - id 对应 Node 的ID
- labels 属性是一个冻结集,包含属于 Node 的标签数组:
['Persion', 'Actor']
- items() 方法,节点 node 的属性
get()
检索单个属性
关系
acted_in = record["actedIn"]
print(acted_in.id) # (1)
print(acted_in.type) # (2)
print(acted_in.items()) # (3)
# 4
print(acted_in["roles"])
print(acted_in.get("roles", "(Unknown)"))
print(acted_in.start_node) # (5)
print(acted_in.end_node) # (6)
type
:保存关系类型,如:ACTED_IN
start_node
:表示关系开始处节点的内部 ID 的整数end_node
:关系结束时节点的内部 ID
路径 Paths
如果返回 node 和 relationship 的 path,它们将作为 Path 的实例被返回
path = record["path"]
print(path.start_node) # (1)
print(path.end_node) # (2)
print(len(path)) # (1)
print(path.relationships) # (1)
len(path)
:路径中关系的计数relationships
:路径中关系对象数组
路径段 Path Segments
- 路径被分割成代表路径中每个关系的段
- 比如路径
(p:Person)-[:ACTED_IN]→(m:Movie)-[:IN_GENRE]→(g:Genre)
(p:Person)-[:ACTED_IN]→(m:Movie)
(p:Person)-[:ACTED_IN]→(m:Movie)
-
路径中的关系可以用
iter()
来迭代for rel in iter(path): print(rel.type) print(rel.start_node) print(rel.end_node)
Cypher 基础内容
从 neo4j 读取数据
本内容的领域模式
Cypher 是为图设计的查询语言。
- 节点由
()
表示 :
表示标签,如(:Person)
- 关系由破折号表示:
(:Person)--(:Movie)
- 关系的方向由箭头表示:
(:Person)-->(:Movie)
- 关系的类型由方括号表示:
[:ACTED_IN]
- 属性于字典表示:
{name: 'Tom Hanks'}
-
Cypher 模式
(m:MOvie {title: ‘Cloud Atlas'})<-[:ACTED_IN]-(p:Person)
- 两个节点类型是:
Movie
和Person
- 定向
ACTED_IN
关系 - 特定的 Movie 节点可以通过
title
属性筛选
- 两个节点类型是:
Cypher 如何工作的
- Cypher 通过匹配数据中的模式来工作
- 使用
MATCH
检索数据 -
从图中找一个
Person
节点,我们可以用 MATCH 配合一个带有标签:Person
的节点来检索MATCH (:Person)
-
想检索所有的
Person
节点,在:
前分配一个变量,由它表示所有的Person
节点MATCH (p:Person) RETURN p
-
找到特定属性的节点,用
{}
的内联方法指定要匹配的属性值MATCH (p:Person {name: 'Tom Hanks'}) RETURN p
-
在 Cypher 中,可以用
.
访问节点的属性,比如只返回 name 属性值MATCH (p: Person {name: 'Tom Hanks'}) RETURN p.born
- Cypher 关键字不分大小写,但标签、属性键、变量区分
-
使用
where
筛选match (p:Person) where p.name = 'Tom Hanks' or p.name = 'Rita Wilson' return p.name, p.born
找关系
-
可以扩展匹配模式,遍历有
ACTED_IN
关系类型的任意节点,match (p:Person {name: 'Tom Hanks'})-[:ACTED_IN]->()
-
数据模型可以找到指向的节点是
(m:Moive)
所以我们可以用match (p:Person {name: 'Tom Hanks'})-[:ACTED_IN]->(m) return m.title
-
这就返回了 Tom Hanks 演的电影标题
-
过滤查询
-
查询2008和2009年的电影
match (p:Person)-[:ACTED_IN]->(m:Moive) where m.released=2009 or m.released=2008 return p,m
-
返回《黑客帝国》演员的名字
match (p:Person)-[:ACTED_IN]->(m:Moive) where m.title='The Matrix' return p.name
也可以
match (p)-[:ACTED_IN]->(m) where p:Person and m:Moive and m.title='The Matrix' return p.name
-
范围匹配
match (p:Person)-[:ACTED_IN]->(m:Movie) where 2000 <= m.released<= 2009 return p.name
-
根据属性存在筛选
match (p:Person)-[:ACTED_IN]->(m:Movie) where p.name='Jack Nocholson' and m.tagline is not null return p.name
-
字符串筛选
match (p:Person)-[:ACTED_IN]->(m:Movie) where p.name starts with 'Michael' return p.name
- 可以是
starts with
,ends with
,contains
-
转小写
toLower()
和toUpper()
match (p:Person)-[:ACTED_IN]->(m:Movie) where toLower(p.name) starts with 'michael' return p.name
- 可以是
-
根据图的模式过滤:找到写了电影但是没有导演电影的人
match (p:Person)-[:WROTE]->(m:Moive) where not exists( (p)-[:DIRECTED]->(m) ) return p.name, m.titile
-
使用列表筛选,列表是同类型元素
match (p:Person)-[:WROTE]->(m:Moive) where p.born in [1995, 1967, 1945] return p.name, m.titile
-
把值和图中现有列表比较
match (p:Person)-[r:ACTED_IN]->(m:Moive) where 'Neo' in r.roles and m.title='The Matrix' return p.name, m.titile
节点或关系有哪些属性?
-
发现节点的属性
match (p:Person) return p.name, keys(p)
keys()函数返回节点属性的列表
-
发现图中的所有属性
call db.propertyKeys()
创建节点
- 我们使用 MERGE 关键字在数据库中创建一个模式
- 在 MERGE 关键字之后,我们指定要创建的模式。通常这将是一个单一的节点或两个节点之间的关系。
-
创建一个代表 Michael Cain 的节点
``` merge (p:Person {name: 'Michael Cain'}) ``` - 请注意,在使用 MERGE 创建节点时,必须至少指定一个属性作为该节点的唯一主键
-
我们还可以将多个 MERGE 子句链接在一个 Cypher 代码块中
merge (p:Person {name: 'Kaite Holems'}) merge (m:Movie {title: 'The Dark Kngiht'}) return p, m
- 创建两个节点,每个节点具有一个主键属性
- 使用
create
- 使用 CREATE 的好处是在添加节点之前不会查找主键。如果您确信数据是干净的,并且希望在导入期间获得更快的速度,则可以使用 CREATE
- 我们使用 MERGE,因为它消除了节点的重复
创建关系
- 两个节点间的关系必须有:类型和方向
-
先找到两个已知的节点,再创建他们的关系
``` match (p:Person {name: 'Michael Cain'}) match (m:Movie {titile: 'The Dark Kngiht'}) merge (p)-[:ACTED_IN]->(m) ``` - 我们创建了两个节点间的 `ACTED_IN` 关系 - 通过 match 确认关系存在 ``` match (p:Person {name: 'Michael Cain'})-[r:ACTED_IN]-(m:Movie {titile: 'The Dark Kngiht'}) return p, m ``` - 在 `match` 中可以不指定方向 - 如果方向指错了,不会返回任何结果
-
-
连续使用多个merge子句
MERGE (p:Person {name: 'Chadwick Boseman'}) MERGE (m:Movie {title: 'Black Panther'}) MERGE (p)-[:ACTED_IN]-(m)
- 关系方向默认从左到右
-
使用单子句同时创建节点和关系
MERGE (p:Person {name: 'Emily Blunt'})-[:ACTED_IN]->(m:Movie {title: 'A Quiet Place'}) RETURN p, m
更新属性
-
设置关系的内联属性
MERGE (p:Person {name: 'Michael Cain'}) MERGE (m:Movie {title: 'Batman Begins'}) MERGE (p)-[:ACTED_IN {roles: ['Alfred Penny']}]->(m) return m, p
-
使用 set 关键字
match (p:Person)-[r:ACTED_IN]->(m:Movie) where p.name='Michael Cain' and m.title='The Dark Kngiht' set r.roles = ['Alfred Penny'], r.year = 2008 return p, r, m
- 设置多个属性用
,
分隔 - 更新也同样使用
set
- 设置多个属性用
-
删除属性用
remove
或者set xxx = null
match (p:Person)-[r:ACTED_IN]->(m:Movie) where p.name='Michael Cain' and m.title='The Dark Kngiht' remove r.roles return p, m
-
或者使用
set null
match (p:Person) set p.roles = null return p
-
merge 的处理
-
我们可以在创建节点和找到节点时,设置属性
merge (p:Person {name: 'Michael Cain'}) on create set p.createAt = datetime(), m.released=2008 on match set p.updateAt = datetime() set p.born = 2006 return p
- 当 merge 创建节点时,设置 createAt 属性
- 当 merge 找到节点时,设置 updataAt 属性
- 无论怎样,都设置 born 属性
- merge 实际上是 find 和 create 的合并操作
删除
- neo4j 中可以删除的元素有:节点、关系、标签、属性
-
删除孤立的节点
match (p:Person) where p.name = 'Michael Cain' delete p
-
删除关系
match (p:Person {name: 'Jane Doe'})-[r: ACTED_IN]->(m:Movie {title: 'The Matrix'}) delete r return p, m
-
删除有关系的节点
match (p:Person {name: 'Jane Doe'}) detach delete p
- 删除了它的关系和节点
-
清除图中所有节点
match (n) detach delete n
-
删除标签
match (p:Person {name: 'Jane Doe'}) set p:Developer return p
- 这里节点变成
(p:person :Developer {name: 'Jane Doe'})
-
可以用 remove 删除标签
match (p:Person {name: 'Jane Doe'}) remove p:Developer return p
- 这里节点变成
-
图中存在哪些标签
call db.labels()