Pandas导出Parquet适配Redshift外部表的PyArrow与fastparquet实现方案
我有一个非常简单的思路:出于便捷性考虑,使用Python Pandas对中等体量数据执行简单数据库操作后,将数据以Parquet格式回写到S3,再将该数据作为外部表挂载到Redshift,避免占用Redshift集群本身的存储空间。我找到了两种实现方案:
示例数据
示例测试数据构造代码如下:
from datetime import date, datetime import pandas as pd data = { 'int': [1, 2, 3, 4, None], 'float': [1.1, None, 3.4, 4.0, 5.5], 'str': [None, 'two', 'three', 'four', 'five'], 'boolean': [True, None, True, False, False], 'date': [ date(2000, 1, 1), date(2000, 1, 2), date(2000, 1, 3), date(2000, 1, 4), None, ], 'timestamp': [ datetime(2000, 1, 1, 1, 1, 1), datetime(2000, 1, 1, 1, 1, 2), None, datetime(2000, 1, 1, 1, 1, 4), datetime(2000, 1, 1, 1, 1, 5), ] } df = pd.DataFrame(data) df['int'] = df['int'].astype(pd.Int64Dtype()) df['date'] = df['date'].astype('datetime64[D]') df['timestamp'] = df['timestamp'].astype('datetime64[s]')
末尾的类型转换操作在两种方案中均为必要步骤,可避免Pandas自动类型识别产生干扰。
采用PyArrow的实现代码如下:
import pyarrow as pa pyarrow_schema = pa.schema([ ('int', pa.int64()), ('float', pa.float64()), ('str', pa.string()), ('bool', pa.bool_()), ('date', pa.date64()), ('timestamp', pa.timestamp(unit='s')) ]) df.to_parquet( path='pyarrow.parquet', schema=pyarrow_schema, engine='pyarrow' )
PyArrow优势说明:Pandas导出Parquet的默认引擎为PyArrow,集成适配性好,同时功能丰富,支持的数据源类型非常全面。
使用fastparquet需要额外配置相关参数,导出代码如下:
from fastparquet import write write('fast.parquet', df, has_nulls=True, times='int96')
这里的核心配置是times参数,我在fastparquet官方项目的issue讨论中找到了date字段适配问题的解决方案。
fastparquet优势说明:fastparquet相比PyArrow功能局限性更强,尤其是支持的数据类型更少,但对应的安装包体积要小很多。
完成Parquet文件导出并存入S3后,可通过以下SQL语句将数据挂载为Redshift外部表:
CREATE EXTERNAL TABLE "<your_external_schema>"."<your_table_name>" ( "int" bigint, "float" float, "str" varchar(255), "boolean" bool, "date" date, "timestamp" timestamp) ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe' STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat' location 's3://<your_bucket>/<your_prefix>/';
我最初在AWS Lambda函数场景中使用Pandas、Parquet和Redshift外部表时,初期运行一切正常,直到Lambda部署包体积达到了上限(参考AWS Lambda官方的部署包体积限制规则)。排查依赖体积后发现PyArrow、Pandas以及Pandas依赖的Numpy是体积占用的主要来源。由于不能为了性能舍弃Numpy,同时也不想放弃Pandas的便捷性,我便尝试寻找轻量的PyArrow替代方案,最终找到了fastparquet,经过调研和大量测试后成功实现了需求。
希望以上说明和相关资源能为其他开发者提供帮助。
内容的提问来源于stack exchange,提问作者Werner

