从 neo4j 查询结果构建 NetworkX 图?

Constructing NetworkX graph from neo4j query result?

我正在尝试了解如何查询 neo4j 数据库,并将结果转换为 networkx 图。我可以查询(电影图)数据库并获得结果,但我可以找到一种简单的方法将结果转换为 networkx 图。是否可以执行以下操作?

from neo4j import GraphDatabase
import networkx as nx

driver = GraphDatabase.driver('bolt://localhost:7687', auth=("neo4j", "hunter2"))

query = """
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE toLower(m.title) CONTAINS "you"
RETURN *
"""

with driver.session() as session:
    result = session.run(query)

# This bit doesn't work
G = nx.Graph(result)

我在网上找到的一些尝试性解决方案都没有成功,最后我自己为此编写了一个函数。将它张贴在这里以防对任何人有帮助。

这通过迭代结果来工作,确定遇到的每个条目是节点还是关系(边),如果尚未添加,则将其添加到图中。我是 cypher/neo4j 的新手,不确定 Node/Relation 是否详尽无遗,所以目前我只是在遇到任何其他问题时提出错误。

from neo4j import GraphDatabase
from neo4j.types.graph import Node, Relationship
import pandas as pd
import networkx as nx

def graph_from_cypher(data):
    """Constructs a networkx graph from the results of a neo4j cypher query.
    Example of use:
    >>> result = session.run(query)
    >>> G = graph_from_cypher(result.data())

    Nodes have fields 'labels' (frozenset) and 'properties' (dicts). Node IDs correspond to the neo4j graph.
    Edges have fields 'type_' (string) denoting the type of relation, and 'properties' (dict)."""

    G = nx.MultiDiGraph()
    def add_node(node):
        # Adds node id it hasn't already been added
        u = node.id
        if G.has_node(u):
            return
        G.add_node(u, labels=node._labels, properties=dict(node))

    def add_edge(relation):
        # Adds edge if it hasn't already been added.
        # Make sure the nodes at both ends are created
        for node in (relation.start_node, relation.end_node):
            add_node(node)
        # Check if edge already exists
        u = relation.start_node.id
        v = relation.end_node.id
        eid = relation.id
        if G.has_edge(u, v, key=eid):
            return
        # If not, create it
        G.add_edge(u, v, key=eid, type_=relation.type, properties=dict(relation))

    for d in data:
        for entry in d.values():
            # Parse node
            if isinstance(entry, Node):
                add_node(entry)

            # Parse link
            elif isinstance(entry, Relationship):
                add_edge(entry)
            else:
                raise TypeError("Unrecognized object")
    return G

driver = GraphDatabase.driver('bolt://localhost:7687', auth=("neo4j", "hunter2"))

query = """
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE toLower(m.title) CONTAINS "you"
RETURN *
"""

with driver.session() as session:
    result = session.run(query)

# This works
G = graph_from_cypher(result.data())

这是一个更紧凑的代码:

from neo4j import GraphDatabase
import networkx as nx

driver = GraphDatabase.driver('bolt://localhost:7687', auth=("neo4j", "neo4jj"))

query = """
MATCH (n)-[r]->(c) RETURN *
"""

results = driver.session().run(query)

G = nx.MultiDiGraph()

nodes = list(results.graph()._nodes.values())
for node in nodes:
    G.add_node(node.id, labels=node._labels, properties=node._properties)

rels = list(results.graph()._relationships.values())
for rel in rels:
    G.add_edge(rel.start_node.id, rel.end_node.id, key=rel.id, type=rel.type, properties=rel._properties)

请记住,MATCH (n)-[r]->(c) RETURN * 查询可能无法检索整个 neo4j 图,因为未连接的节点将被忽略。如果您需要包含未连接节点的整个图,请从 MATCH (n) RETURN n 查询的结果中添加节点,然后从 MATCH (n)-[r]->(c) RETURN *

添加关系