如何使用Python基于Pandas DataFrame创建Neo4j节点与关系
问题原因
你的代码存在以下几个核心错误,导致无法正常写入节点和关系:
- 参数引用错误:在
UNWIND $rows AS row的逻辑里,所有行数据都存储在row对象中,代码里写的$source、$target没有在参数字典中定义,根本取不到对应值。 - 节点标签逻辑错误:
source、target是你数据表的列名,不是节点的业务类型,你全程没有创建过带:source标签的节点,后续MATCH (s:source)永远匹配不到结果;同时节点属性写的{property: xxx}没有实际业务意义,属性键应该和存储字段对应,比如人名要存在name字段下。 - 关系类型写死:你把关系类型固定为
R_TYPE,根本没法匹配数据里lives in/born in/returns to三类不同的关系。 - 函数传参错误:
add_nodes_and_relations里调用insert_data时第一个参数传了函数自身,没有传入定义好的query语句,会直接触发参数错误。 - 缺失返回值:Cypher语句没有返回写入计数,代码里取
res[0]['total']会直接报索引错误。 - 原始数据未清洗:target列的
Utah./Canada.带多余句点,会和不带点的地名生成重复节点。
修正后实现
首先先清洗原始数据的多余标点,再写入Neo4j,以下代码默认你已经开启Neo4j预装的APOC插件(桌面版、主流云服务版Neo4j都默认自带,用来处理动态关系类型非常方便):
import pandas as pd # 先清洗原始测试数据 df = pd.DataFrame({ "source": ["John", "Peter", "Oscar"], "target": ["California", "Utah.", "Canada."], "relation": ["lives in", "born in", "returns to"] }) # 去掉target列末尾多余的点 df["target"] = df["target"].str.rstrip(".") def add_nodes_and_relations(rows, batch_size=10000): query = ''' UNWIND $rows AS row // 合并写入源节点:人物实体,用name属性存人名作为唯一键 MERGE (s:Person {name: trim(row.source)}) // 合并写入目标节点:地点实体,用name属性存地名作为唯一键 MERGE (t:Location {name: trim(row.target)}) // 动态创建对应类型的关系,避免重复生成 WITH s, t, row CALL apoc.merge.relationship( s, replace(row.relation, " ", "_"), {}, {}, t, {} ) YIELD rel // 返回当前批次写入条数供计数 RETURN count(*) AS total ''' # 修正之前的传参错误,传入query变量而不是函数自身 return insert_data(query, rows, batch_size) def insert_data(query, rows, batch_size = 10000): total = 0 batch = 0 result = None while batch * batch_size < len(rows): batch_data = rows[batch*batch_size:(batch+1)*batch_size].to_dict('records') res = conn.query(query, parameters = {'rows': batch_data}) total += res[0]['total'] batch += 1 result = {"total_inserted": total, "batches": batch} print(result) return result # 调用函数写入即可 # add_nodes_and_relations(df)
注意事项
- Neo4j的关系名称不支持带空格,代码里用
replace(row.relation, " ", "_")把空格替换为下划线,会生成LIVES_IN/BORN_IN/RETURNS_TO这类符合规范的关系类型名。 - 如果没有安装APOC插件,可以提前在Python端把关系类型做枚举映射,通过字符串拼接生成对应Cypher即可,生产环境不要直接把未校验的外部输入拼进Cypher避免注入风险,自有测试数据可以忽略这个问题。
- 节点标签要按实体类型划分,人物统一用
:Person标签,地点统一用:Location标签,后续做查询、索引优化都会更方便,不要用数据表的列名当节点标签。 - 所有MERGE逻辑都要优先匹配业务唯一键(这里人名、地名都用name当唯一键),避免生成重复节点。
内容的提问来源于stack exchange,提问作者user840
相关产品推荐
相关产品推荐

