按日期

时间:2016-07-29 11:24:35

标签: scala apache-spark amazon-s3 apache-spark-sql aws-sdk

描述

我有一个应用程序,它将数据发送到AWS Kinesis Firehose,并将数据写入我的S3存储桶。 Firehose使用" yyyy / MM / dd / HH"格式来写文件。

与此示例中的S3路径类似:

s3://mybucket/2016/07/29/12

现在我有一个用Scala编写的Spark应用程序,我需要从特定时间段读取数据。我有开始和结束日期。数据采用JSON格式,这就是我使用sqlContext.read.json()而不是sc.textFile()的原因。

如何快速有效地阅读数据?

我尝试了什么?

  1. 通配符 - 我可以选择特定日期或特定月份所有日期的所有小时数据,例如:

    val df = sqlContext.read.json("s3://mybucket/2016/07/29/*")
    val df = sqlContext.read.json("s3://mybucket/2016/07/*/*")
    

    但如果我必须阅读几天的日期,例如2016-07-29 - 2016-07-30我不能以相同的方式使用通配符方法。

    这让我想到了下一点...

  2. 使用多个路径this解决方案中 samthebest 所示的目录CSV。使用逗号分隔目录似乎仅适用于sc.textFile()而不是sqlContext.read.json()
  3. 联盟 - 的上一个链接的第二个解决方案建议分别读取每个目录,然后将它们合并在一起。虽然他建议联合RDD-s,但也可以选择联合DataFrames。如果我手动生成给定日期时间段的日期字符串,那么我可能会创建一个不存在的路径,而不是忽略它,整个读取失败。相反,我可以使用AWS SDK并使用AmazonS3Client中的函数listObjects来获取上一个链接中的 iMKanchwala 解决方案中的所有密钥。

    唯一的问题是我的数据在不断变化。如果read.json()函数将所有数据作为单个参数获取,它将读取所有必需的数据,并且足够智能从数据中推断出json模式。如果我单独阅读2个目录并且它们的模式不匹配,那么我认为联合这两个数据帧会成为一个问题。

  4. nhahtdh 的全局(?)语法 - This解决方案比 1 和< strong> 2 因为它们提供了更详细地指定日期和目录的选项,并且作为单个&#34;路径&#34;所以它也适用于read.json()

    但同样,对于丢失的目录,会出现一个熟悉的问题。让我们说我想要从20.07到30.07的所有数据,我可以这样声明:

    val df = sqlContext.read.json("s3://mybucket/2016/07/[20-30]/*")
    

    但如果我错过了7月25日的数据,那么路径..16/07/25/就不存在了,整个功能都失败了。

  5. 显然当请求的时间段是25.11.2015-12.02.2016时会变得更加困难,那么我需要以编程方式(在我的Scala脚本中)创建一个类似这样的字符串路径:

    "s3://mybucket/{2015/11/[25-30],2015/12/*,2016/01/*,2016/02/[01-12]}/*"
    

    通过创建它,我会以某种方式确定这些25-30和01-12间隔都有相应的路径,如果缺少一个,它会再次失败。 (幸运的是,Asterisk会处理丢失的目录,因为它会读取存在的所有内容)

    如何从一个目录路径中一次性读取所有必要的数据而不会因某个日期间隔之间缺少目录而失败?

1 个答案:

答案 0 :(得分:12)

有一个更简单的解决方案。如果您查看DataFrameReader API,您会发现有.json(paths: String*)方法。只需构建一个你想要的路径集合,然后根据你的喜好建立一个路径,然后调用方法,例如,

val paths: Seq[String] = ...
val df = sqlContext.read.json(paths: _*)