从S3加载Redshift(带分区)

时间:2016-04-15 21:28:11

标签: amazon-web-services amazon-s3 hive amazon-redshift

我的S3文件(s3://MY_s3/stage/my_s3_file)在load_dt上有一个分区:

S3结构:

-MY_S3
 --stage
  ---my_s3_file
    ----load_dt=2016-02-01
         ----000024
    ----load_dt=2016-02-02
         ----000036

实际文件位于load_dt分区之下,如000024& 000036。

如果我没有在Redshift表中保存load_dt,则COPY命令正常工作,但是当我在Redshift表中添加load_dt时,COPY命令因数据错误而失败,因为输入布局&目标布局不匹配(目标上有额外的load_dt)。

创建S3文件的hive表在末尾显示分区的load_dt。

如何使此COPY命令与load_dt在目标Redshift上一起使用?

我甚至尝试将S3位置更改为s3://MY_s3/stage/my_s3_file/load_dt,但没有运气。

4 个答案:

答案 0 :(得分:3)

当Hive(在Apache Hadoop下运行)创建分区EXTERNAL TABLE时,它会按目录分隔文件。例如,load_dt=2016-02-01存储在名为load_dt=2016-02-01的目录中的所有行。

目录中的文件不存储分区列(load_dt)的值。相反,分区列的值存储为目录名称的一部分。因此,重命名目录实际上会更改该列中所有行的值。

是的,这有点奇怪,但这就是Hive存储数据的方式!

Amazon Redshift可以从Amazon S3导入CSV文件(包括压缩的CSV文件)。它甚至可以从多个子目录导入文件,因为它只查看要加载的文件的路径前缀。但是,它不了解Hive存储分区数据的方式,因此它不会从目录名称加载分区列

一些选项:

  • 在输出数据中添加包含相同值的另一列(就像您现在所做的那样)
  • 在基于某些计算(例如,从日期字段)设置列值的COPY之后运行命令
  • 一次加载一个目录(复杂实现而不是那么高效)

答案 1 :(得分:1)

Redshift'Copy'命令将在表架构和镶木地板列之间的不匹配列下显示错误。 因此,当您使用范围(每日)分区时,您可以使用以下脚本。

export PGUSER=sample
export PGPASSWORD=sample
export PGHOST=xxxx.xxxx.redshift.amazonaws.com
export PGPORT=5439
export PGDATABASE=xxxx

start_date=`date -d '2018-01-01' +%s`
base_s3='s3://bucket_and_table_root_path/range_column_name='


for day in {0..364}
do
  base_ymd=`date -d @$((${start_date} + 3600 * 24 * ${day})) +'%Y-%m-%d'`
  base_ymd_lower=`echo ${base_ymd} | sed '1,$s/-/_/g'`
  echo ${base_s3}${base_ymd}
  echo 'start-time' `date`
  psql <<EOF
DROP TABLE loading_table_${base_ymd_lower}_temp;
CREATE TABLE loading_table_${base_ymd_lower}_temp (
    col_a VARCHAR(xxxx) ENCODE LZO,
    ...
)
DISTSTYLE even
;
COPY loading_table_${base_ymd_lower}_temp
FROM '${base_s3}${base_ymd}'
iam_role 'arn:aws:iam::xxxxxxxxxxx:role/xxxxxxxxxx'
format as parquet
;
EOF

done

接下来,您可以在Redshift中将CTAS与UNION关键字一起使用。

答案 2 :(得分:0)

如果您可以将文件名更改为“load_dt_20160201”而不是“load_dt = 2016-02-01”,那么

“来自's3:// MY_s3 / stage / my_s3_file / load_dt'的复制表”应该有效。 COPY命令将S3路径的最后一部分作为前缀。

答案 3 :(得分:0)

我想我找到了答案。

我无法加载配置单元分区,因为Hive在Hive元数据中存储了该分区值,这就是S3文件中没有分区列的原因。

现在我通过Hive将一个新列添加到S3作为Load_Dt_New,因此S3文件将具有我的Redshift COPY命令所需的列。