操作查询结果

本节介绍如何处理查询结果,以便以最适合您的应用程序的形式提取数据。

结果作为列表

默认情况下,Driver.execute_query() 返回一个 EagerResult 对象。

records, summary, keys = driver.execute_query(
    "MATCH (a:Person) RETURN a.name AS name, a.age AS age",
    database_="neo4j",
)
for person in records:  (1)
    print(person)
    # person["name"] or person["age"] are also valid

# Some summary information  (2)
print("Query `{query}` returned {records_count} records in {time} ms.".format(
    query=summary.query, records_count=len(records),
    time=summary.result_available_after
))

print(f"Available keys are {keys}")  # ['name', 'age'] (3)
1 结果记录作为一个列表,因此很容易循环遍历它们。
2 一个 执行摘要,包含元数据和有关结果的信息。
3 返回行中可用的keys

转换为 Pandas DataFrame

驱动程序可以将结果转换为 Pandas DataFrame。要实现此目的,请使用.execute_query() 关键字参数result_transformer_ 并将其设置为neo4j.Result.to_df。此方法仅在安装了pandas 库的情况下可用。

返回一个包含两列 (n, m) 和 10 行的 DataFrame
import neo4j

pandas_df = driver.execute_query(
    "UNWIND range(1, 10) AS n RETURN n, n+1 AS m",
    database_="neo4j",
    result_transformer_=neo4j.Result.to_df
)
print(type(pandas_df))  # <class 'pandas.core.frame.DataFrame'>

此转换器接受两个可选参数

  • expand — 如果为True,结果中的一些数据结构将被递归扩展和平展。有关更多信息,请参阅 API 文档

  • parse_dates — 如果为True,将仅包含time.DateTime 对象、time.Date 对象或None 的列将转换为pandas.Timestamp

如果需要将参数传递给to_df,请使用lambda 函数
result_transformer_=lambda res: res.to_df(True)

转换为图

驱动程序可以将结果转换为图对象集合。要实现此目的,请使用.execute_query() 关键字参数result_transformer_ 并将其设置为neo4j.Result.graph。为了充分利用此方法,您的查询应返回类似于图的结果,而不是单个列。图转换器返回一个 Graph 对象,它公开属性nodesrelationships,它们是 NodeRelationship 对象的设置视图。

您可以使用图格式进行进一步处理或可视化查询结果。以下是一个使用pyvis 库绘制图的示例实现。

使用pyvis 可视化图结果
import pyvis
from neo4j import GraphDatabase
import neo4j


URI = "<URI for Neo4j database>"
AUTH = ("<Username>", "<Password>")


def main():
    with GraphDatabase.driver(URI, auth=AUTH) as driver:
        # Create some friends
        input_list = [("Arthur", "Guinevre"),
                      ("Arthur", "Lancelot"),
                      ("Arthur", "Merlin")]
        driver.execute_query("""
            UNWIND $pairs AS pair
            MERGE (a:Person {name: pair[0]})
            MERGE (a)-[:KNOWS]->(friend:Person {name: pair[1]})
            """, pairs=input_list,
            database_="neo4j",
        )

        # Create a film
        driver.execute_query("""
            MERGE (film:Film {title: $title})
            MERGE (liker:Person {name: $person_name})
            MERGE (liker)-[:LIKES]->(film)
            """, title="Wall-E", person_name="Arthur",
            database_="neo4j",
        )

        # Query to get a graphy result
        graph_result = driver.execute_query("""
            MATCH (a:Person {name: $name})-[r]-(b)
            RETURN a, r, b
            """, name="Arthur",
            result_transformer_=neo4j.Result.graph,
        )

        # Draw graph
        nodes_text_properties = {  # what property to use as text for each node
            "Person": "name",
            "Film": "title",
        }
        visualize_result(graph_result, nodes_text_properties)


def visualize_result(query_graph, nodes_text_properties):
    visual_graph = pyvis.network.Network()

    for node in query_graph.nodes:
        node_label = list(node.labels)[0]
        node_text = node[nodes_text_properties[node_label]]
        visual_graph.add_node(node.element_id, node_text, group=node_label)

    for relationship in query_graph.relationships:
        visual_graph.add_edge(
            relationship.start_node.element_id,
            relationship.end_node.element_id,
            title=relationship.type
        )

    visual_graph.show('network.html', notebook=False)


if __name__ == "__main__":
    main()
pyvis example
图 1. 上述示例的图形可视化

自定义转换器

对于更高级的场景,您可以使用参数result_transformer_ 来提供一个自定义函数,该函数进一步操纵来自查询的 Result 对象。转换器接收一个Result 对象,并且可以输出任何数据结构。转换器的返回值反过来由.execute_query() 返回。

在转换器函数内部,您可以使用 任何Result 方法

使用singleconsume 的自定义转换器
# Get a single record (or an exception) and the summary from a result.
def get_single_person(result):
    record = result.single(strict=True)
    summary = result.consume()
    return record, summary


record, summary = driver.execute_query(
    "MERGE (a:Person {name: $name}) RETURN a.name AS name",
    name="Alice",
    database_="neo4j",
    result_transformer_=get_single_person,
)
print("The query `{query}` returned {record} in {time} ms.".format(
      query=summary.query, record=record, time=summary.result_available_after))
使用fetchpeek 的自定义转换器
# Get exactly 5 records, or an exception.
def exactly_5(result):
    records = result.fetch(5)

    if len(records) != 5:
        raise Exception(f"Expected exactly 5 records, found only {len(records)}.")
    if result.peek():
        raise Exception("Expected exactly 5 records, found more.")

    return records


records = driver.execute_query("""
    UNWIND ['Alice', 'Bob', 'Laura', 'John', 'Patricia'] AS name
    MERGE (a:Person {name: name}) RETURN a.name AS name
    """, database_="neo4j",
    result_transformer_=exactly_5,
)

转换器不能返回Result 对象本身。这样做大致等同于返回指向结果缓冲区的指针,该缓冲区在查询的事务结束时将失效。

def transformer(result):
    return result

result = driver.execute_query(
    "MATCH (a:Person) RETURN a.name",
    result_transformer_=transformer)
print(result)
print(result.single())
neo4j.exceptions.ResultConsumedError: The result is out of scope.
The associated transaction has been closed.
Results can only be used while the transaction is open.

术语表

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 数据库连接所需的详细信息。