在hive中创建外部表时,我可以将位置指向目录中的特定文件吗?

时间:2012-06-29 21:28:03

标签: hive external

我已经定义了一个表格:

create external table PageViews (Userid string, Page_View string)
partitioned by (ds string)
row format as delimited fields terminated by ','
stored as textfile location '/user/data';

我不希望/ user / data目录中的所有文件都用作表的一部分。我有可能做到以下几点吗?

location 'user/data/*.csv'

3 个答案:

答案 0 :(得分:19)

kmosley说的是真的。截至目前,您无法有选择地选择某些文件作为Hive表的一部分。但是,有两种方法可以解决它。

选项1: 您可以将所有csv文件移动到另一个HDFS目录中,并在其上创建一个Hive表。如果它对您更有效,您可以在当前目录中创建一个包含所有CSV文件的子目录(例如,csv)。然后,您可以在此子目录的顶部创建Hive表。请记住,在父目录之上创建的任何Hive表都不包含子目录中的数据。

选项2: 您可以更改查询以使用名为INPUT__FILE__NAME的虚拟列。

您的查询类似于:

SELECT 
   *
FROM
   my_table
WHERE
   INPUT__FILE__NAME LIKE '%csv';

这种方法的不良后果是Hive查询将不得不浏览目录中存在的整个数据,即使您只关心特定文件。查询不会使用INPUT__FILE__NAME根据谓词过滤掉文件。它只会在映射阶段过滤掉不使用INPUT__FILE__NAME的谓词匹配的记录(从而过滤掉特定文件中的所有记录),但映射器也会在不必要的文件上运行。它会为您提供正确的结果,可能会有一些(可能是次要的)性能开销。

这种方法的好处是,如果表中有多个文件,并且希望能够在几个查询和子集中查询该表(或其分区)中的所有文件,则可以使用相同的Hive表。其他查询中的文件。您可以使用INPUT__FILE__NAME虚拟列来实现此目的。举个例子: 如果HDFS目录/user/hive/warehouse/web_logs/中的分区如下所示:

/user/hive/warehouse/web_logs/dt=2012-06-30/
   /user/hive/warehouse/web_logs/dt=2012-06-30/00.log
   /user/hive/warehouse/web_logs/dt=2012-06-30/01.log
   .
   .
   .
   /user/hive/warehouse/web_logs/dt=2012-06-30/23.log

让我们说你的表定义如下:

CREATE EXTERNAL TABLE IF NOT EXISTS web_logs_table (col1 STRING)
PARTITIONED BY (dt STRING)
LOCATION '/user/hive/warehouse/web_logs';

添加适当的分区后,您可以使用以下查询查询分区中的所有日志:

SELECT
   *
FROM
   web_logs_table w
WHERE
   dt='2012-06-30';

但是,如果您只关注当天第一个小时的日志,则可以使用以下查询查询第一个小时的日志:

SELECT
   *
FROM
   web_logs_table w
WHERE 
   dt ='2012-06-30'
   AND INPUT__FILE__NAME='00.log';

另一个类似的用例可能是包含来自不同域的Web日志的目录,并且各种查询需要分析不同域集上的日志。查询可以使用INPUT__FILE__NAME虚拟列过滤掉域。

在上述两种用例中,拥有小时或域的子分区也可以解决问题,而无需使用虚拟列。但是,可能存在一些需要您不创建子分区的设计权衡。在这种情况下,可以说,使用INPUT__FILE__NAME虚拟列是最好的选择。

在两个选项之间做出决定:

这实际上取决于您的使用案例。如果您从不关心文件是否正在尝试从Hive表中排除,使用选项2可能是一种过度杀伤,您应该修复目录结构并在包含您关心的文件的目录之上创建一个Hive表

如果您当前排除的文件遵循与其他文件相同的格式(因此它们都可以是同一个Hive表的一部分),您可以看到自己编写的查询将分析目录中的所有数据,然后选择2。

答案 1 :(得分:11)

当遇到类似问题时,我遇到了这个问题。我能够通过使用自定义SerDe来解决它。然后我添加了SerDe属性,它引导了RegEx应用于任何特定表的文件名模式。

如果您只处理标准CSV文件,自定义SerDe可能看起来有点过分,我有一个更复杂的文件格式需要处理。如果你不回避编写Java,这仍然是一个非常可行的解决方案。当您无法重新构建存储位置中的数据并且在不成比例的大文件集中查找非常特定的文件模式时,它尤其有用。

> CREATE EXTERNAL TABLE PageViews (Userid string, Page_View string)  
> ROW FORMAT SERDE 'com.something.MySimpleSerDe' 
> WITH SERDEPROPERTIES ( "input.regex" = "*.csv")
> LOCATION '/user/data';

答案 2 :(得分:7)

不,你现在不能这样做。打开JIRA票证,允许正则表达式为Hive表(https://issues.apache.org/jira/browse/HIVE-951)选择包含的文件。

现在最好的办法是在不同的目录上创建一个表,然后复制您要查询的文件。