Apache spark __配置单元\默认\分区\作为粘合ETL作业中的分区值

Apache spark __配置单元\默认\分区\作为粘合ETL作业中的分区值,apache-spark,amazon-s3,pyspark,boto3,aws-glue,Apache Spark,Amazon S3,Pyspark,Boto3,Aws Glue,我有一个CSV数据,它是通过一个胶水爬虫程序进行爬网的,最后被放在一个表中 我试图运行一个ETL作业,将磁盘上的数据重新划分为日期列的一些组件。然后将CSV转换为拼花地板 i、 我的数据中有一个名为date的列,我想在s3上将数据划分为年、月、日分区 我能够转换为拼花地板,并使其在序列号值的不同列上正确分区,但它将值uu HIVE_DEFAULT_partition_uu_u放入与日期相关分区的所有值year、month和day中 我可以对其他列(如序列号)进行分区,但年/月/日不在原始数据集中

我有一个CSV数据,它是通过一个胶水爬虫程序进行爬网的,最后被放在一个表中

我试图运行一个ETL作业,将磁盘上的数据重新划分为日期列的一些组件。然后将CSV转换为拼花地板

i、 我的数据中有一个名为date的列,我想在s3上将数据划分为年、月、日分区

我能够转换为拼花地板,并使其在序列号值的不同列上正确分区,但它将值uu HIVE_DEFAULT_partition_uu_u放入与日期相关分区的所有值year、month和day中

我可以对其他列(如序列号)进行分区,但年/月/日不在原始数据集中,因此我的方法是将日期列中的值创建为数据集中的新列,并告诉write_dynamic_frame函数按列进行分区,但这不起作用

一般来说,我对spark/pyspark和glue都是新手,所以很有可能我遗漏了一些简单的东西

感谢所有提供帮助的人

import sys
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.sql import functions as F
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.dynamicframe import DynamicFrame
from awsglue.job import Job


args = getResolvedOptions(sys.argv, ['JOB_NAME'])

sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)
job.init(args['JOB_NAME'], args)

datasource0 = glueContext.create_dynamic_frame.from_catalog(database = "my_database", table_name = "my_table", transformation_ctx = "datasource0")
applymapping1 = ApplyMapping.apply(frame = datasource0, mappings = [("date", "date", "date", "date"), ("serial-number", "string", "serial-number", "string")], transformation_ctx = "applymapping1")
resolvechoice2 = ResolveChoice.apply(frame = applymapping1, choice = "make_struct", transformation_ctx = "resolvechoice2")
dropnullfields3 = DropNullFields.apply(frame = resolvechoice2, transformation_ctx = "dropnullfields3")

to_spark_df4 = dropnullfields3.toDF()

with_file_name_df5 = to_spark_df4.withColumn("input_file_name", F.input_file_name()).withColumn('year', F.year(F.col("date").cast("date"))).withColumn('month', F.month(F.col("date").cast("date"))).withColumn('day', F.dayofmonth(F.col("date").cast("date")))

back_to_glue_df8 = DynamicFrame.fromDF(with_file_name_df5, glueContext, "back_to_glue_df8")


datasink4 = glueContext.write_dynamic_frame.from_options(frame = back_to_glue_df8, connection_type = "s3", connection_options = {"path": "s3://output/path","partitionKeys": ["serial-number","year", "month","day"]}, format = "parquet", transformation_ctx = "datasink4")
job.commit()
结果是我在s3中的键最终看起来像这样:

serial-number=1234567890/year=__HIVE_DEFAULT_PARTITION__/month=__HIVE_DEFAULT_PARTITION__/day=__HIVE_DEFAULT_PARTITION__/part-01571-273027e4-72ba-45ff-ac15-c0bb2f342e58.c000.snappy.parquet

更新:为格式化而编辑

我运行的作业与您的作业非常相似。我希望你现在能解决这个问题,但不管怎样,以下是解决你困境的方法:

碱性溶液: 从pyspark.sql.functions导入年、月、月、日 在包含ApplyMapping之前的代码的其余部分 添加年、月和日列,非零填充 df=df.toDF df=带有“年”列的df,yeardf.date\ .带“月”列,每月日期\ .带有“day”列,dayofmonthdf.date 补充说明: 如果您需要在Athena上运行查询以选择日期范围,我建议您避免使用嵌套分区,因此年->月->日,而是使用平面分区模式。这样做的原因是,查询的编写变得更加简单。下面是获取平面模式的python代码:

从pyspark.sql.functions导入日期\格式 在包含ApplyMapping之前的代码的其余部分 df=df.toDF df=df.带有'date_2',date_formatdf.date',yyyy-MM-dd' 日期_2是因为列日期已经存在, 但是我们希望分区的格式是字符串格式。 如果愿意,您可以稍后删除原始列。 假设您现在要查询2020年3月15日至4月3日的数据

下面是基于您选择的分区模式的SQL查询

嵌套模式 选择项目1、项目2 从我的桌子上 其中年份=2020年 和 月=3天>=15天
或者月=4,如果partitionKey的值为空,则创建_配置单元u默认分区_uu。日期字段是否已填充?当您这样做:。使用列'year',F.yearF.coldate.castdate时,我注意到您以前有一个ApplyMapping,它将字段和类型从一个日期映射到另一个日期,我想知道您是否需要在数据帧转换回glue dynamicframe后执行此操作?我看着那些ApplyMapping“自动生成的步骤并阅读文档,除了重命名列或更改类型之外,我想知道这有什么意义?我在Athena文档中读到分区类型必须是基本类型,它没有枚举,但我假设这意味着从那些年、月、日函数返回的整数应该是可以的。我想也许我已经读到类型必须是字符串,但这里有一个与原生pyspark非常相似的有效示例:下面是关于在新附加的列之后使用ApplyMapping的注释