Mar*_*kus 4 python apache-spark parquet pyspark
语境
我有一个Parquet存储在 HDFS 中的表,有两个分区,每个分区仅生成一个文件。
parquet_table \
| year=2020 \
file_1.snappy.parquet
| year=2021 \
file_2.snappy.parquet
Run Code Online (Sandbox Code Playgroud)
我的计划是只获取最新的分区并对其进行处理。
parquet_table \
| year=2020 \
file_1.snappy.parquet
| year=2021 \
file_2.snappy.parquet
Run Code Online (Sandbox Code Playgroud)
这有效,我只检索所需的数据。当我写这篇文章时,pySpark我假设纯 Spark 将在某种程度上是模拟的。
问题
尽管我检索了正确的数据,Spark 仍然有两个分区连接到 DataFrame df:
df = spark.read.parquet("hdfs_path_to_table/parquet_table/year=2021/")
Run Code Online (Sandbox Code Playgroud)
当我计算分区内的内容时,我发现只有一个产生数据:
df.rdd.getNumPartitions()
# -> 2
Run Code Online (Sandbox Code Playgroud)
当然,我现在可以轻松地完成df.coalesce(1)并最终获得所需的结果。不管怎样,我想知道为什么会发生这种情况,实际上我宁愿不想合并,而是直接只检索分区。
问题
有什么解决方案让我的 DataFramedf只有相应的正确值吗.getNumPartitions()?因此,有没有办法加载单个parquet文件并在单个分区中生成该文件?
问题之一是partitionSpark 世界中的一个重载术语,您正在查看两种不同类型的分区:
您的数据集被组织为一个Hive-partitioned表,其中每个分区都是一个以 <partition_attriute>=<partiton_value> 命名的单独目录,其中可能包含许多数据文件。这仅对动态修剪要读取的输入文件集有用,对实际的 RDD 处理没有影响
当 Spark 加载数据并创建 DataFrame/RDD 时,该 RDD 被组织为可以并行处理的分割,也称为分区。
df.rdd.getNumPartitions()返回数据中的拆分数量,这与输入表分区完全无关。它由许多配置选项决定,但主要由 3 个因素驱动:
spark.default.parallelism特别是为什么你的 RDD 中有 2 个分区,即使你没有足够的数据来填充第一个分区spark.sql.files.maxPartitionBytes,因此可能会将单个多 GB parquet 文件拆分为多个分区)spark.sql.shuffle.partitionsAQE 设置控制)总的来说,您希望保留此行为,因为 Spark 有必要并行处理数据并获得良好的性能。当您使用时,df.coalesce(1)您会将数据合并到单个 RDD 分区中,但您将在单个核心上进行处理,在这种情况下,只需在 Pandas 和/或 Pyarrow 中完成工作会快得多。
如果您想要保留输出上的属性,以便每个 Hive 分区属性都有一个 parquet 文件,则可以使用以下构造:
# Read your partitioned dataset and filter on your preferred partition(s)
df = spark.read.parquet("hdfs_path_to_table/parquet_table/").filter("year = 2021")
# do your work
df_output = df.<do_something>
# repartition impacts how Spark organize the data in RDD splits
df_repartitioned = df_output.repartition("<partition attribute>")
# PartitionedBy impacts how Spark organizes data on disk in separate folders
df_repartitioned.write.mode("overwrite").partitionedBy("<partition_attribute>").parquet("hdfs_output")
Run Code Online (Sandbox Code Playgroud)
如果您处理某些分区并且不想每次都覆盖完整输出,请务必设置spark.sql.sources.partitionOverwriteMode=dynamic为仅覆盖受影响的 Hive 分区。
| 归档时间: |
|
| 查看次数: |
1996 次 |
| 最近记录: |