如何将带有 NULL 值的引用 CSV 读入 Amazon Athena

Posted

技术标签:

【中文标题】如何将带有 NULL 值的引用 CSV 读入 Amazon Athena【英文标题】:How to read quoted CSV with NULL values into Amazon Athena 【发布时间】:2018-11-16 08:23:39 【问题描述】:

我正在尝试使用存储在 S3 上的引用 CSV 文件在 Athena 中创建一个外部表。问题是,我的 CSV 在应该被读取为 INT 的列中包含缺失值。简单例子:

CSV:

id,height,age,name
1,,26,"Adam"
2,178,28,"Robert"

创建表定义:

CREATE EXTERNAL TABLE schema.test_null_unquoted (
  id INT,
  height INT,
  age INT,
  name STRING
)
ROW FORMAT 
SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
WITH SERDEPROPERTIES (
'separatorChar' = ",",
'quoteChar' = '"',
'skip.header.line.count' = '1'
)
STORED AS TEXTFILE
LOCATION 's3://mybucket/test_null/unquoted/'

CREATE TABLE 语句运行良好,但当我尝试查询表时,我得到了HIVE_BAD_DATA: Error parsing field value ''

我尝试让 CSV 看起来像这样(引用空字符串):

"id","height","age","name"
1,"",26,"Adam"
2,178,28,"Robert"

但它不起作用。

尝试在 SERDEPROPERTIES 中指定 'serialization.null.format' = '' - 不起作用。

尝试通过 TBLPROPERTIES ('serialization.null.format'='') 指定相同的内容 - 仍然没有。

当您将所有列指定为 STRING 时,它可以工作,但这不是我需要的。

因此,问题是,是否有任何方式可以通过正确的列规范向 Athena 读取引用的 CSV(引用很重要,因为我的真实数据要复杂得多)?

【问题讨论】:

【参考方案1】:

处理这些数据的快速而肮脏的方式:

CSV:

id,height,age,name
1,,26,"Adam"
2,178,28,"Robert"
3,123,34,"Bill, Comma"
4,183,38,"Alex"

DDL:

CREATE EXTERNAL TABLE ***.test_null_unquoted (
  id INT,
  height INT,
  age INT,
  name STRING
)
ROW FORMAT DELIMITED
 FIELDS TERMINATED BY ','
 LINES TERMINATED BY '\n' -- Or use Windows Line Endings
LOCATION 's3://XXXXXXXXXXXXX/'
TBLPROPERTIES ('skip.header.line.count'='1')
;

问题在于它没有处理最后一个字段中的引号字符。根据AWS 提供的文档,这对于从Hive 给出以下内容的 LazySimpleSerDe 来说是有意义的。

我怀疑解决方案是使用以下 SerDe org.apache.hadoop.hive.serde2.RegexSerDe

我稍后会处理正则表达式。

编辑:

如许的正则表达式:

CREATE EXTERNAL TABLE ***.test_null_unquoted (
  id INT,
  height INT,
  age INT,
  name STRING
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
"input.regex" = "(.*),(.*),(.*),\"(.*)\""
)
LOCATION 's3://XXXXXXXXXXXXXXX/'
TBLPROPERTIES ('skip.header.line.count'='1') -- Does not appear to work
;

注意:RegexSerDe 似乎无法与 TBLPROPERTIES ('skip.header.line.count'='1') 一起正常工作。这可能是由于 Athena 或 SerDe 使用的Hive version。在您的情况下,您可能只排除 ID IS NULL 所在的行。

进一步阅读:

*** - remove surrounding quotes from fields while loading data into hive

Athena - OpenCSVSerDe for Processing CSV

【讨论】:

有谁知道 Athena 使用的是哪个版本的 Hive? 确实 RegexSerDe 按预期工作,谢谢!我只是想知道,由于 Athena 只是现有数据之上的一个抽象层,而且我想每次读取文件时都会对其进行解析,因此使用 RegexSerDe 和 OpenCSVSerDe 之间是否存在性能差异? 这是一个非常有趣的问题。我一直想设置一些 Athena 基准测试,老实说,我从未考虑过不同序列化器/反序列化器之间的差异。 我没有运行任何严肃的基准测试,但从我测试的结果来看,与 OpenCSV 相比,正则表达式 serde 的性能极差。我有一张有 5kk 行和 20 列各种类型的表。如果我在使用正则表达式创建的表上运行一个简单的 count(*),则查询运行时间超过 20 分钟。对于 CSV,只需几秒钟。但谁知道呢,我可能做错了什么。干杯。 这种正则表达式方法是否适用于任意数量的列?你如何解释正则表达式模式?【参考方案2】:

不幸的是,在 Athena 中无法同时支持引用字段支持空值。您必须选择或。

您可以使用 OpenCSVSerDe 并将所有列键入为字符串,这将为您提供对带引号的字段的支持,并为空字段提供空字符串。在查询时使用TRY_CASTCASE/WHEN 转换值。

或者您可以使用LazySimpleSerDe 并在查询时去掉引号。

我会选择 OpenCSVSerDe,因为您始终可以创建一个包含所有类型转换的视图并将该视图用于您的常规查询。

您可以在此处阅读有关在 Athena 中使用 CSV 的所有细节:The Athena Guide: Working with CSV

【讨论】:

【参考方案3】:

这对我有用。使用 OpenCSVSerDe 并将所有列转换为字符串。阅读更多:https://aws.amazon.com/premiumsupport/knowledge-center/athena-hive-bad-data-error-csv/

【讨论】:

以上是关于如何将带有 NULL 值的引用 CSV 读入 Amazon Athena的主要内容,如果未能解决你的问题,请参考以下文章

将包含一些空值的CSV文件读入VBA数组

python用两个键将带有行和列标题的csv文件读入字典

VB.NET:将 CSV 文件读入二维数组

python-import带有十进制值的csv

将带有值的新键添加到嵌套对象数组中

当值有太多有效数字时,read.csv 将数字转换为字符/因子