MERGE'ing 在 Neo4j 中的超级节点上

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 63w+ 字,讲解图 2808+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2200+ 小伙伴加入学习 ,欢迎点击围观

在我继续使用 芝加哥犯罪数据集的 过程中,我想将犯下的罪行与其在 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”的良好替代品,但在这种情况下它可以完成工作。

这里给我的教训是,如果一个查询花费的时间比你想象的要长,它应该尝试使用其他结构/其他结构的组合,看看情况是否有所改善——他们可能会!

相关文章