Scala 使用存储在spark sql数据帧中的信息将其保存到S3的最佳方法

Scala 使用存储在spark sql数据帧中的信息将其保存到S3的最佳方法,scala,apache-spark,amazon-s3,apache-spark-sql,Scala,Apache Spark,Amazon S3,Apache Spark Sql,我有数据帧,数据如下: channel eventId1 eventId2 eventTs eventTs2 serialNumber someCode Web-DTB akefTEdZhXt8EqzLKXNt1Wjg akTEdZhXt8EqzLKXNt1Wjg 1545502751154 1545502766731 4 rfs Web-DTB 3ycLHHrbE

我有数据帧,数据如下:

        channel  eventId1               eventId2               eventTs  eventTs2  serialNumber  someCode
        Web-DTB akefTEdZhXt8EqzLKXNt1Wjg    akTEdZhXt8EqzLKXNt1Wjg  1545502751154   1545502766731   4   rfs
        Web-DTB 3ycLHHrbEkBJ.piYNyI7u55w    3ycLHHEkBJ.piYNyI7u55w  1545502766247   1545502767800   4   njs
        Web-DTB 3ycL4rHHEkBJ.piYNyI7u55w    3ycLHHEkBJ.piYNyI7u55w  1545502766247   1545502767800   4   null
我需要将此数据保存到S3路径,如下所示:

  s3://test/data/ABC/hb/eventTs/[eventTs]/uploadTime_[eventTs2]/*.json.gz
当我需要从分区中提取数据以写入S3路径时,如何继续执行此操作:(S3路径是数据帧中存在的events和events2的函数)

我想我可以迭代数据帧中的每一行,提取路径并保存到S3,但我不想这样做


有没有办法按EventS和eventTs2上的数据帧分组,然后将数据帧保存到完整的S3路径中?有没有更好的

Spark支持类似于Hive中的分区。如果eventTs、eventTs2的不同元素数量较少,分区将是解决此问题的一个好方法

有关partitionBy的更多信息,请查看

用法示例:

val someDF = Seq((1, "bat", "marvel"), (2, "mouse", "disney"), (3, "horse", "animal"), (1, "batman", "marvel"), (2, "tom", "disney") ).toDF("id", "name", "place")
someDF.write.partitionBy("id", "name").orc("/tmp/somedf")
如果使用“id”和“name”上的paritionBy编写数据帧,将创建以下目录结构

/tmp/somedf/id=1/name=bat
/tmp/somedf/id=1/name=batman

/tmp/somedf/id=2/name=mouse
/tmp/somedf/id=2/name=tom

/tmp/somedf/id=3/name=horse
第一个和第二个分区成为目录,id等于1且名称为bat的所有行将保存在目录结构下
/tmp/somedf/id=1/name=bat
,分区BY中定义的分区顺序决定了目录的顺序

在您的情况下,分区将位于events和events2上

val someDF = Seq(
        ("Web-DTB","akefTEdZhXt8EqzLKXNt1Wjg","akTEdZhXt8EqzLKXNt1Wjg","1545502751154","1545502766731",4,"rfs"),
        ("Web-DTB","3ycLHHrbEkBJ.piYNyI7u55w","3ycLHHEkBJ.piYNyI7u55w","1545502766247","1545502767800",4,"njs"),
        ("Web-DTB","3ycL4rHHEkBJ.piYNyI7u55w","3ycLHHEkBJ.piYNyI7u55w","1545502766247","1545502767800",4,"null"))
    .toDF("channel" , "eventId1", "eventId2", "eventTs",  "eventTs2",  "serialNumber",  "someCode")
someDF.write("eventTs", "eventTs2").orc("/tmp/someDF")
创建一个目录结构,如下所示

/tmp/someDF/eventTs=1545502766247/eventTs2=1545502767800
/tmp/someDF/eventTs=1545502751154/eventTs2=1545502766731

除了在S3中存储之外。我知道这种分区逻辑。在S3中寻找一种简单而干净的方法。分区将是最简单的IMHO,除非eventTS/eventTS2中不同元素的数量不是以千为单位,并且dataframe中没有数千个分区。在这种情况下,每个分区将创建数千个非常小的文件。编辑此问题以更清楚地了解我的处境。S3路径是eventTs和eventTs2的函数,我怀疑我们是否可以在S3中保存而不指定HDFS中存储的完整路径。您可以在S3中保存而不指定完整路径,试试看。工作正常!大学教师;我不知道为什么我认为不会。基于此进行分区后,是否仍然可以删除列?或者在partitionBy中使用自定义项?因为我不想格式化日期,不想从epoch以yyyyMMdd格式存储新列,也不想增加数据量。我无法删除原始列的粒度。因为我有3个不同于原始数据列的分区列。
/tmp/someDF/eventTs=1545502766247/eventTs2=1545502767800
/tmp/someDF/eventTs=1545502751154/eventTs2=1545502766731