查询数据库
写入数据库
要创建两个代表名为 Alice
和 David
的人物节点,以及它们之间的 KNOWS
关系,请使用 Cypher 子句 CREATE
summary = driver.execute_query(""" (1)
CREATE (a:Person {name: $name})
CREATE (b:Person {name: $friendName})
CREATE (a)-[:KNOWS]->(b)
""",
name="Alice", friendName="David", (2)
database_="neo4j", (3)
).summary
print("Created {nodes_created} nodes in {time} ms.".format(
nodes_created=summary.counters.nodes_created,
time=summary.result_available_after
))
1 | Cypher 查询 |
2 | 作为关键字参数的查询参数 |
3 | 运行查询的数据库 |
从数据库读取
要从数据库中检索信息,请使用 Cypher 子句 MATCH
人物
的人物
节点records, summary, keys = driver.execute_query("""
MATCH (p:Person)-[:KNOWS]->(:Person)
RETURN p.name AS name
""",
database_="neo4j",
)
# Loop through results and do something with them
for record in records: (1)
print(record.data()) # obtain record as dict
# Summary information (2)
print("The query `{query}` returned {records_count} records in {time} ms.".format(
query=summary.query, records_count=len(records),
time=summary.result_available_after
))
1 | records 包含结果,作为 Record 对象的数组 |
2 | summary 包含服务器返回的执行摘要 |
更新数据库
Alice
以添加 age
属性records, summary, keys = driver.execute_query("""
MATCH (p:Person {name: $name})
SET p.age = $age
""", name="Alice", age=42,
database_="neo4j",
)
print(f"Query counters: {summary.counters}.")
要创建一条新关系,将其链接到两个已存在的节点,请结合使用 Cypher 子句 MATCH
和 CREATE
Alice
和 Bob
之间创建 :KNOWS
关系records, summary, keys = driver.execute_query("""
MATCH (alice:Person {name: $name}) (1)
MATCH (bob:Person {name: $friend}) (2)
CREATE (alice)-[:KNOWS]->(bob) (3)
""", name="Alice", friend="Bob",
database_="neo4j",
)
print(f"Query counters: {summary.counters}.")
1 | 检索名为 Alice 的人物节点,并将其绑定到变量 alice |
2 | 检索名为 Bob 的人物节点,并将其绑定到变量 bob |
3 | 从绑定到 alice 的节点创建一个新的 :KNOWS 传出关系,并将其附加到名为 Bob 的 Person 节点 |
从数据库删除
要删除节点及其附带的任何关系,请使用 Cypher 子句 DETACH DELETE
Alice
节点# This does not delete _only_ p, but also all its relationships!
records, summary, keys = driver.execute_query("""
MATCH (p:Person {name: $name})
DETACH DELETE p
""", name="Alice",
database_="neo4j",
)
print(f"Query counters: {summary.counters}.")
查询参数
请勿将参数直接硬编码或拼接进查询中。相反,请始终使用占位符并指定Cypher 参数,如前面的示例所示。这是为了
-
性能优势:Neo4j 会编译和缓存查询,但只有在查询结构未更改的情况下才能这样做;
-
安全原因:请参阅防止 Cypher 注入。
查询参数可以作为多个关键字参数传递,或者作为值分组到字典中,作为 parameters_
关键字参数。如果混合使用,关键字参数的优先级高于字典参数。
driver.execute_query(
"MERGE (:Person {name: $name})",
name="Alice", age=42,
database_="neo4j",
)
parameters = {
"name": "Alice",
"age": 42
}
driver.execute_query(
"MERGE (:Person {name: $name})",
parameters_=parameters,
database_="neo4j",
)
您的任何关键字查询参数都不能以单个下划线结尾。这是为了避免与关键字配置参数冲突。如果您需要使用此类参数名称,请在 parameters_
字典中传递它们。
在某些情况下,您的查询结构可能会阻止在所有部分使用参数。对于这些罕见的用例,请参阅属性键、关系类型和标签中的动态值。 |
错误处理
由于 .execute_query()
可能会引发多种不同的异常,因此处理错误的最佳方法是在单个 try/except
块中捕获所有异常
try:
driver.execute_query(...)
except Exception as e:
... # handle exception
如果故障被认为是瞬时性的(例如由于服务器暂时不可用),驱动程序会自动重试运行失败的查询。如果操作在多次尝试后仍然失败,则会引发异常。 |
查询配置
您可以提供其他关键字参数来更改 .execute_query()
的默认行为。配置参数以 _
结尾。
数据库选择
建议始终使用 database_
参数显式指定数据库,即使在单数据库实例上也是如此。这可以使驱动程序更高效地工作,因为它节省了到服务器的网络往返以解析主数据库。如果未指定数据库,则使用用户的主数据库。
driver.execute_query(
"MATCH (p:Person) RETURN p.name",
database_="neo4j",
)
通过配置方法指定数据库优于使用 USE Cypher 子句。如果服务器在集群上运行,带有 USE 的查询需要启用服务器端路由。查询执行时间也可能更长,因为它们可能无法在第一次尝试时到达正确的集群成员,需要路由到包含所请求数据库的成员。 |
请求路由
在集群环境中,所有查询默认都定向到主节点。为了提高读取查询的性能,您可以使用参数 routing_="r"
将查询路由到读取节点。
driver.execute_query(
"MATCH (p:Person) RETURN p.name",
routing_="r", # short for neo4j.RoutingControl.READ
database_="neo4j",
)
尽管在读取模式下执行写入查询可能会导致运行时错误,但您不应依赖此进行访问控制。两种模式之间的区别在于,读取事务将被路由到集群的任何节点,而写入事务则定向到主节点。换句话说,无法保证以读取模式提交的写入查询将被拒绝。 |
以不同用户身份运行查询
您可以使用参数 auth_
通过不同的用户执行查询。在查询级别切换用户比创建新的 Driver
对象更经济。然后,查询将在给定用户的安全上下文(即主数据库、权限等)中运行。
查询范围的身份验证要求服务器版本 >= 5.8。
driver.execute_query(
"MATCH (p:Person) RETURN p.name",
auth_=("somebody_else", "their_password"),
database_="neo4j",
)
参数 impersonated_user_
提供了类似的功能,并且在驱动程序/服务器版本 >= 4.4 中可用。区别在于您不需要知道用户的密码即可模拟他们,但创建 Driver
的用户需要具有适当的权限。
driver.execute_query(
"MATCH (p:Person) RETURN p.name",
impersonated_user_="somebody_else",
database_="neo4j",
)
转换查询结果
您可以使用 result_transformer_
参数将查询结果转换为不同的数据结构。驱动程序提供了内置方法,可将结果转换为 pandas 数据帧或图,但您也可以自行编写转换器。
有关更多信息,请参阅操作查询结果。
完整示例
from neo4j import GraphDatabase
URI = "{neo4j-database-uri}"
AUTH = ("{neo4j-username}", "{neo4j-password}")
people = [{"name": "Alice", "age": 42, "friends": ["Bob", "Peter", "Anna"]},
{"name": "Bob", "age": 19},
{"name": "Peter", "age": 50},
{"name": "Anna", "age": 30}]
with GraphDatabase.driver(URI, auth=AUTH) as driver:
try:
# Create some nodes
for person in people:
records, summary, keys = driver.execute_query(
"MERGE (p:Person {name: $person.name, age: $person.age})",
person=person,
database_="neo4j",
)
# Create some relationships
for person in people:
if person.get("friends"):
records, summary, keys = driver.execute_query("""
MATCH (p:Person {name: $person.name})
UNWIND $person.friends AS friend_name
MATCH (friend:Person {name: friend_name})
MERGE (p)-[:KNOWS]->(friend)
""", person=person,
database_="neo4j",
)
# Retrieve Alice's friends who are under 40
records, summary, keys = driver.execute_query("""
MATCH (p:Person {name: $name})-[:KNOWS]-(friend:Person)
WHERE friend.age < $age
RETURN friend
""", name="Alice", age=40,
routing_="r",
database_="neo4j",
)
# Loop through results and do something with them
for record in records:
print(record)
# Summary information
print("The query `{query}` returned {records_count} records in {time} ms.".format(
query=summary.query, records_count=len(records),
time=summary.result_available_after
))
except Exception as e:
print(e)
# further logging/processing
有关更多信息,请参阅API 文档 → Driver.execute_query()。
术语表
- LTS
-
长期支持版本是保证支持数年的版本。Neo4j 4.4 是 LTS 版本,Neo4j 5 也将有 LTS 版本。
- Aura
-
Aura 是 Neo4j 的完全托管云服务。它提供免费和付费计划。
- Cypher
-
Cypher 是 Neo4j 的图查询语言,可让您从数据库中检索数据。它类似于 SQL,但适用于图。
- APOC
-
Awesome Procedures On Cypher (APOC) 是一个函数库(其中包含许多函数),这些函数本身无法在 Cypher 中轻松表达。
- Bolt
-
Bolt 是 Neo4j 实例和驱动程序之间交互所使用的协议。它默认监听端口 7687。
- ACID
-
原子性、一致性、隔离性、持久性 (ACID) 是保证数据库事务可靠处理的属性。符合 ACID 的 DBMS 确保即使发生故障,数据库中的数据也能保持准确和一致。
- 最终一致性
-
如果数据库提供所有集群成员将在某个时间点存储最新版本数据的保证,则该数据库是最终一致的。
- 因果一致性
-
如果读写查询在集群的每个成员中以相同的顺序可见,则数据库是因果一致的。这比最终一致性更强。
- NULL
-
null 标记不是类型,而是值缺失的占位符。有关更多信息,请参阅Cypher → 使用
null
。 - 事务
-
事务是一个工作单元,它要么整体提交,要么在失败时回滚。一个例子是银行转账:它涉及多个步骤,但它们必须全部成功或被撤销,以避免钱从一个账户中扣除而没有添加到另一个账户。
- 背压
-
背压是一种阻碍数据流动的力。它确保客户端不会被比其处理能力更快的数据淹没。
- 事务函数
-
事务函数是由
execute_read
或execute_write
调用执行的回调。如果服务器故障,驱动程序会自动重新执行该回调。 - 驱动程序
-
一个
Driver
对象包含与 Neo4j 数据库建立连接所需的详细信息。