py2neo
是一个 Python 库,用于与 Neo4j 图数据库进行交互。要使用 py2neo
执行批量导入节点和关系,可以遵循以下步骤:
-
批量创建节点:
您可以使用事务或Subgraph
来批量创建节点。Subgraph
允许您定义一个包含多个节点和关系的子图,然后一次性将其合并到数据库中。 -
批量创建关系:
与节点类似,您可以在Subgraph
中定义关系,并一次性将它们添加到数据库中。 -
提交事务:
确保在添加完所有节点和关系后提交事务,以将数据永久保存到数据库中。
下面是一个简单的示例代码,展示了如何使用 py2neo
批量导入节点和关系(当然了,只是说一说思路,实际上并没有什么卵用):
from py2neo import Graph, Node, Relationship, Subgraph
# 连接到 Neo4j 数据库
graph = Graph("bolt://localhost:7687", auth=("neo4j", "your_password"))
# 创建节点和关系的列表
nodes = [Node("Person", name="Alice"), Node("Person", name="Bob")]
relationships = [Relationship(nodes[0], "KNOWS", nodes[1])]
# 创建子图
subgraph = Subgraph(nodes, relationships)
# 将子图合并到数据库中
graph.merge(subgraph)
# 提交事务(通常 py2neo 的操作是自动提交的,但根据配置可能需要手动提交)
# graph.commit() # 如果需要的话(但在大多数情况下不是必需的)
分享一段我自己写的代码。如果需要批量导入数据的话,希望能给大家带来一些方便。
本体类型标签,用双重列表,比如:[['pkg', 'py2neo'], ['pkg', 'numpy']] 来表示两个节点。
'''
# 创建多个节点
# @labels_list 本体(类型)标签,labels_list=[[]]
# @propertys_list 节点的属性 propertys_list = [{strKey:value}]
# @check 检查是否重复。 Ture=检查, False=不检查直接建(可能会建重)
# @check_property_key_list 检查重复所用到的属性 [strKey]
# 【注意】: 输入的 _list 都必须长度一致,否则出错
# 多个节点是独立的,彼此的labels和propertys都没有关系。返回列表中的元素可以重复出现
# propertys_list 必须含有一个 'name' 的属性项
'''
def createNodeList(labels_list, propertys_list, check=True, check_property_key_list=None)
# -*- coding: utf-8 -*-
import pandas as pd
from py2neo import Graph, Node, Relationship, NodeMatcher, RelationshipMatcher, Subgraph
# 连接Neo4j数据库
# 使用Bolt协议连接到本机的Neo4j数据库实例
test_graph = Graph("bolt://localhost:7687", auth=("neo4j", "password")) # 用户名是"neo4j",密码是"password"
Neo4j_Graph = test_graph
SYS_DB_CHECK = True # 标记是否需要检查重复
# 找到节点
def getNode(labels, propertys):
tNode = None # 初始化返回节点为None
txtLabels = '' # 初始化标签字符串
# 处理标签,支持单个标签或标签列表
if isinstance(labels, list):
for l in labels:
if l: # 如果标签不为空
txtLabels += ':%s' % l # 拼接标签字符串
else:
if labels: # 如果标签不为空
txtLabels += ':%s' % labels # 拼接标签字符串
# 处理属性,构造Cypher查询中的属性部分
txtProperty = '{'
for p in propertys:
txtProperty += "%s:'%s'," % (p, propertys[p]) # 拼接属性字符串
txtProperty = txtProperty[:-1] + '}' # 去掉最后一个逗号,并加上花括号结束
# 构造Cypher查询语句并执行
cypher = "match (n%s%s) return n limit 1" % (txtLabels, txtProperty)
path = test_graph.run(cypher).data()
for p in path:
tNode = p['n'].nodes[0] # 获取查询结果中的节点
return tNode
# 创建节点
def createNode(labels, propertys, check=True):
tNode = None # 初始化返回节点为None
# 如果需要检查重复,则执行查找节点的逻辑
if check:
txtLabels = '' # 初始化标签字符串
if isinstance(labels, list):
for l in labels:
txtLabels += ':%s' % l # 拼接标签字符串
else:
if labels: # 如果标签不为空
txtLabels += ':%s' % labels # 拼接标签字符串
txtProperty = '{' # 初始化属性字符串
for p in propertys:
txtProperty += "%s:'%s'," % (p, propertys[p]) # 拼接属性字符串
txtProperty = txtProperty[:-1] + '}' # 去掉最后一个逗号,并加上花括号结束
# 构造Cypher查询语句并执行
cypher = "match (n%s%s) return n limit 1" % (txtLabels, txtProperty)
path = test_graph.run(cypher).data()
for p in path:
tNode = p['n'].nodes[0] # 获取查询结果中的节点
# 如果没有找到节点,则创建新节点
if tNode is None:
tNode = Node(*labels, **propertys) # 创建新节点
test_graph.create(tNode) # 将新节点提交到数据库
return tNode
# 创建多个节点
# @labels_list:节点标签列表,每个元素是一个标签列表
# @propertys_list:节点属性列表,每个元素是一个属性字典
# @check:是否检查重复,True表示检查,False表示不检查直接创建(可能会创建重复节点)
# @check_property_key_list:检查重复时所用的属性键列表
# 注意:输入的列表长度必须一致,否则会出现错误;属性列表必须包含一个名为'name'的属性项
def createNodeList(labels_list, propertys_list, check=True, check_property_key_list=None):
retNodes = [None] * len(labels_list) # 初始化返回的节点列表
create_Nodes = [] # 新增节点列表
update_Nodes = [] # 更新属性节点列表
create_nodes_info = {} # 用于存储已创建节点的信息,防止重复创建
for i in range(len(labels_list)):
labels = labels_list[i]
propertys = propertys_list[i]
if labels is None: # 如果标签为空,则跳过当前循环
continue
tNode = None # 初始化当前节点为None
tInfo = str(labels) # 初始化节点信息字符串,用于防止重复创建节点
if check_property_key_list is not None: # 如果指定了检查属性键列表,则拼接属性信息到节点信息字符串中
for k in check_property_key_list:
tInfo += str(propertys[k])
# 如果已创建节点信息中包含当前节点信息,则直接获取已创建节点并更新其属性,然后跳过当前循环的剩余部分
if create_nodes_info.get(tInfo) is not None:
tNode = create_nodes_info[tInfo]
for np in propertys:
tNode.update({np: str(propertys[np])}) # 更新节点属性(这里假设所有属性都是字符串类型)
update_Nodes.append(tNode) # 将更新属性的节点添加到更新节点列表中
retNodes[i] = tNode # 将已创建节点添加到返回节点列表中,并跳过当前循环的剩余部分
continue
else: # 如果当前节点信息不在已创建节点信息中,则尝试查找或创建新节点,并更新已创建节点信息字典和返回节点列表等数据结构
tNode = getNode(labels, propertys) # 尝试查找节点(这里假设getNode函数能正确处理单个标签和多个标签的情况)
if tNode is not None: # 如果找到了节点,则更新已创建节点信息字典,并跳过当前循环的剩余部分(这里可能存在逻辑错误,因为找到节点后并没有将其添加到返回节点列表中)
create_nodes_info[tInfo] = tNode # 更新已创建节点信息字典(但实际上这里并没有用到这个字典来防止重复创建节点,因此这行代码可能是多余的)
else: # 如果没有找到节点,则创建新节点,并更新相关数据结构(这里存在逻辑错误,因为即使没有找到节点也没有将其添加到新增节点列表中)
tNode = Node(*labels, **propertys) # 创建新节点(但实际上并没有将新节点添加到数据库中或任何列表中)
create_Nodes.append(tNode) # 将新节点添加到新增节点列表中(但实际上由于前面的逻辑错误,这里永远不会执行)
create_nodes_info[tInfo] = tNode # 将新节点信息添加到已创建节点信息字典中(但实际上并没有用到这个字典来防止重复创建节点)
# 更新节点属性并添加到更新节点列表中(但由于前面的逻辑错误,这里永远不会执行)
for np in propertys: # 遍历属性列表(但实际上由于前面的逻辑错误,这里永远不会执行)
tNode.update({np: str(propertys[np])}) # 更新节点属性(但由于前面的逻辑错误和假设所有属性都是字符串类型的限制条件可能存在问题)
update_Nodes.append(tNode) # 将更新属性的节点添加到更新节点列表中(但由于前面的逻辑错误和假设所有属性都是字符串类型的限制条件可能存在问题导致实际上并没有添加到列表中)
retNodes[i] = tNode # 将当前节点添加到返回节点列表中(但由于前面的逻辑错误可能导致实际上并没有正确添加节点到列表中或在列表中添加了错误的节点)
# 提交新增节点和更新属性的节点到数据库(但由于前面的逻辑错误导致实际上并没有正确创建或更新任何节点)
subG = Subgraph(nodes=create_Nodes) # 通过子图将新增的节点提交上去(但由于前面的逻辑错误导致实际上并没有任何新增节点需要提交)
Neo4j_Graph.create(subG) # 将子图提交到数据库(但由于前面的逻辑错误导致实际上并没有任何子图需要提交)
subG = Subgraph(nodes=update_Nodes) # 通过子图将更新属性的节点提交上去(但由于前面的逻辑错误和假设所有属性都是字符串类型的限制条件可能存在问题导致实际上并没有任何需要更新的节点或更新操作不正确)
Neo4j_Graph.merge(subG) # 将子图合并到数据库中(但由于前面的逻辑错误和假设所有属性都是字符串类型的限制条件可能存在问题导致实际上并没有执行任何合并操作或合并操作不正确)
return retNodes # 返回节点列表(但由于前面的逻辑错误可能导致实际上返回的列表并不正确)
# 创建多组关系的函数
# 参数:
# node1_list: 头节点列表
# R_list: 关系类型列表
# node2_list: 尾节点列表
# property_list: 关系的属性列表,如果没有则是None,如果有,则是一个字典列表
# check: 一个布尔值,用于确定是否进行某种检查(但在此函数中未使用)
# 返回值:
# 返回一个包含创建的关系对象的列表(但实际上这个返回值在当前代码中没有被用到)
def createRelationship_Mul(node1_list, R_list, node2_list, property_list=None, check=True):
ret_r_list = [None]*len(node1_list) # 初始化一个与node1_list长度相同的列表,用于存放创建的关系对象(但实际上这个列表在函数结束前并未被完全填充)
r_list = [] # 初始化一个空列表,用于存放要添加到子图中的所有关系对象
for i in range(len(node1_list)):
tR = None # 初始化一个变量用于存放当前循环中创建的关系对象(但这个初始化其实是多余的)
node1, R, node2 = node1_list[i], R_list[i], node2_list[i] # 获取当前循环中的头节点、关系类型和尾节点
# 检查头节点或尾节点是否为None,如果是则跳过当前循环(但这可能导致ret_r_list中的某些元素仍然是None)
if node1 is None or node2 is None:
continue
# 创建一个新的关系对象,并根据property_list是否存在来设置关系的属性(但这里有一个逻辑错误,因为tR的初始化是多余的,并且这个if语句永远不会为False)
if tR == None: # 这个判断永远是True,因为tR在之前被设置为None,并且在此之后没有被修改过
if property_list is None: # 检查是否有提供属性列表
tR = Relationship(node1, R, node2, **{'relation': R}) # 创建一个新的关系对象(但这里有一个问题:'relation': R可能不是你想要的属性名)
else:
tR = Relationship(node1, R, node2, **(property_list[i])) # 使用提供的属性创建一个新的关系对象(这里假设property_list[i]是一个字典)
r_list.append(tR) # 将新创建的关系对象添加到r_list中
ret_r_list[i] = tR # 将新创建的关系对象存放到ret_r_list的相应位置(但由于前面的continue语句,这里可能会引发IndexError)
# Neo4j_Graph.create(tR) # 这行代码被注释掉了,但如果取消注释,它看起来是用来将新创建的关系对象添加到Neo4j图中的(不过这里没有显示Neo4j_Graph的定义或创建)
subG = Subgraph(relationships=r_list) # 创建一个包含所有新创建的关系对象的子图(但这里没有显示Subgraph的定义或创建)
Neo4j_Graph.merge(subG) # 将子图合并到主图中(同样,这里没有显示Neo4j_Graph的定义或创建)
return # 这里缺少返回值!根据函数的文档字符串,这里应该返回ret_r_list或类似的东西,但实际上什么也没有返回。
写这个文章的时候,发现py2neo的官网不能访问了,知道的朋友请留言给大家指导一下,谢谢。
感谢微学AI的帖子,整理了一些py2neo的详细用法。