29

我已经这样定义了一个表:

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'
4

3 回答 3

22

克莫斯利说的是真的。截至目前,您无法选择性地选择某些文件作为 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虚拟列是您最好的选择。

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

这实际上取决于您的用例。如果您从不关心文件是您试图从 Hive 表中排除,那么使用选项 2 可能是一种矫枉过正,您应该修复目录结构并在包含您关心的文件的目录顶部创建一个 Hive 表.

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

于 2012-07-01T00:11:29.413 回答
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';
于 2016-08-15T03:08:43.123 回答
7

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

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

于 2012-06-29T22:26:55.113 回答