如何在Hive外部表中跳过CSV头?

62

我正在使用Cloudera的Hive版本,并尝试创建一个外部表,其数据是CSV文件,第一列包含列名。以下是我用来执行此操作的代码。

CREATE EXTERNAL TABLE Test ( 
  RecordId int, 
  FirstName string, 
  LastName string 
) 
ROW FORMAT serde 'com.bizo.hive.serde.csv.CSVSerde' 
WITH SerDeProperties (  
  "separatorChar" = ","
) 
STORED AS TEXTFILE 
LOCATION '/user/File.csv'

样本数据

RecordId,FirstName,LastName
1,"John","Doe"
2,"Jane","Doe"

有人可以帮我解决如何跳过第一行的问题吗?还是说我需要添加一个中间步骤?


我刚开始尝试使用Hive,从我的了解来看,SerDe仅逐行处理,因此可能需要一些中间步骤才能实现。如果我想到了什么,我会在这里发布。我也对解决方案很感兴趣。 - nolanpro
8个回答

100
截至Hive v0.13.0版本,您可以使用skip.header.line.count表属性:
create external table testtable (name string, message string)
row format delimited 
fields terminated by '\t' 
lines terminated by '\n' 
location '/testtable'
TBLPROPERTIES ("skip.header.line.count"="1");

对于现有的表,请使用 ALTER TABLE

ALTER TABLE tablename
SET TBLPROPERTIES ("skip.header.line.count"="1");

请注意,虽然它可以工作,但它也有自己的问题。当生成的输出文件超过一个时,即reducers大于1时,它会跳过每个文件的第一条记录,这可能并不是期望的行为。

17
看起来现在可以使用"SET skip.header.line.count = 1;"跳过标题行。更多信息请参考https://issues.apache.org/jira/browse/HIVE-5795的修补说明。 - Anthony Compton

26

虽然您已经得到了Daniel的答案,但是这里有一些可以使用OpenCSVSerde进行的自定义:

CREATE EXTERNAL TABLE `mydb`.`mytable`(
    `product_name` string,
    `brand_id` string,
    `brand` string,
    `color` string,
    `description` string,
    `sale_price` string)
PARTITIONED BY (
    `seller_id` string)
ROW FORMAT SERDE
    'org.apache.hadoop.hive.serde2.OpenCSVSerde'
WITH SERDEPROPERTIES (
    'separatorChar' = '\t',
    'quoteChar' = '"',
    'escapeChar' = '\\')
STORED AS INPUTFORMAT
    'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
    'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
    'hdfs://namenode.com:port/data/mydb/mytable'
TBLPROPERTIES (
    'serialization.null.format' = '',
    'skip.header.line.count' = '1')

通过这个,您可以完全控制分隔符、引号字符、转义字符、空值处理和标题处理。
请看这里这里

1
因为我正在使用AWS Athena,需要使用OpenCSVSerde,所以我来到这里寻找答案。我已经有一段时间没有接触HIVE了,但由于这个SerDe来自HIVE堆栈,看到关于OpenCSVSerde的这个次要答案真是太好了。谢谢@Nirmal。 - Ashley Raiteri
1
一个重要的注意事项 - 我在 SerDe 文档中发现了这个。限制 这个 SerDe 将所有列都视为 String 类型。即使您使用此 SerDe 创建了一个具有非字符串列类型的表,DESCRIBE TABLE 输出也会显示字符串列类型。类型信息是从 SerDe 中检索的。要将表中的列转换为所需的类型,可以创建一个视图,对表进行 CAST 到所需的类型。 - Ashley Raiteri

11

只需在您的查询中添加以下属性,记录中的第一行标题或行将不会加载或跳过。

试试这个

tblproperties ("skip.header.line.count"="1");

5

skip.header.line.count将跳过标题行。

然而,如果您正在使用一些外部工具访问表格,它仍将看到实际数据而不是跳过这些行。


2
create external table table_name( 
Year int, 
Month int,
column_name data_type ) 
row format delimited fields terminated by ',' 
location '/user/user_name/example_data' TBLPROPERTIES('serialization.null.format'='', 'skip.header.line.count'='1');

1
我不太确定它是否适用于 ROW FORMAT serde 'com.bizo.hive.serde.csv.CSVSerde',但我猜它应该类似于 ROW FORMAT DELIMITED FIELDS TERMINATED BY ','。 在您的情况下,第一行将被视为普通行。但是第一个字段无法转换为 INT,因此对于第一行的所有字段都将设置为 NULL。您只需要一个中间步骤来解决它:
INSERT OVERWRITE TABLE Test
SELECT * from Test WHERE RecordId IS NOT NULL

唯一的缺点是您的原始csv文件将被修改。希望对您有所帮助。祝好运!


CSVSerDe被用于消除CSV文件中的双引号。 - Rick Gittins

1

仅适用于已经创建了带有标题的表格的人。这是相同的更改命令。如果您已经拥有该表并希望忽略第一行而不必删除和重新创建,则此选项很有用。它还有助于使人们熟悉使用TBLPROPERTIES的ALTER选项。

ALTER TABLE tablename SET TBLPROPERTIES ("skip.header.line.count"="1");

0

我也曾经遇到过这个问题,但是没有找到方法告诉Hive跳过第一行,就像在Greenplum中一样。所以最终我只能从文件中删除它。 例如:"cat File.csv | grep -v RecordId > File_no_header.csv"


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