如何按列名而不是按列顺序从多个 CSV 在 AWS Athena 中创建 table
How to create a table in AWS Athena from multiple CSVs by column names and not by column order
我想从存储在 S3 中的多个 CSV 文件在 AWS Athena 中创建一个 table。
CSV 有一个 header 行和列名。
我的问题是每个 CSV 中的列顺序不同,我想按名称获取列。
当我在 Athena 中尝试正常的 CREATE TABLE 时,我得到了前两列。
CREATE EXTERNAL TABLE `test`(
`id` string,
`name` string)
ROW FORMAT SERDE
'org.apache.hadoop.hive.serde2.OpenCSVSerde'
WITH SERDEPROPERTIES (
'escapeChar'='\',
'quoteChar'='\"',
'separatorChar'=',')
STORED AS INPUTFORMAT
'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
's3://...'
TBLPROPERTIES (
'has_encrypted_data'='false')
这里有一个例子:
csv 1:
+----+-------+-------+---------+
| id | name | price | comment |
+----+-------+-------+---------+
| 1 | shirt | 123 | abc |
| 2 | shoes | 222 | ddd |
+----+-------+-------+---------+
csv 2:
+----+------+-------+-------+---------+
| id | size | price | color | name |
+----+------+-------+-------+---------+
| 5 | L | 100 | red | shirt |
| 6 | S | 55 | white | t-shirt |
+----+------+-------+-------+---------+
我要的table:
+----+---------+
| id | name |
+----+---------+
| 1 | shirt |
| 2 | shoes |
| 5 | shirt |
| 6 | t-shirt |
+----+---------+
我得到的table:
+----+-------+
| id | name |
+----+-------+
| 1 | shirt |
| 2 | shoes |
| 5 | L |
| 6 | S |
+----+-------+
谢谢
我会为不同的 CSV 使用两个不同的表(您需要将 CSV 存储在不同的文件夹中)。
最终,为了获得两个 CSV 的 id、name 结构,我将使用 VIEW 联合来自不同表的必要列。
将文件放在不同的文件夹中,并使用 Glue Crawler 创建数据存储。
使用胶水爬虫。这会很有帮助。
IMO,Glue Crawler 没有设置来获取列名并使用它们来定义 table 的架构,这有点疯狂。我们 运行 解决了这个问题(S3 中同一文件夹中的架构更改),下面是我们解决它的方法。
注意 - 如果您可以将模式(header 顺序)映射到特定的 S3 路径,则以下解决方案有效。
源数据
我们有四个文件。 a.csv
和 b.csv
共享相同的架构,而 c.csv
和 d.csv
具有不同的架构。
$ cat a.csv
a,b
1,2
3,4
$ cat b.csv
a,b
5,6
3,4
$ cat c.csv
a,b,c
1,2,3
4,5,6
$ cat d.csv
a,c,d,x
6,7,8,9
1,2,3,4
这些保存在S3中:
$ aws s3 ls s3://example-s3-bucket/
2019-01-04 09:47:42 12 a.csv
2019-01-04 09:49:49 12 b.csv
2019-01-04 09:49:53 18 c.csv
2019-01-04 09:49:56 24 d.csv
为每个模式创建一个 table
为每个模式创建一个 table,只需传入相同的 S3 位置。
请注意,为简洁起见,我省略了定界符和字段分隔符定义。
create external table athena_testing_ab (
a int,
b int
)
LOCATION 's3://example-s3-bucket/'
;
create external table athena_testing_c (
a int,
b int,
c int
)
LOCATION 's3://example-s3-bucket/'
;
create external table athena_testing_d (
a int,
c int,
d int,
x int
)
LOCATION 's3://example-s3-bucket/'
;
使用UNION
s
查询所有tables
我们现在一起查询这 3 个 table 和 UNION
,为每个 table.
在适当的 S3 路径上过滤
您可能希望使用正则表达式或子字符串解析来更优雅地过滤 $PATH
,尤其是当您的存储桶中有成百上千个文件时。
select
a,
b,
null as c,
null as d,
null as x
from
athena_testing_ab
where "$PATH" in ('s3://example-s3-bucket/a.csv', 's3://example-s3-bucket/b.csv')
union all
select
a,
b,
c,
null as d,
null as x
from
athena_testing_c
where "$PATH" in ('s3://example-s3-bucket/c.csv')
union all
select
a,
null as b,
c,
d,
x
from
athena_testing_d
where "$PATH" in ('s3://example-s3-bucket/d.csv')
我想从存储在 S3 中的多个 CSV 文件在 AWS Athena 中创建一个 table。
CSV 有一个 header 行和列名。 我的问题是每个 CSV 中的列顺序不同,我想按名称获取列。
当我在 Athena 中尝试正常的 CREATE TABLE 时,我得到了前两列。
CREATE EXTERNAL TABLE `test`(
`id` string,
`name` string)
ROW FORMAT SERDE
'org.apache.hadoop.hive.serde2.OpenCSVSerde'
WITH SERDEPROPERTIES (
'escapeChar'='\',
'quoteChar'='\"',
'separatorChar'=',')
STORED AS INPUTFORMAT
'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
's3://...'
TBLPROPERTIES (
'has_encrypted_data'='false')
这里有一个例子:
csv 1:
+----+-------+-------+---------+
| id | name | price | comment |
+----+-------+-------+---------+
| 1 | shirt | 123 | abc |
| 2 | shoes | 222 | ddd |
+----+-------+-------+---------+
csv 2:
+----+------+-------+-------+---------+
| id | size | price | color | name |
+----+------+-------+-------+---------+
| 5 | L | 100 | red | shirt |
| 6 | S | 55 | white | t-shirt |
+----+------+-------+-------+---------+
我要的table:
+----+---------+
| id | name |
+----+---------+
| 1 | shirt |
| 2 | shoes |
| 5 | shirt |
| 6 | t-shirt |
+----+---------+
我得到的table:
+----+-------+
| id | name |
+----+-------+
| 1 | shirt |
| 2 | shoes |
| 5 | L |
| 6 | S |
+----+-------+
谢谢
我会为不同的 CSV 使用两个不同的表(您需要将 CSV 存储在不同的文件夹中)。
最终,为了获得两个 CSV 的 id、name 结构,我将使用 VIEW 联合来自不同表的必要列。
将文件放在不同的文件夹中,并使用 Glue Crawler 创建数据存储。
使用胶水爬虫。这会很有帮助。
IMO,Glue Crawler 没有设置来获取列名并使用它们来定义 table 的架构,这有点疯狂。我们 运行 解决了这个问题(S3 中同一文件夹中的架构更改),下面是我们解决它的方法。
注意 - 如果您可以将模式(header 顺序)映射到特定的 S3 路径,则以下解决方案有效。
源数据
我们有四个文件。 a.csv
和 b.csv
共享相同的架构,而 c.csv
和 d.csv
具有不同的架构。
$ cat a.csv
a,b
1,2
3,4
$ cat b.csv
a,b
5,6
3,4
$ cat c.csv
a,b,c
1,2,3
4,5,6
$ cat d.csv
a,c,d,x
6,7,8,9
1,2,3,4
这些保存在S3中:
$ aws s3 ls s3://example-s3-bucket/
2019-01-04 09:47:42 12 a.csv
2019-01-04 09:49:49 12 b.csv
2019-01-04 09:49:53 18 c.csv
2019-01-04 09:49:56 24 d.csv
为每个模式创建一个 table
为每个模式创建一个 table,只需传入相同的 S3 位置。
请注意,为简洁起见,我省略了定界符和字段分隔符定义。
create external table athena_testing_ab (
a int,
b int
)
LOCATION 's3://example-s3-bucket/'
;
create external table athena_testing_c (
a int,
b int,
c int
)
LOCATION 's3://example-s3-bucket/'
;
create external table athena_testing_d (
a int,
c int,
d int,
x int
)
LOCATION 's3://example-s3-bucket/'
;
使用UNION
s
查询所有tables
我们现在一起查询这 3 个 table 和 UNION
,为每个 table.
您可能希望使用正则表达式或子字符串解析来更优雅地过滤 $PATH
,尤其是当您的存储桶中有成百上千个文件时。
select
a,
b,
null as c,
null as d,
null as x
from
athena_testing_ab
where "$PATH" in ('s3://example-s3-bucket/a.csv', 's3://example-s3-bucket/b.csv')
union all
select
a,
b,
c,
null as d,
null as x
from
athena_testing_c
where "$PATH" in ('s3://example-s3-bucket/c.csv')
union all
select
a,
null as b,
c,
d,
x
from
athena_testing_d
where "$PATH" in ('s3://example-s3-bucket/d.csv')