操作查询结果

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

作为列表的结果

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

records, summary, keys = driver.execute_query(
    "MATCH (a:Person) RETURN a.name AS name, a.age AS age",
    database_="<database-name>",
)
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

驱动程序可以通过设置 result_transformer_=neo4j.Result.to_df 将结果转换为 Pandas DataFrame。此方法需要安装 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_="<database-name>",
    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)

转换为图形

驱动程序可以通过设置 result_transformer_=neo4j.Result.graph 将结果转换为图形对象集合。为了充分利用此方法,您的查询应该返回图形类型的结果,而不是单列结果。图形转换器返回一个 Graph 对象,该对象公开了 nodesrelationships 属性,它们分别是 NodeRelationship 对象的集合视图。

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

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


URI = "<database-uri>"
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_="<database-name>",
        )

        # 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_="<database-name>",
        )

        # 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_="<database-name>",
    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_="<database-name>",
    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 (长期支持版)

长期支持 (Long Term Support) 版本是保证在若干年内得到支持的版本。Neo4j 4.4 和 5.26 是 LTS 版本。

Aura

Aura 是 Neo4j 的全托管云服务。它提供免费和付费计划。

Cypher

Cypher 是 Neo4j 的图查询语言,允许您从数据库中检索数据。它就像 SQL,但专用于图数据库。

APOC

Awesome Procedures On Cypher (APOC) 是一个包含(许多)函数的库,这些函数在 Cypher 本身中难以轻松实现。

Bolt

Bolt 是用于 Neo4j 实例和驱动程序之间交互的协议。默认监听 7687 端口。

ACID

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

最终一致性

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

因果一致性

如果读写查询被集群中的每个成员以相同的顺序看到,则数据库具有因果一致性。这比最终一致性更强。

NULL

空标记不是一种类型,而是缺失值的占位符。更多信息,请参阅 Cypher → 使用 null

事务

事务是一个工作单元,要么被提交,要么在失败时被回滚。例如银行转账:它涉及多个步骤,但它们必须全部成功或全部撤销,以避免钱从一个账户扣除却未存入另一个账户的情况。

背压

背压是对数据流的抵抗力。它确保客户端不会被过快发送的数据压垮,从而超出其处理能力。

书签

书签是代表数据库某种状态的标记。通过将一个或多个书签与查询一起传递,服务器将确保在所表示的状态建立之前,该查询不会被执行。

事务函数

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

驱动程序 (Driver)

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