2013-04-01 53 views
37

我使用的是Cloudera的Hive版本,并尝试通过包含第一列中的列名称的csv文件创建外部表。这里是我用来做到这一点的代码。Hive外部表跳过第一行

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" 

谁能帮助我如何跳过第一行还是需要增加一个中间步骤?

+0

我刚开始玩蜂窝自己,从我可以告诉,SERDE上唯一一个行通过行的基础上工作,所以它可能不是没有一些中间是可能的。如果我能想到什么,我会在这里发布。我也对解决方案感兴趣。 – nolanpro

回答

49

数据中的标题行在Hive中是永久的头痛。在修改Hive源代码之前,我相信如果没有中间步骤,就无法脱身。 (编辑:这不再是真实的,请参阅下面的更新)

不幸的是,这回答你的问题。我会针对完整性的中间步骤提出一些想法。

如果您愿意在触及表的每个查询中筛选出标题行,那么您可以在数据加载中不需要额外的步骤。不幸的是,这在其他地方增加了一个额外的设置。当标题行违反了你的模式时,你将不得不变得聪明/杂乱。如果你采用这种方法,你可以考虑编写一个自定义的SerDe,使得这一行更容易过滤。不幸的是,SerDe无法完全删除该行(或者可能形成可能的解决方案),他们必须返回类似null。我从来没有见过这种方法在实践中被用来处理标题行,因为它使阅读变得很痛苦,并且阅读往往比写作更普遍。如果您正在处理一个表或者如果标题行只是许多格式不正确的行中的一行,它可能有一席之地。

您可以通过删除数据加载中的第一行来进行一次过滤。 INSERT声明中的WHERE子句可以做到这一点。你可以使用像sed这样的工具来摆脱它。我已经看到两种方法。在你采用哪种方法之间存在权衡,也不是处理标题行的真正方法。不幸的是,这两种方法都需要时间并需要临时重复数据。如果您确实需要另一个应用程序的标题行,则重复将是永久性的。

更新:

从蜂巢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"); 
+11

看起来您现在可以使用“SET skip.header.line.count = 1;”跳过标题行。欲了解更多信息,请参阅[https://issues.apache.org/jira/browse/HIVE-5795](https://issues.apache.org/jira/browse/HIVE-5795)上的补丁说明。 –

+0

感谢您的更新!目前,我并未与Hive合作,以便及时了解像这样的更改。我已经发布了一个社区wiki,所以如果你已经测试了SET skip.header.line.count,我将不胜感激,如果你能解决我的问题(尽管在0.13.0版本以下的版本中有一段时间的解决办法) 。 –

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文件将被修改。我希望它有帮助。 GL!

+0

正在使用CSVSerDe消除CSV文件中的双引号。 –

1

我也为此而苦苦挣扎,发现没有办法告诉配置单元跳过第一行,就像存在在Greenplum。所以最后我不得不从文件中删除它。 例如“cat File.csv | grep -v RecordId> File_no_header。CSV”

1
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'); 
0

skip.header.line.count的作品,但如果你有一些外部工具访问访问这个表,它仍然会看到,没有跳过这些行

8

当你从你的答案实际数据大牛,这是使用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') 

有了这个,你有过的分隔符,引号字符总量控制,转义字符,空值处理和报头处理

herehere

+0

来这里寻找这个答案,因为我使用AWS Athena,这需要我使用OpenCSVSerde。我有一段时间没有碰过HIVE,但由于SerDe来自HIVE栈,所以很高兴看到关于OpenCSVSerde的次要答案。谢谢@Nirmal –

+1

一个重要的注意事项 - 我在SerDe文档中发现了这一点。 *限制* 此SerDe将所有列都视为String类型。即使使用此SerDe创建包含非字符串列类型的 表,DESCRIBE TABLE输出也会显示字符串列类型。类型信息是从SerDe中检索的 。要将列转换为 表中的所需类型,可以在表上创建一个视图,将CAST转换为 所需的类型。 –

1

只需追加属性在您的查询和第一个标题或行int记录将不会加载或将被跳过。

试试这个

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

不是说这个解决方案也包含在顶级答案中:-) – Carpetsmoker