Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache spark 使用日期范围对分区数据进行Spark SQL查询_Apache Spark_Apache Spark Sql - Fatal编程技术网

Apache spark 使用日期范围对分区数据进行Spark SQL查询

Apache spark 使用日期范围对分区数据进行Spark SQL查询,apache-spark,apache-spark-sql,Apache Spark,Apache Spark Sql,我的数据集按以下方式进行分区: Year=yyyy |---Month=mm | |---Day=dd | | |---<parquet-files> Year=yyyy |---月份=毫米 ||---Day=dd | | |--- 在spark中创建包含两个日期之间数据的数据框最简单有效的方法是什么?编辑以添加多个加载路径以处理注释 可以使用正则表达式样式的语法 val dataset = spark .read .format("parque

我的数据集按以下方式进行分区:

Year=yyyy
 |---Month=mm
 |   |---Day=dd
 |   |   |---<parquet-files>
Year=yyyy
|---月份=毫米
||---Day=dd
|   |   |---
在spark中创建包含两个日期之间数据的数据框最简单有效的方法是什么?

编辑以添加多个加载路径以处理注释

可以使用正则表达式样式的语法

val dataset = spark
  .read
  .format("parquet")
  .option("filterPushdown", "true")
  .option("basePath", "hdfs:///basepath/")
  .load("hdfs:///basepath/Year=2017/Month=10/Day={0[6-9],[1-3][0-9]}/*/",
    "hdfs:///basepath/Year=2017/Month=11/Day={0[1-3]}/*/")

注意:您不需要
X=*
,如果您需要所有的天、月等,您只需执行
*

您可能还应该阅读一些关于(如上面的filterPushdown设置为true)的内容


最后,您会注意到上面的basepath选项,其原因可以在这里找到:

如果您必须坚持这种分区策略,答案取决于您是否愿意承担分区发现成本

如果您愿意让Spark发现所有分区,这只需要发生一次(直到添加新文件),那么您可以加载basepath,然后使用分区列进行筛选

如果您不希望Spark发现所有分区,例如,因为您有数百万个文件,那么唯一有效的通用解决方案是将要查询的间隔分成几个子间隔,您可以使用@r0bb23的方法轻松查询,然后合并在一起

如果您希望充分利用上述两种情况,并且拥有稳定的模式,那么可以通过定义外部分区表在元存储中注册分区。如果您希望您的模式随着metastore管理的表的发展而发展,那么此时不要这样做

例如,要在
2017-10-06
2017-11-03
之间进行查询,您需要执行以下操作:

// With full discovery
spark.read.parquet("hdfs:///basepath")
  .where('Year === 2017 && (
    ('Month === 10 && 'Day >= 6') || ('Month === 11 && 'Day <= 3')
  ))

// With partial discovery
val df1 = spark.read.option("basePath", "hdfs:///basepath/")
  .parquet("hdfs:///basepath/Year=2017/Month=10/Day={0[6-9], [1-3][0-9]}/*/")
val df2 = spark.read.option("basePath", "hdfs:///basepath/")
  .parquet("hdfs:///basepath/Year=2017/Month=11/Day={0[1-3]}/*/")
val df = df1.union(df2)

值得添加小时和分钟的原因是,您可以编写处理时间间隔的通用代码,而不管您是按周、日、小时还是每15分钟对数据进行分区。事实上,您甚至可以在同一个表中管理不同粒度的数据,例如,较旧的数据在更高级别上聚合,以减少需要查找的分区总数。

如果您希望对分区进行简单的范围查询,最好的解决方案是使用更好的分区策略,其中时间位于单个轴上,例如。,
/tbl/ts=yyyymmddhhmm/*.parquet
。在这篇文章中,有一部分是关于这个主题的,这不是问题的一般解决方案。事实上,使用这种分区策略查询日期间隔并没有简单的通用解决方案。例如,您将如何使用此方法在
2017-10-06
2017-11-03
之间进行查询?下面的答案中有一些好信息。但您不需要答案中显示的工会(请参见上面的编辑)。所以我不得不说,我认为它比你想象的更具普遍性,不过,它需要一些不太漂亮的辅助函数。但对于大多数系统来说,这是值得的。因为,正如您所承认的,分区发现在规模上并不便宜。部分发现只是在规模上更好。虽然我同意,但更好的分区策略会有所帮助。我使用的东西更像下面的东西,使助手函数和上面的代码变得简单。因为spark在保存为拼花地板格式时为每个分区创建了一个文件夹:你上一个通用提案不会创建大量文件夹(每分钟一个)吗?这不可能是一个问题(io/ressource-wise)对于操作系统?(在基于unix的系统上,我认为有时需要通过ulimit进行一些调优)。谢谢你的回答,顺便说一句@AydinK。对你的问题有两个想法。首先,能够解析到分钟粒度并不意味着将其划分为单个分钟粒度是有意义的。我在生产中听说的最小值是15分钟,即最后两位的
00
15
30
45
。其次,在大数据中使用标准文件系统是不寻常的。大多数生产环境使用HDFS或基于云的对象存储(如AWS S3),它们可以处理大量对象。
spark.read.parquet("hdfs:///basepath")
  .where('ts >= 201710060000L && 'ts <= 201711030000L)