查询数据库

连接到数据库后,您可以使用 CypherDriver.execute_query() 方法运行查询。

Driver.execute_query() 是在驱动程序 5.8 版本中引入的。
对于早期版本的查询,请使用 会话和事务

写入数据库

要创建一个表示名为 Alice 的人的节点,请使用 Cypher 子句 CREATE

创建一个表示名为 Alice 的人的节点
summary = driver.execute_query(
    "CREATE (:Person {name: $name})",  (1)
    name="Alice",  (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

检索所有 Person 节点
records, summary, keys = driver.execute_query(
    "MATCH (p: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 包含服务器返回的 执行摘要

更新数据库

要更新数据库中节点的信息,请使用 Cypher 子句 MATCHSET

更新节点 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 子句 MATCHCREATE

AliceBob 之间创建一个 :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 创建一个新的 :KNOWS 关系,该关系从绑定到 alice 的节点发出并连接到名为 BobPerson 节点

从数据库删除

要删除节点及其所有连接的关系,请使用 Cypher 子句 DETACH DELETE

删除 Alice 节点
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 参数,如前面的示例所示。这是为了

  1. 性能优势:Neo4j 会编译和缓存查询,但只有在查询结构不变的情况下才能这样做;

  2. 安全原因:请参阅 防止 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_ 参数显式指定数据库,即使在单数据库实例上也是如此。这可以让驱动程序更高效地工作,因为它可以节省与服务器的网络往返以解析主数据库。如果没有提供数据库,则使用 用户的 home 数据库

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",
)

虽然在读取模式下执行写入查询可能会导致运行时错误,但您不应该依赖它来进行访问控制。这两种模式之间的区别在于,读取事务将被路由到集群的任何节点,而写入事务将被直接发送到领导者。换句话说,不能保证以读取模式提交的写入查询会被拒绝。

以其他用户身份运行查询

您可以使用参数 impersonated_user_ 在不同用户的安全上下文中执行查询,并指定要模拟的用户名。为了使此操作成功,创建 Driver 的用户需要具有 相应的权限。模拟用户比创建新的 Driver 对象更便宜。

driver.execute_query(
    "MATCH (p:Person) RETURN p.name",
    impersonated_user_="somebody_else",
    database_="neo4j",
)

模拟用户时,查询将在模拟用户的完整安全上下文中运行,而不是在经过身份验证的用户(即 home 数据库、权限等)的上下文中运行。

转换查询结果

您可以使用 result_transformer_ 参数将查询的结果转换为不同的数据结构。驱动程序提供了将结果转换为 pandas 数据框或图形的内置方法,但您也可以制作自己的转换器。

有关更多信息,请参阅 操作查询结果

一个完整的示例

from neo4j import GraphDatabase


URI = "<URI for Neo4j database>"
AUTH = ("<Username>", "<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

Cypher 上的绝佳程序 (APOC) 是一个包含(许多)函数的库,这些函数不能轻易用 Cypher 本身表达。

Bolt

Bolt 是用于 Neo4j 实例和驱动程序之间交互的协议。默认情况下,它在端口 7687 上监听。

ACID

原子性、一致性、隔离性和持久性 (ACID) 是保证数据库事务可靠处理的属性。符合 ACID 的 DBMS 确保数据库中的数据即使在发生故障时也能保持准确和一致。

最终一致性

如果数据库保证所有集群成员在某个时间点存储数据的最新版本,则该数据库是最终一致的。

因果一致性

如果数据库保证所有集群成员以相同的顺序看到读写查询,则该数据库是因果一致的。这比最终一致性更强大。

NULL

空标记不是一种类型,而是用于表示值不存在的占位符。有关更多信息,请参阅 Cypher → 使用null

事务

事务是工作的单位,要么完全提交,要么在失败时回滚。一个例子是银行转账:它涉及多个步骤,但这些步骤必须全部成功或被恢复,以避免从一个帐户中扣款而没有添加到另一个帐户中。

背压

背压是反对数据流的力。它确保客户端不会被比其处理能力更快的速度接收的数据淹没。

事务函数

事务函数是由execute_readexecute_write调用执行的回调。如果服务器出现故障,驱动程序会自动重新执行回调。

驱动程序

一个 Driver 对象保存了与 Neo4j 数据库建立连接所需的信息。