为文件输入

时间:2016-05-25 08:35:50

标签: java scala hadoop apache-spark rdd

我是Spark和Hadoop生态系统的新手,已经爱上了它。 现在,我正在尝试将现有Java应用程序移植到Spark。

此Java应用程序的结构如下:

  1. 使用BufferedReader逐个读取文件,其中自定义Parser类对输入数据执行一些繁重的计算。输入文件各为1到最大2.5 GB。
  2. 将数据存储在内存中(HashMap<String, TreeMap<DateTime, List<DataObjectInterface>>>
  3. 将内存数据存储区写为JSON。这些JSON文件的大小较小。
  4. 我写了一个Scala应用程序,它确实由一个worker处理我的文件,但这显然不是我从Spark中获得的最大性能优势。

    现在我把这个移植到Spark的问题: 输入文件是基于行的。我通常每行有一条消息。但是,某些消息依赖于前面的行来在Parser中形成实际的有效消息。例如,我可能会在输入文件中按以下顺序获取数据:

    1. {timestamp}# 0x033 #{data_bytes} \ n
    2. {timestamp}# 0x034 #{data_bytes} \ n
    3. {timestamp}# 0x035 #{data_bytes} \ n
    4. {时间戳}#0x0FE#{data_bytes} \ n
    5. {timestamp}# 0x036 #{data_bytes} \ n
    6. 要形成一条超出“组合消息”0x036的实际消息,解析器还需要消息0x033,0x034和0x035中的行。其他消息也可以介于这些所需消息集之间。可以通过读取一行来解析大多数消息。

      现在最后我的问题: 如何让Spark根据我的目的正确拆分我的文件?文件不能“随机”拆分;它们必须以确保可以解析所有消息的方式进行拆分,并且解析器不会等待他永远不会得到的输入。这意味着每个组合消息(依赖于前一行的消息)需要在一个分割中。

      我想有几种方法可以实现正确的输出,但我会在这篇文章中提出一些想法:

      • 为文件输入定义手动分割算法?这将检查分割的最后几行是否包含“大”消息的开头[0x033,0x034,0x035]。
      • 拆分文件但是想要火花,但也要添加固定数量的行(比方说50,这将确保工作)从最后一次拆分到下一次拆分。 Parser类将正确处理多个数据,不会引入任何问题。

      第二种方式可能更容易,但我不知道如何在Spark中实现它。有人能指出我正确的方向吗?

      提前致谢!

1 个答案:

答案 0 :(得分:1)

我在http://blog.ae.be/ingesting-data-spark-using-custom-hadoop-fileinputformat/的博文上看到了您的评论,并决定在此处提供我的意见。

首先,我不完全确定你要做什么。请帮帮我:你的文件包含0x033,0x034,0x035和0x036的行,所以Spark会单独处理它们?实际上这些线路需要一起处理吗?

如果是这种情况,您不应将此解释为“腐败分裂”。正如您可以在博客中看到的那样,Spark将文件拆分为可以单独处理的记录。默认情况下,它通过拆分换行符上的记录来完成此操作。但是,在你的情况下,你的“记录”实际上分布在多行。所以,是的,您可以使用自定义fileinputformat。我不确定这是最简单的解决方案。

您可以尝试使用执行以下操作的自定义fileinputformat来解决此问题:而不是像默认fileinputformat那样逐行提供,您解析文件并跟踪遇到的记录(0x033,0x034等)。同时你可以过滤掉像0x0FE这样的记录(不确定你是否想在其他地方使用它们)。结果是Spark将所有这些物理记录作为一个逻辑记录。

另一方面,可能更容易逐行读取文件并使用功能键(例如[对象33,0x033],[对象33,0x034],......)映射记录。这样,您可以使用您选择的键组合这些行。

当然还有其他选择。无论您选择哪种,都取决于您的使用案例。