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:

之前匹配 ab 节点
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()