设置递归参数后仍无法从多级目录加载数据到Hive表
解决Hive递归加载子目录数据失败的问题
你遇到的核心问题是:Hive的LOAD DATA命令本身不支持递归遍历子目录,你设置的mapred.input.dir.recursive=true和hive.mapred.supports.subdirectories=true这两个参数,是给Hive的查询任务(比如SELECT)用的,对LOAD DATA命令完全不起作用——LOAD DATA的逻辑是直接将指定路径下的文件移动/复制到表的存储目录,只要发现路径下存在子目录就会抛出你看到的错误。
下面给你三个可靠的解决方案,按推荐程度排序:
方案1:用INSERT OVERWRITE + 递归查询加载数据(最推荐)
这个方法利用Hive查询的递归特性来读取所有子目录的文件,再插入到目标表中,步骤如下:
- 先创建一个临时外部表,指向你的原始数据目录(让Hive能递归读取所有子目录的CSV):
CREATE EXTERNAL TABLE raw_tmptbl ( id int, name string ) ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde' WITH SERDEPROPERTIES ( 'escapeChar'='\\', 'quoteChar'='"', 'separatorChar'=',' ) LOCATION '/app/tmptbl/';
- 设置递归读取的配置参数(覆盖会话级别的设置):
SET mapred.input.dir.recursive=true; SET hive.mapred.supports.subdirectories=true; SET hive.input.dir.recursive=true; -- 部分Hive版本需要这个额外参数
- 将递归读取到的数据插入到你的目标表中:
INSERT OVERWRITE TABLE default.tmptbl SELECT id, name FROM raw_tmptbl;
完成后,你可以删掉这个临时外部表(不会影响原始数据):
DROP TABLE raw_tmptbl;
方案2:提前合并所有子目录的文件到根目录
如果你的目录结构比较简单,也可以先用HDFS命令把所有子目录里的CSV文件移动到根目录,再用LOAD DATA:
- 移动所有子目录的CSV到根目录:
hdfs dfs -mv /app/tmptbl/*/*.csv /app/tmptbl/
- 删除空的子目录(避免后续
LOAD DATA再次报错):
hdfs dfs -rmdir /app/tmptbl/DIR1 /app/tmptbl/DIR2
- 执行
LOAD DATA命令:
LOAD DATA INPATH '/app/tmptbl/' INTO TABLE default.tmptbl;
方案3:使用通配符匹配子目录文件(版本依赖)
部分较新的Hive版本支持用通配符来指定子目录的文件,比如:
LOAD DATA INPATH '/app/tmptbl/*/*.csv' INTO TABLE default.tmptbl;
但这个方法的局限性很大:如果子目录层级更深,通配符会变得很复杂;而且不是所有Hive版本都支持这个特性,稳定性不如前两个方案。
内容的提问来源于stack exchange,提问作者Sivaprasanna Sethuraman
相关产品推荐
相关产品推荐

