精华 Neo4j图数据库高级应用系列 / 服务器扩展指南 APOC(4.3) - 循环执行 iterate
发布于 5 年前 作者 graphway 2349 次浏览 来自 分享

1. 定义 iterate()过程包含2个子查询: - 第一个查询返回要处理的对象集合,也称作外查询; - 第二个查询按照批次处理固定数量的对象,直至所有对象处理完成。也称作内查询。 配置参数iterateList为true时,会将第一个查询中返回的对象作为一个批次来处理;反之则一个一个对象处理。

iterate.png

  1. 应用

iterate()提供较commit()过程更丰富的执行控制选项,可以用来并行更新大量的数据库对象。通过设置批次大小,控制事务的规模、减少对系统资源的要求。

  1. 过程调用接口 CALL apoc.periodic.iterate( statement1, statement2, { batchSize:1000, iterateList:true, parallel:false, params:{}, concurrency:50, retries:0 } ) YIELD batches, total

参数名 类型 缺省值 可为空? 说明 statement1 字符串 无 否 Cypher查询,返回要更新的对象列表。又称作“外查询”。 statement2 字符串 无 否 Cypher查询,针对statement1中返回的对象进行的更新操作。又称作“内查询”。 {configurations} MAP 有 是 具体配置选项参见下面各行。 batchSize 正整数 1000 是 批次大小,即每个事务包含多少次statement2的执行。 concurrency 正整数 50 是 当parallel为true时,定义并行执行的任务数。 failedParams 整数 -1 是 如果是大于0的整数,那么该值设置最多返回的失败任务的数目。-1表示返回所有失败的任务。 iterateList 布尔值 false 是 为true时,会将第一个查询中返回的对象作为一个批次来处理;反之则一个一个对象处理。 params MAP {} 是 传递给内部查询statement2的参数。 parallel 布尔值 false 是 是否并行执行statement2的更新操作。 retries 正整数 0 是 statement2执行失败后(例如出现死锁),进程休眠100ms,然后重试的次数。

  1. 示例

// 4.3(1) 迭代执行数据库更新查询,创建人物之间新关系。 // 参数:- statement1: 返回所有人物节点 // - statement2: 搜索2度“父子”关系、并建立新的“爷孙”关系 // - configuration: 批次大小10,并行执行,并发数4 // 返回结果:任务执行用时和批次信息

CALL apoc.periodic.iterate( “MATCH (n:人物) RETURN n”, “MATCH (n)-[:父子*2]->(m) MERGE (n) -[:爷孙]-> (m)”, { batchSize:10, parallel:true, iterateList:true, concurrency:4 } )

重要技巧#1: 建议始终设置iterateList:true,因为这样使得一个批次中所有内查询(由batchSize决定)会作为一个事务被提交、从而提高运行效率。 重要技巧#2: 仅当数据库是存储在SSD(固态硬盘)时才使用parallel:true选项,因为SSD具有更好的随机读写速率。如果是物理硬盘则不要使用并行选项,因为这反而会降低整体执行效率。 重要技巧#3: 并发数concurrency通常设置成分配给数据库服务运行的CPU内核数的整数倍。例如,如果Neo4j服务器运行在8个CPU内核的虚拟或物理主机上,那么concurrency可以是8、16、24等值。 重要技巧#4: 并发执行时,如果不同线程需要对同一数据库对象(节点或关系)进行更新,先执行的线程会对待更新的数据库对象加锁(locking),这时其它线程的更新会被阻塞、并报告“锁获取失败”或者Java NullPointerException空指针错误。 一种解决方法是设置重试次数retries,每次重试会等待100ms。 如果还是出现死锁,则不使用并行执行。

---- 待续 ---- (下一章:异步执行submit)

回到顶部