Neo4j 使用 py2neo 从 pandas 数据帧创建节点和关系
Neo4j create nodes and relationships from pandas dataframe with py2neo
使用 py2neo 从 Neo4j 数据库的密码查询中获取 pandas 数据帧的结果非常简单,因为:
>>> from pandas import DataFrame
>>> DataFrame(graph.data("MATCH (a:Person) RETURN a.name, a.born LIMIT 4"))
a.born a.name
0 1964 Keanu Reeves
1 1967 Carrie-Anne Moss
2 1961 Laurence Fishburne
3 1960 Hugo Weaving
现在我正在尝试使用 py2neo 从 pandas 数据帧创建(或更好地合并)一组节点和关系到 Neo4j 数据库中。想象一下我有一个像这样的数据框:
LABEL1 LABEL2
p1 n1
p2 n1
p3 n2
p4 n2
其中标签是列 header,属性是值。我想为我的数据帧的每一行重现以下密码查询(以第一行为例):
query="""
MATCH (a:Label1 {property:p1))
MERGE (a)-[r:R_TYPE]->(b:Label2 {property:n1))
"""
我知道我可以告诉 py2neo 只是 graph.run(query)
,甚至 运行 一个 LOAD CSV
密码脚本,但我想知道我是否可以遍历数据框和在 py2neo 中逐行应用上述查询。
您可以使用 DataFrame.iterrows()
遍历 DataFrame 并对每一行执行查询,将行中的值作为参数传递。
for index, row in df.iterrows():
graph.run('''
MATCH (a:Label1 {property:$label1})
MERGE (a)-[r:R_TYPE]->(b:Label2 {property:$label2})
''', parameters = {'label1': row['label1'], 'label2': row['label2']})
这将每行执行一个事务。我们可以将多个查询批处理到一个事务中以获得更好的性能。
tx = graph.begin()
for index, row in df.iterrows():
tx.evaluate('''
MATCH (a:Label1 {property:$label1})
MERGE (a)-[r:R_TYPE]->(b:Label2 {property:$label2})
''', parameters = {'label1': row['label1'], 'label2': row['label2']})
tx.commit()
通常我们可以在单个事务中批处理 ~20k 数据库操作。
我发现建议的解决方案对我不起作用。即使节点已经存在,上面的代码也会创建新节点。为确保您不创建任何重复项,我建议在 merge
:
之前匹配 a
和 b
节点
tx = graph.begin()
for index, row in df.iterrows():
tx.evaluate('''
MATCH (a:Label1 {property:$label1}), (b:Label2 {property:$label2})
MERGE (a)-[r:R_TYPE]->(b)
''', parameters = {'label1': row['label1'], 'label2': row['label2']})
tx.commit()
同样在我的例子中,我必须同时添加关系属性(参见下面的代码)。此外,我有 500k+ 关系要添加,所以我预计 运行 进入 java 堆内存错误。我通过将 begin()
和 commit()
放在循环中解决了这个问题,因此对于每个新关系都会创建一个新事务:
for index, row in df.iterrows():
tx = graph.begin()
tx.evaluate('''
MATCH (a:Label1 {property:$label1}), (b:Label2 {property:$label2})
MERGE (a)-[r:R_TYPE{property_name:$p}]->(b)
''', parameters = {'label1': row['label1'], 'label2': row['label2'], 'p': row['property']})
tx.commit()
使用 py2neo 从 Neo4j 数据库的密码查询中获取 pandas 数据帧的结果非常简单,因为:
>>> from pandas import DataFrame
>>> DataFrame(graph.data("MATCH (a:Person) RETURN a.name, a.born LIMIT 4"))
a.born a.name
0 1964 Keanu Reeves
1 1967 Carrie-Anne Moss
2 1961 Laurence Fishburne
3 1960 Hugo Weaving
现在我正在尝试使用 py2neo 从 pandas 数据帧创建(或更好地合并)一组节点和关系到 Neo4j 数据库中。想象一下我有一个像这样的数据框:
LABEL1 LABEL2
p1 n1
p2 n1
p3 n2
p4 n2
其中标签是列 header,属性是值。我想为我的数据帧的每一行重现以下密码查询(以第一行为例):
query="""
MATCH (a:Label1 {property:p1))
MERGE (a)-[r:R_TYPE]->(b:Label2 {property:n1))
"""
我知道我可以告诉 py2neo 只是 graph.run(query)
,甚至 运行 一个 LOAD CSV
密码脚本,但我想知道我是否可以遍历数据框和在 py2neo 中逐行应用上述查询。
您可以使用 DataFrame.iterrows()
遍历 DataFrame 并对每一行执行查询,将行中的值作为参数传递。
for index, row in df.iterrows():
graph.run('''
MATCH (a:Label1 {property:$label1})
MERGE (a)-[r:R_TYPE]->(b:Label2 {property:$label2})
''', parameters = {'label1': row['label1'], 'label2': row['label2']})
这将每行执行一个事务。我们可以将多个查询批处理到一个事务中以获得更好的性能。
tx = graph.begin()
for index, row in df.iterrows():
tx.evaluate('''
MATCH (a:Label1 {property:$label1})
MERGE (a)-[r:R_TYPE]->(b:Label2 {property:$label2})
''', parameters = {'label1': row['label1'], 'label2': row['label2']})
tx.commit()
通常我们可以在单个事务中批处理 ~20k 数据库操作。
我发现建议的解决方案对我不起作用。即使节点已经存在,上面的代码也会创建新节点。为确保您不创建任何重复项,我建议在 merge
:
a
和 b
节点
tx = graph.begin()
for index, row in df.iterrows():
tx.evaluate('''
MATCH (a:Label1 {property:$label1}), (b:Label2 {property:$label2})
MERGE (a)-[r:R_TYPE]->(b)
''', parameters = {'label1': row['label1'], 'label2': row['label2']})
tx.commit()
同样在我的例子中,我必须同时添加关系属性(参见下面的代码)。此外,我有 500k+ 关系要添加,所以我预计 运行 进入 java 堆内存错误。我通过将 begin()
和 commit()
放在循环中解决了这个问题,因此对于每个新关系都会创建一个新事务:
for index, row in df.iterrows():
tx = graph.begin()
tx.evaluate('''
MATCH (a:Label1 {property:$label1}), (b:Label2 {property:$label2})
MERGE (a)-[r:R_TYPE{property_name:$p}]->(b)
''', parameters = {'label1': row['label1'], 'label2': row['label2'], 'p': row['property']})
tx.commit()