使用小于100的行组大小在spark中创建镶木地板文件

时间:2018-01-09 22:51:15

标签: hadoop apache-spark parquet

我有一个拥有少量字段的火花数据框。一些字段是巨大的二进制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/')

2 个答案:

答案 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中使用如此大的行组。