PySpark:如何在读取parquet文件时读取分区列

4

我有一些数据存储在parquet文件和hive表中,按年、月、日进行分区。因此,每个parquet文件都存储在/table_name/year/month/day/文件夹中。

我只想读取部分分区的数据。我有以下单个分区路径列表:

paths_to_files = ['hdfs://data/table_name/2018/10/29',
                  'hdfs://data/table_name/2018/10/30']

然后尝试做类似这样的事情:

df = sqlContext.read.format("parquet").load(paths_to_files)

然而,我的数据不包括“年、月和日”的信息,因为这些不是数据本身的一部分,而是存储在文件路径中的信息。我可以使用SQL上下文和hive查询,并使用某些select语句来选择只从我感兴趣的分区中选择数据。然而,我宁愿避免在Python中构建SQL查询,因为我非常懒,不喜欢阅读SQL。
我的两个问题是:
1. 以性能为优化目标的最佳数据读取方式是什么?其中,关于年、月和日的信息不存在于parquet文件中,但是只包含在文件路径中(使用sqlContext.sql('...')发送hive查询,或使用read.parquet等任何方法)。 2. 当使用我上述的方法时,是否可以提取分区列的信息?

1
你好, 你是否考虑过使用函数input_file_name()为每个文件添加一个附加的列,其中包含文件名,类似于以下链接中的示例:https://dev59.com/qVkS5IYBdhLWcg3wb2Ts 这样你的路径就会被包含在内。你甚至可以使用正则表达式剥离路径的某些部分,例如月份、日期。 - gaw
是的,我尝试过那样做,但解析年、月和日似乎有点慢。 - ira
1
我认为你可以添加basepath选项 sqlContext.read.option("basePath", hdfs://data/table_name).format("parquet").load(paths_to_files),然后你就能得到你想要的列。这是在稍微不同的用法中对我有效的方法。 - Josh Herzberg
谢谢@JoshHerzberg。添加option("basePath",..)对我有用 :) - Vasanth Subramanian
2个回答

3
阅读年份分区的父目录的直接文件路径对于数据框架来说应该足够确定有它下面的分区。然而,如果没有像/year=2018/month=10这样的目录结构,数据框架就不知道如何命名分区。
因此,如果您使用Hive,则通过元存储更好,因为分区在那里被命名,Hive存储关于表格的额外有用信息,您不需要依靠从Spark代码中知道磁盘上文件的直接路径。
不确定您为什么认为需要读/写SQL。
请使用数据框架API代替,例如:
df = spark.table("table_name")
df_2018 = df.filter(df['year'] == 2018)
df_2018.show() 

不幸的是,当我尝试读取年份分区的父目录路径时,出现了“无法确定parquet模式”的错误。目前还没有找到解决方法。非常感谢您提供的处理方法,而无需编写SQL查询语句。 - ira
请您提供一些详细信息,说明为什么通过元数据存储访问会更好? - ira
Hive元数据存储知道文件的位置,并自动确定parquet文件的列和元数据。 - OneCricketeer
非常感谢!使用dataframe api写入表格也是可能的吗?(我有一个外部hive表,以parquet格式存储,由一列分区) - ira
df.saveAsTable,我相信。 - OneCricketeer

-1

您的数据存储方式不太适合 parquet 格式,因此您需要逐个加载文件并添加日期。

或者,您可以将文件移动到适合 parquet 的目录结构中(例如.../table/year=2018/month=10/day=29/file.parquet),然后您可以读取父目录(table)并按年、月和日进行过滤(Spark 仅会读取相关目录),这样您的 DataFrame 中也会包含这些属性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接