我的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
,但没有运气。
答案 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)
“来自's3:// MY_s3 / stage / my_s3_file / load_dt'的复制表”应该有效。 COPY命令将S3路径的最后一部分作为前缀。
答案 3 :(得分:0)
我想我找到了答案。
我无法加载配置单元分区,因为Hive在Hive元数据中存储了该分区值,这就是S3文件中没有分区列的原因。
现在我通过Hive将一个新列添加到S3作为Load_Dt_New,因此S3文件将具有我的Redshift COPY命令所需的列。