代码之家  ›  专栏  ›  技术社区  ›  Jane Wayne

如何改进将数千个微小的JSON文件加载到Spark数据框中?

  •  0
  • Jane Wayne  · 技术社区  · 7 年前

    我有大约30000个非常小的JSON文件,我正试图从一个安装的S3桶中加载到一个Spark数据框中。据报道 here here 可能存在性能问题,并被描述为 Hadoop Small Files Problem . 与之前报告的不同,我不会递归到目录中(因为我的所有JSON文件都在一个子文件夹中)。加载JSON文件的代码如下所示。

    val df = spark
      .read
      .option("multiline", "true")
      .json("/mnt/mybucket/myfolder/*.json")
      .cache
    

    到目前为止,我的工作似乎“停滞不前”。我看到两个阶段。

    • 作业0,阶段0:列出叶文件和目录
    • 作业1,阶段1:val df=spark.read.option(“多行”,“…”

    Job 0, Stage 0 相当快,不到1分钟。 Job 1, Stage 1 但是,要花很长时间才能出现(失去时间跟踪,但在两个时间之间,我们谈的是20多分钟),当它确实出现在Jobs用户界面上时,它似乎被“卡住”(15多分钟后,我仍在等待报告任何进展)。有趣的是, 作业0,阶段0 有200个任务(我看到有7个执行者被使用),以及 工作1,阶段1 只有一个任务(似乎只有一个节点/执行器被使用!)多浪费啊!).

    是否有任何方法可以使加载30000个文件的速度更快或更高的性能这一看似简单的步骤?

    我想的是简单地将这些文件“合并”为大文件;例如,将1000个JSON文件合并为30个大文件(使用 NDJSON )但是,我对这种方法持怀疑态度,因为合并文件(比如使用python)本身可能需要很长时间(类似于本机Linux) ls 这个目录中的命令需要很长时间才能返回);而且,这种方法可能会破坏端到端集群计算的目的(不是很优雅)。

    2 回复  |  直到 7 年前
        1
  •  3
  •   OneCricketeer Gabriele Mariotti    7 年前

    将JSON文件合并成新行分隔的、更大的(目标是一个或最多10个文件,而不是30个)文件是这里唯一的选择。

    python打开30k文件的速度不会比您已经做的慢,它只是不会被分发。

    除此之外, multiline=true 特别是当您已经有了一个非常大的JSON文件并且它是一个顶级数组或正在存储的对象时。在该选项存在之前,“jsonlines”是spark可以读取的唯一格式。

    这里最一致的解决方案是修复正在写入所有这些文件的摄取管道,这样您就可以提前积累记录,然后转储更大的批。或者只是使用kafka,而不是从S3(或任何类似的文件系统)读取数据。

        2
  •  0
  •   stevel    7 年前

    有两个HTTP请求,一个读取,一个头,一个获取;如果文件都保存在同一个目录中,那么列表成本只是一个列表/5000个对象,所以需要6个列表调用。您将支付约25美元的3万名员工和接线员的电话费。

    如果您使用spark获取列表并从每个单独的文件生成一条记录,那么每一个文件的调度任务的开销也是如此。您可以做一个技巧,使列表本身(在.py中做)成为输入RDD(即每个文件一行),map()成为该文件的读取,map的输出成为表示单个文件的记录。 scala example 。这解决了Spark调度开销,因为该输入列表将被拆分成更大的部分,并推送到工作人员手中,因此只留下那些HTTP head/get调用。

    为了有效地工作,使用Hadoop2.8+jars,并使用 FileSystem.listFiles(Path, true) 到一个单一的递归列表下的整个目录树的路径,所以使用S3列表API是最理想的。

    (完成后,为什么不将代码发布到其他人的某个地方?)