Apache Spark:保存按“虚拟”列分区的DataFrame

13
我正在使用PySpark进行经典ETL作业(加载数据集,处理它,保存它),并希望将我的DataFrame保存为按“虚拟”列分区的文件/目录;我所说的“虚拟”是指我有一个名为Timestamp的列,其中包含ISO 8601编码的日期字符串,并且我想要按年/月/日进行分区;但是,实际上我在DataFrame中没有年、月或日列;尽管我可以从这个Timestamp中推导出这些列,但我不希望我的结果项序列化其中一个这些列。
保存DataFrame到磁盘后的文件结构应如下:
/ 
    year=2016/
        month=01/
            day=01/
                part-****.gz

是否有一种使用Spark / Pyspark实现我想要的方法?

1个回答

24

用于分区的列不包含在序列化数据本身中。例如,如果您像这样创建 DataFrame

df = sc.parallelize([
    (1, "foo", 2.0, "2016-02-16"),
    (2, "bar", 3.0, "2016-02-16")
]).toDF(["id", "x", "y", "date"])

并将其写成下面这样:

import tempfile
from pyspark.sql.functions import col, dayofmonth, month, year
outdir = tempfile.mktemp()

dt = col("date").cast("date")
fname = [(year, "year"), (month, "month"), (dayofmonth, "day")]
exprs = [col("*")] + [f(dt).alias(name) for f, name in fname]

(df
    .select(*exprs)
    .write
    .partitionBy(*(name for _, name in fname))
    .format("json")
    .save(outdir))

每个单独的文件中都不会包含分区列:

import os

(sqlContext.read
    .json(os.path.join(outdir, "year=2016/month=2/day=16/"))
    .printSchema())

## root
##  |-- date: string (nullable = true)
##  |-- id: long (nullable = true)
##  |-- x: string (nullable = true)
##  |-- y: double (nullable = true)

数据分区仅存储在目录结构中,不会在序列化文件中重复。只有当您读取完整个或部分目录树时,它才会被附加:

sqlContext.read.json(outdir).printSchema()

## root
##  |-- date: string (nullable = true)
##  |-- id: long (nullable = true)
##  |-- x: string (nullable = true)
##  |-- y: double (nullable = true)
##  |-- year: integer (nullable = true)
##  |-- month: integer (nullable = true)
##  |-- day: integer (nullable = true)

sqlContext.read.json(os.path.join(outdir, "year=2016/month=2/")).printSchema()

## root
##  |-- date: string (nullable = true)
##  |-- id: long (nullable = true)
##  |-- x: string (nullable = true)
##  |-- y: double (nullable = true)
##  |-- day: integer (nullable = true)

1
我是Python的新手。有没有一种方法可以在路径中不使用year=,month=和day=?我理解其中大部分内容。 - deanw
嗨@deanw,你找到“year =”、“month =”等问题的解决方案了吗? - Pablo
很遗憾,不行。 - deanw
我需要进一步分区,按照:年份 - 月份 - 日 - 上午/下午。有什么想法吗? - hipoglucido

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