Neo4j LOAD CSV应用程序线程被阻止

时间:2017-12-30 11:26:05

标签: neo4j graphenedb

我正在尝试使用neo4j中的LOAD CSV命令从CSV文件导入大约500,000行数据。

csv中的数据组织如下:

Artists    |    Feature1    |    Feature2    |    Feature3

每个列都填充了音乐艺术家的名字,大多数人在一列中出现不止一次。如果艺术家名称出现在任何列中,我希望有一个该艺术家的节点。如果那个艺术家'名称在列中和/或多列中不止一次出现,我希望该艺术家只有一个节点。

对于每位艺术家,我想跟踪他们的特色以及他们的特色。 csv的每一行代表一首歌。对于艺术家制作的每首歌曲(csv的每一行),我想在FEATURES列中将艺术家的Artist关系添加到Features1/2/3中的艺术家列。

以下是我正在使用的代码:

CREATE CONSTRAINT ON (a:Artist) ASSERT a.artistName IS UNIQUE;

USING PERIODIC COMMIT 50
LOAD CSV WITH HEADERS from 'https://aws.bigfile.csv' as line
MERGE (artist:Artist {artistName: line.Artist})
MERGE (feature1:Artist {artistName: line.Feature1})
MERGE (feature2:Artist {artistName: line.Feature2})
MERGE (feature3:Artist {artistName: line.Feature3})

MERGE (artist)-[f1:FEATURES]->(feature1) 
ON CREATE SET f1.strength = 1
ON MATCH SET f1.strength = f1.strength + 1

MERGE (artist)-[f2:FEATURES]->(feature2) 
ON CREATE SET f2.strength = 1
ON MATCH SET f2.strength = f2.strength + 1

MERGE (artist)-[f3:FEATURES]->(feature3) 
ON CREATE SET f3.strength = 1
ON MATCH SET f3.strength = f3.strength + 1

所需行为:第一次出现以另一位艺术家为特色的人会创建FEATURES关系,并应将strength关系的FEATURES属性设置为1.对于每次后续出现,力度属性上升1.因此,经常以艺术家B为特色的艺术家A应该有(a)-[:FEATURES {strength: AHighNumber]->(b)

之类的关系

在这种情况下,关系是方向性和方向性的(A特征B与B特征A不同)。

应该有超过10,000个不同的艺术家,因此节点,但大约2,000个节点,我开始遇到系统超时问题。

我在日志中收到了一堆以下消息:

2017-12-30 10:54:04.268+0000 WARN [o.n.k.i.c.MonitorGc] GC Monitor: Application threads blocked for 467ms.

是否有其他信息可用于确定问题?知道如何重构我的代码以避免这个问题吗?非常感谢所有帮助。谢谢!

2 个答案:

答案 0 :(得分:1)

如果您粘贴查询(不要将其粘贴,只需将其粘贴)到浏览器中,您就会收到一条警告,当用完时,会显示:

  

此查询的执行计划包含Eager运算符   强制所有相关数据在之前的主内存中实现   诉讼。   在查询中使用带有大数据集的LOAD CSV   执行计划包含Eager运算符可能会消耗一个   很多内存,很可能表现不佳。请参阅Neo4j手册   进入Eager运算符以获取更多信息和提示   问题可以避免。

这解释了为什么您会看到性能问题......它有效地取消了对定期提交的任何使用。

当您在同一节点标签上有多个MERGE时,您可以在查询计划中获得热切的操作。解决此类问题的一般方法是在CSV中使用单个变量中的节点进行合并:

USING PERIODIC COMMIT 50
LOAD CSV WITH HEADERS from 'https://aws.bigfile.csv' as line
MERGE (artist:Artist {artistName: line.Artist})

如果您的CSV中的line.Artist包含所有可能的艺术家,那么单次传递应该有效。但是,如果line.Feature1(和其他人)中的其他艺术家不在line.Artist中,那么您需要依次为每个艺术家再做一次,直到所有节点已加载(您还可以将PERIODIC COMMIT推送到5000到10000左右)。

请注意,与多个节点相同关系类型的多个MERGE也有助于EAGER操作。您应该真的看看是否可以以不同的格式获取CSV。您并不真正需要所有这些额外的列,line.Artistline.Feature应该足够了,然后您将拥有多个具有相同艺术家和不同功能的行,并且您赢得了#39;赶不上急切的行动。

另外,为了避免急切的操作并允许使用定期提交,可以在3次传递中执行查询(在您导入所有节点之后):

USING PERIODIC COMMIT 10000
LOAD CSV WITH HEADERS from 'https://aws.bigfile.csv' as line
match (artist:Artist {artistName: line.Artist})
match (feature:Artist {artistName: line.Feature1})

MERGE (artist)-[f:FEATURES]->(feature1) 
ON CREATE SET f.strength = 1
ON MATCH SET f.strength = f.strength + 1

然后重复line.Feature2line.Feature3

答案 1 :(得分:0)

我已经找到了一个(中间)解决方案,它没有直接解决上面的内存问题,但仍然有效。

以前,我试图从原始文件创建艺术家节点,合并它们,以便每个艺术家只有一个节点。我怀疑节点的创建/合并变得越来越昂贵,因为对于文件的每一行,密码本质上必须查看所有现有节点以查看是否为该行创建新节点。

相反,我编写了一些Python代码,它们为每列获取唯一值(艺术家名称),将它们组合成一个长列表,并再次从此列表中获取唯一值以过滤掉出现在多个列中的重复艺术家。然后我将其写入一个包含一列艺术家的文件。我使用这个更短的文件来创建所有艺术家节点。代码:

data = pd.read_csv('artists-full.csv', encoding = 'latin1')
columns = ['Artist', 'Feature1', 'Feature2', 'Feature3']
df = pd.DataFrame(data, columns=columns)

# Get an array of strings for each column. Clean out repeats
artists_set1 = df.loc[:, 'Artist'].unique().tolist()
artists_set2 = df.loc[:, 'Feature1'].unique().tolist()
artists_set3 = df.loc[:, 'Feature2'].unique().tolist()
artists_set4 = df.loc[:, 'Feature3'].unique().tolist()

# Combine the artists from different columns
artists_list = [artists_set1, artists_set2, artists_set3, artists_set4]
flat_artists_list = [item for sublist in artists_list for item in sublist]
# Get rid of duplicates by creating a set
artists_set = set(flat_artists_list)
# Turn the set back into a list
artists = list(artists_set)
print(len(artists))

# Write the list to csv
with open ('artists.csv', 'w', encoding='utf-8') as f:
    for artist in artists:
        f.write(str(artist) + '\n')

从那里,我使用原始文件和以下Cypher代码创建了艺术家之间的关系:

CREATE CONSTRAINT ON (a:Artist) ASSERT a.artistName IS UNIQUE;
MERGE (artist)-[f1:FEATURES]->(feature1) 
ON CREATE SET f1.strength = 1
ON MATCH SET f1.strength = f1.strength + 1

MERGE (artist)-[f2:FEATURES]->(feature2) 
ON CREATE SET f2.strength = 1
ON MATCH SET f2.strength = f2.strength + 1

MERGE (artist)-[f3:FEATURES]->(feature3) 
ON CREATE SET f3.strength = 1
ON MATCH SET f3.strength = f3.strength + 1