按时间戳或年,月,日,小时分区更好吗

Posted

技术标签:

【中文标题】按时间戳或年,月,日,小时分区更好吗【英文标题】:Is it better to partition by time stamp or year,month,day, hour 【发布时间】:2019-08-08 08:34:25 【问题描述】:

我正在开发一个 spark 应用程序,它将处理后的数据写入 parquet 文件,并且对数据的查询总是大约一个时间段。因此,我想按日期时间对其进行分区。这两种方法哪一种更好?

DataFrame: |CreationTime(java.sql.Timestamp)|数据(字符串)|

1) dataframe.write.partitionBy("CreationTime").parquet(path)

2) dataframe.withColumn("year", year("CreationTime")) .withColumn("month", month("CreationTime")) .withColumn("day", day("CreationTime")) .write.partitionBy("year","month","day").parquet(path)

在第二种情况下,阅读器变得复杂,它必须执行startTime.year > col("year") and endTime.year < col("year),月份和日期也是如此。

在这种情况下,对数据进行分区的常见做法和建议是什么?

【问题讨论】:

如果使用第一个选项,分区大小是多少(CreationTime 有多详细)? 跟进@JeroenHeier,第一个选项实际上并没有多大意义。按日期进行分区肯定会创建分区,但您永远无法知道有多少分区以及分区边界是什么:您将无法在查询时优化可预测的策略。使用自定义策略(例如明确年、月等)为您提供可预测的基数,以及更多的查询时间优化。如果您只需要查看第一项即可丢弃整个文件,那是一个胜利。您的建议可能更简单(yyyy-MM 字符串怎么样,尽管它的重量超过两个 int) 我正在尝试每隔 10 分钟在生产者处存储我的数据。假设我每 10 分钟就有 1GB。 【参考方案1】:

以每 10 分钟 1GB 为目标意味着您将很快建立大量数据(1000 个文件和每周 1 TB 的数据,不分先后)。

你的选择至少要考虑到:

您必须支持的查询(它们 - 几乎 - 总是有时间范围,还是永远没有?) 您要将其转储到的存储(您是否必须跨多个数据中心/S3 存储桶/...进行拆分) 分区方案将添加到数据之上的大小

例如,创建年列、月列、日列、小时列和分钟列意味着为每个记录创建 5 个列,每个列都是数字类型。也许它可以忽略不计,也许根本就不是。而且,对于无助于构建任何功能的数据,您必须为写入时存储空间的增加、相关带宽和读取时解析它的 CPU 付出代价。

另一方面,这将是一种非常可读/可调试的方式来存储这些数据。

您可以采用另一种更简单的策略,即用一个数字表示每 10 分钟的帧:yourTimestampInMillisSinceEpoch / TimeUnit.MINUTES.convert(10, TimeUnit.MILLISECONDS)。这只需要你一个号码。

我会推荐这种“单列”策略,但我不会就此止步。

在实际将文件写入单个路径之前,我会按天和按月拆分数据帧。并不是说我实际上需要存储日期和月份(我会在写结果之前删除它们),但我会使用它们来构建我的 parquet 文件夹路径,类似于(hdfs or S3, etc...)://your_root/year/month/day/。 (一种特别有效的方法是利用partition discovery at the spark level,它允许 Spark 使用目录路径来“推断”“虚拟”列,并相应地优化查询)。

如果我需要在某个时间范围内查询,这将允许我利用 HDFS globs,甚至不开始读取没有机会保存该给定时间范围内任何有趣数据的文件。

将所有数据转储到单个路径会阻止这种优化,您需要列出一个非常大的目录,然后打开每个文件以查看它所在的时间窗口,这将非常浪费 CPU,带宽、性能(是的,未来还有钱)。

【讨论】:

以上是关于按时间戳或年,月,日,小时分区更好吗的主要内容,如果未能解决你的问题,请参考以下文章

Spark Sql:从时间戳按小时间隔分区

如何按特定日期范围(例如小时、日、月)对数据进行分组?

按 24 小时划分并使用 pyspark 或 panda 聚合

将时间分区添加到表的最佳实践

JavaScript 中两个日期的年、月、日之间的差异

请教WINDOWS怎么批量转换时间戳