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