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

Hive 在配置单元中创建外部表时,我可以将位置指向目录中的特定文件吗?,hive,external,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 'use

我定义了这样一个表:

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'

不,您当前不能这样做。有一个JIRA票证打开,允许正则表达式为配置单元表()选择包含的文件


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

kmosley说的是真的。到目前为止,您不能有选择地选择某些文件作为配置单元表的一部分。然而,有两种方法可以绕过它

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

选项2: 您可以更改查询以使用名为
INPUT\u FILE\u NAME
的虚拟列

您的查询类似于:

SELECT 
   *
FROM
   my_table
WHERE
   INPUT__FILE__NAME LIKE '%csv';
这种方法的不良影响是,即使您只关心特定的文件,配置单元查询也必须对目录中的整个数据进行搅动。查询不会使用
INPUT\u FILE\u NAME
根据谓词筛选出文件。在映射阶段,它只会使用
INPUT\u FILE\u NAME
过滤掉与谓词不匹配的记录(从而过滤掉特定文件中的所有记录),但映射程序也会在不必要的文件上运行。它将为您提供正确的结果,可能会有一些(可能很小的)性能开销

这种方法的好处是,如果您的表中有多个文件,并且希望能够在几个查询中查询该表(或其分区)中的所有文件,并在其他查询中查询文件的子集,则可以使用同一个配置单元表。您可以使用
INPUT\u FILE\u NAME
virtual列来实现这一点。例如: 如果HDFS目录
/user/hive/warehouse/web\u 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';
假设您的表定义如下所示:

/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';
但是,如果您只关心一天中第一个小时的日志,则可以使用以下查询查询第一个小时的日志:

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\u FILE\u NAME
virtual列筛选出域

在上述两种用例中,为小时或域设置子分区也可以解决问题,而不必使用虚拟列。但是,可能存在一些设计权衡,要求您不要创建子分区。在这种情况下,可以说,使用
INPUT\u FILE\u NAME
virtualcolumn是最好的选择

在两个选项之间选择:

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


如果当前排除的文件与其他文件的格式相同(因此它们都可以是同一个配置单元表的一部分),并且您可以看到自己正在编写一个查询来分析目录中的所有数据,那么请使用选项2

当我有一个类似的问题要解决时,我遇到了这个问题。我能够通过使用自定义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';

谢谢你,马克。我目前正在生产中使用选项1,但我将在我的开发环境中测试选项2,以便将其添加到我的toolbeltOption中#2仍然是一个问题当您有插入覆盖时,它将删除所有文件,即使您只想覆盖其中一个文件。