hive tez insert union all问题
(1)问题描述
在hive中使用tez模式时,发现tez的输出结果在对应表目录中,生成了子目录,造成未配置tez的hive客户端对该表进行读取时,无法获取到数据。
检查表的输出目录,在分区目录下发现了两个子目录:1和2:
/user/hive/test1/20170920000000/1
/user/hive/test1/20170920000000/2

(2)原因

查看对应的sql,发现存在insert union操作,查看往上信息,发现tez对于insert union操作会进行优化,通过并行加快速度,为防止有相同文件输出,所以对并行的输出各自生成成了一个子目录,在子目录中存放结果。如果此时全部hive客户端引擎及相关都设定为tez,则无问题。如果有客户端还在使用mr引擎,则会出现读取不到数据的情况。而在hive中,对于表目录存放信息有如下策略:


在Hive默认设置中,hive只能读取对应表目录下的文件,


1)如果表目录中同时存在目录和文件


则使用hive进行读取时,会报目录非文件的错误


2)表目录中只有目录


hive不会进行深层递归查询,只会读取到对应查询目录,会查询结果为空


3)表目录中只有文件


则可以正常查询




Hive on tez 中对insert union操作进行了优化,会并行输出到对应的表目录,为防止有相同名文件存在,所以为各自输出在表目录下各自设置了一个目录,里边存放执行结果


此种目录,对tez引擎客户端可读。但是对于mr引擎,因为其只会便遍历到对应分区层。发现分区下没有文件后,就返回空


(3)解决思路


发现该现象后,从网上搜索解决方案,http://grokbase.com/t/hive/user/162r80a2g9/anyway-to-avoid-creating-subdirectories-by-insert-with-union


经该文章提示,可以开启mapreduce的递归查询模式:


set mapreduce.input.fileinputformat.input.dir.recursive=true


            在hive中,设置执行查询后,会提示错误,要求将set hive.mapred.supports.subdirectories=true;



同时为了查看tez的此种情况对其他引擎的兼容性,又对sparktThriftServer的sql访问进行了测试:


        对于sparkthriftserver,只需添加set mapreduce.input.fileinputformat.input.dir.recursive=true ,即可访问对应数据


总结一下sparkThriftServer模式与hive的不同


1)在表目录下同时有文件和目录时(非分区目录)


此时sparkThriftServer和hive都会报非文件错误


2)在表目录下均为目录(非分区目录)


此时sparkThriftServer会报非文件错误,hive无错,但是查询为空




(4)解决方案


1)方案一:所有hive端都替换为tez引擎


这不会出现上述问题,但会存在对其他引擎如spqrk,mr,presto等的影响


2)方案二:为hadoop和hive设置可递归读


该方案相对可行,但需要调研对普通mr任务的影响