Dask日期列存储为Parquet后Apache Drill查询返回微秒时间戳问题
Dask存储Parquet日期列类型异常的解决方法
问题背景
- 基于含日期列、数值列的Dask DataFrame,执行如下代码写入Parquet存储:
ddf.to_parquet('/some/folder', engine='pyarrow', overwrite=True)
- 预期效果:日期列以Parquet原生日期类型写入,查询时可直接得到格式化的年月日值
- 实际现象:使用Apache Drill查询时,日期列返回16位微秒级时间戳数值,对应关系如下:
- 数值
1546300800000000对应实际期望日期2019-01-01 - 数值
1548979200000000对应实际期望日期2019-02-01
- 数值
- 已尝试在Drill中使用CAST语句将数值转换为日期格式,未得到预期结果
- 待解决问题:
- 是否存在配置项可指定Dask将日期列以原生日期类型写入Parquet
- 如何通过Apache Drill查询获取正确的格式化日期结果
解决方案
1. Dask端修正写入的Parquet日期类型
出现微秒时间戳存储的核心原因:Dask搭配pyarrow引擎写入时,默认会将datetime64类型列映射为timestamp[us](微秒级时间戳)类型,而非Parquet规范定义的原生DATE类型,可通过显式指定schema强制类型映射:
- 写入前先对日期列做类型预处理,剥离时分秒信息,切换为pyarrow的原生日期类型
- 调用
to_parquet时通过schema参数显式声明列类型,示例代码:
import pyarrow as pa # 预处理日期列,转为pyarrow原生日期类型 ddf['date_col'] = ddf['date_col'].dt.date.astype('date32[pyarrow]') # 写入时指定schema,强制日期列为Parquet原生DATE类型 ddf.to_parquet( '/some/folder', engine='pyarrow', overwrite=True, schema=pa.schema([ ('date_col', pa.date32()), ('value_col', pa.float64()) # 按实际数值列类型调整 ]) )
- 完成上述配置后,Parquet文件中的日期列会以原生DATE类型存储,不再以微秒时间戳形式落盘
2. Apache Drill端转换微秒时间戳为日期格式
针对已经生成的微秒时间戳存储的Parquet文件,无需重新生成文件,可在查询时通过内置函数完成转换,之前CAST转换失败的原因是未对齐时间戳单位,直接将微秒值按秒级epoch传入转换函数,导致结果异常:
- 转换逻辑:先将微秒级时间戳除以1000000,换算为秒级epoch时间,再通过时间转换函数生成目标日期
- 字符串格式日期查询示例:
SELECT FROM_UNIXTIME(date_col / 1000000, 'yyyy-MM-dd') AS formatted_date, value_col FROM dfs.`/some/folder`
- 原生DATE类型结果查询示例(返回值为日期类型而非字符串):
SELECT CAST(TO_TIMESTAMP(date_col / 1000000) AS DATE) AS date_value, value_col FROM dfs.`/some/folder`
- 结果校验:
- 代入值
1546300800000000,换算后秒级epoch为1546300800,转换后正好得到2019-01-01 - 代入值
1548979200000000,换算后秒级epoch为1548979200,转换后正好得到2019-02-01
- 代入值
内容的提问来源于stack exchange,提问作者ps0604
相关产品推荐
相关产品推荐

