在我继续使用 芝加哥犯罪数据集的 过程中,我想将犯下的罪行与其在 FBI 犯罪类型 层次结构中的位置联系起来。
这些是我要连接的子图:
我们在每个“犯罪”节点上都有一个“fbiCode”,它指示犯罪属于哪个“犯罪子类别”。
我从以下查询开始将节点连接在一起:
MATCH (crime:Crime)
WITH crime SKIP {skip} LIMIT 10000
MATCH (subCat:SubCategory {code: crime.fbiCode})
MERGE (crime)-[:CATEGORY]->(subCat)
RETURN COUNT(*) AS crimesProcessed
我让这个在 Python 脚本中运行,只要 'crimesProcessed' 返回值 > 0,它就会在每次迭代中将 'skip' 递增 10,000。
首先,“类别”关系的创建速度非常快,但它在大约 100 万个节点中明显减慢了速度。
我分析了查询,但查询计划没有显示任何明显错误。我怀疑我有一个超级节点问题,其中密码运行时遍历所有子类别的关系,以检查其中一个是否指向“MERGE”语句另一侧的犯罪。
我取消了导入作业并编写了一个查询来检查每个子类别有多少关系。从 1,000 到 93,000 不等,这在一定程度上证实了我的怀疑。
Michael 建议调整查询以使用最短路径函数来检查关系是否存在,然后如果关系不存在则使用“CREATE”子句创建它。
最短路径函数的巧妙之处在于它将从基数最低的一侧开始,一旦找到关系就会停止搜索。让我们看一下该版本的查询:
MATCH (crime:Crime)
WITH crime SKIP {skip} LIMIT 10000
MATCH (subCat:SubCategory {code: crime.fbiCode})
MERGE (crime)-[:CATEGORY]->(subCat)
RETURN COUNT(*) AS crimesProcessed
这样效果更好——10,000 个节点在大约 2.5 秒内处理——并且随着更多关系的添加,时间保持不变。这允许我创建所有类别节点,但如果我们使用 CREATE UNIQUE 而不是 MERGE ,我们实际上可以做得更好
MATCH (crime:Crime)
WITH crime SKIP {skip} LIMIT 10000
MATCH (subCat:SubCategory {code: crime.fbiCode})
MERGE (crime)-[:CATEGORY]->(subCat)
RETURN COUNT(*) AS crimesProcessed
使用此查询处理 10,000 个节点需要 250 毫秒 -900 毫秒秒来处理,这意味着我们可以在 5-6 分钟内处理所有节点——好时光!
我不太熟悉“CREATE UNIQUE”代码,所以我不确定它是否始终是“MERGE”的良好替代品,但在这种情况下它可以完成工作。
这里给我的教训是,如果一个查询花费的时间比你想象的要长,它应该尝试使用其他结构/其他结构的组合,看看情况是否有所改善——他们可能会!