我有一个拥有少量字段的火花数据框。一些字段是巨大的二进制blob。整行的大小约为50 MB。
我将数据框保存为镶木地板格式。我使用parquet.block.size
参数控制行组的大小。
Spark会生成一个镶木地板文件,但是我总是会在一个行组中获得至少100行。这对我来说是个问题,因为块大小可能会变成千兆字节,这对我的应用程序来说效果不好。
parquet.block.size
按预期工作,只要尺寸足够大,可以容纳超过100行。
我将InternalParquetRecordWriter.java修改为MINIMUM_RECORD_COUNT_FOR_CHECK = 2
,这解决了问题,但是,我找不到可以支持调整此硬编码常量的配置值。
是否有不同/更好的方法来获得小于100的行组大小?
这是我的代码片段:
from pyspark import Row
from pyspark.sql import SparkSession
import numpy as np
from pyspark.sql.types import StructType, StructField, BinaryType
def fake_row(x):
result = bytearray(np.random.randint(0, 127, (3 * 1024 * 1024 / 2), dtype=np.uint8).tobytes())
return Row(result, result)
spark_session = SparkSession \
.builder \
.appName("bbox2d_dataset_extraction") \
.config("spark.driver.memory", "12g") \
.config("spark.executor.memory", "4g")
spark_session.master('local[5]')
spark = spark_session.getOrCreate()
sc = spark.sparkContext
sc._jsc.hadoopConfiguration().setInt("parquet.block.size", 8 * 1024 * 1024)
index = sc.parallelize(range(50), 5)
huge_rows = index.map(fake_row)
schema = StructType([StructField('f1', BinaryType(), False), StructField('f2', BinaryType(), False)])
bbox2d_dataframe = spark.createDataFrame(huge_rows, schema).coalesce(1)
bbox2d_dataframe. \
write.option("compression", "none"). \
mode('overwrite'). \
parquet('/tmp/huge/')
答案 0 :(得分:2)
不幸的是,我还没有找到办法。我报告this issue删除了硬编码值并使其可配置。如果您有兴趣,我会有一个补丁。
答案 1 :(得分:1)
PARQUET-409尚未解决,但是有两种解决方法可以使应用程序与该100
每行组的硬编码最小记录数一起工作。
第一个问题和解决方法:
您提到您的行可能多达50Mb。
这样行组大小约为5Gb。
同时,您的火花执行器只有4Gb(spark.executor.memory
)。
使其明显大于最大行组大小。
对于spark.executor.memory
,我建议使用12-20Gb的大型Spark执行程序存储器。试一试,看看哪个适合您的数据集。
我们的大多数生产作业都在此范围内的Spark执行程序内存中运行。
为了使这种方法适用于如此大的行组,您可能还希望将spark.executor.cores
调低至1,以确保每个执行程序进程一次仅占用一个这样的大行组。 (以牺牲一些Spark效率为代价)也许将spark.executor.cores
设置为2-这可能需要将spark.executor.memory
增加到20-31Gb范围。 (尝试保留under 32Gb,因为jvm切换到未压缩的OOP,这可能会占用50%的内存开销)
第二个问题和解决方法:如此大的5Gb行块很可能分布在许多HDFS块上,因为默认的HDFS块在128-256Mb范围内。 (我假设您像使用“ hadoop”标签一样,使用HDFS来存储这些实木复合地板文件)实木复合地板best practice用于将行组完全驻留在一个HDFS块中:
行组大小:较大的行组允许较大的列块 使得可以做更大的顺序IO。更大的群体 在写路径中需要更多缓冲(或两次通过写)。我们 建议使用较大的行组(512MB-1GB)。由于整个行组 可能需要阅读,我们希望它完全适合一个HDFS块。 因此,HDFS块大小也应设置为更大。一个 优化的读取设置为:1GB行组,1GB HDFS块大小,1 每个HDFS文件的HDFS块。
这里是如何更改HDFS块大小的示例(在您创建此类拼花文件之前进行设置):
sc._jsc.hadoopConfiguration().set("dfs.block.size", "5g")
或在Spark Scala中:
sc.hadoopConfiguration.set("dfs.block.size", "5g")
我希望有时可以将其固定在Parquet级别,但是这两个变通办法应该可以让您在Parquet中使用如此大的行组。