Reputation: 2776
I'm trying to understand how to query a neo4j database, and turn the result into a networkx graph. I can query the (movie graph) database and obtain a result, but I can find a simple way to turn the result into a networkx graph. Is it possible to do something like below?
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)
Upvotes: 5
Views: 8696
Reputation: 131
Here is a more compact code:
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)
Keep in mind that MATCH (n)-[r]->(c) RETURN *
query may not retrieve the entire neo4j graph since unconnected nodes will be omitted. If you need your entire graph with unconnected nodes, add nodes from the results of MATCH (n) RETURN n
query and then add relations from MATCH (n)-[r]->(c) RETURN *
Upvotes: 13
Reputation: 2776
After failing to get a few attempted solutions I found online to work, I ended up writing a function for this myself. Posting it here in case it's helpful to anyone.
This works by iterating over the results, figuring out whether each entry encountered is a node or a relation (edge) and adding it to the graph if it hasn't been added yet. I'm new to cypher/neo4j and not certain if Node/Relation is exhaustive of what the results might be, so at present I just raise an error should anything else be encountered.
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())
Upvotes: 15