在 Ruby 中高效地将数据从大型 CSV(或数据流)导入 Neo4j

Import data from a large CSV (or stream of data) to Neo4j efficiently in Ruby

我是后台进程的新手,所以如果我做出了错误的假设,请随时指出我。

我正在尝试编写一个脚本,将导入数据从一个大型 CSV 文件导入到 Neo4j 数据库中(将其视为数据流,无穷无尽)。 csv 文件仅包含两列 - user_a_id 和 user_b_id,它们映射定向关系。需要考虑的几点:

  1. 数据可能有重复
  2. 同一个用户可以映射到多个其他用户,并且不能保证它何时会再次出现。

我目前的解决方案:我正在使用 sidekiq 并让一名工作人员批量读取文件并派遣工作人员在数据库中创建边缘。

我遇到的问题:

  1. 由于我正在接收数据流,我无法对文件进行预排序并分配为一个用户建立关系的作业。
  2. 由于作业是异步执行的,如果两个工作人员正在处理同一个节点的关系,我将从 Neo4j 获得写锁。
  3. 假设我绕过写锁,如果两个工作人员正在处理重复的记录,我将构建重复的边。

可能的解决方案:建立一个同步队列并且只有一个worker来执行写入(似乎sidekiq或resque都没有这个选项)。这可能会很慢,因为只有一个线程在处理这项工作。

或者,我可以编写自己的实现,创建一个工作人员根据 user_id(每个队列一个唯一的 id)构建多个作业队列,并使用 redis 来存储它们。然后为每个队列分配一名工人写入数据库。设置最大队列数,这样我就不会 运行 内存不足,并在队列用完所有作业后删除队列(如果我将来看到相同的 user_id 则重建它)。 - 虽然这听起来并不微不足道,所以我更愿意在深入研究之前使用现有的库。

我的问题是 — 是否有现有的 gem 可供我使用?处理此问题的最佳做法是什么?

您有多种选择 ;)

如果您的数据确实在文件中而不是流中,我绝对建议您查看 Neo4j 附带的 neo4j-import 命令。它允许您以每秒 100 万行的速度导入 CSV 数据。两个注意事项:您可能需要稍微修改文件格式,并且需要生成一个新数据库(它不会将新数据导入现有数据库)

我也会熟悉 LOAD CSV 命令。这需要任何格式的 CSV,并允许您编写一些 Cypher 命令来转换和导入数据。它不如 neo4j-import 快,但速度相当快,它可以从磁盘或 URL.

流式传输 CSV 文件

既然您使用的是 Ruby,我也建议您查看 neo4apis。这是我写的 gem,目的是使批量导入数据更容易,这样您就不会对文件中的每个条目发出一个请求。它允许您在一种带有导入器的 DSL 中定义 class。这些导入器可以采用任何类型的 Ruby 对象,并且鉴于 Ruby 对象,将定义应使用 add_nodeadd_relationship 方法导入的内容。在幕后,这会生成 Cypher 查询,这些查询会被缓冲并分批执行,这样您就不会多次往返 Neo4j。

在考虑异步处理事情之前,我会先调查所有这些事情。但是,如果您确实有一组永无止境的数据进来。 MERGE 子句应该可以帮助您解决任何竞争条件或锁。它允许您创建尚不存在的对象和关系。它基本上是一个 find_or_create,但在数据库级别。如果您使用 LOAD CSV,您可能也需要合并,而 neo4apis 在幕后使用 MERGE

希望对您有所帮助!