1.问题背景介绍
项目中抛弃了通过sqoop方式将数据从关系型数据库导入到HIVE的方式。而是采用一种JdbcHandler的方式,直接将关系型数据库中的数据映射到hive的方式,算是对hive分析关系型数据库中数据的一种优化方案,hive官网也很早就提出了要实现这一功能,不过还没有发布:
/>
https://issues.apache.org/jira/secure/attachment/12474978/JDBCStorageHandler+Design+Doc.pdf
我们的JdbcHandler在映射oracle数据类型和hive数据类型时,参照sqoop的数据类型映射关系,将oracle char/varchar/varchar2类型映射为了hive string类型,但是实际测试中却发现,
在执行“select * from tablename”时可以正确显示oracle表中的所有数据,而给select语句添加where条件(JdbcHandler支持条件下推)后,varchar/varchar2类型都能够通过jdbchandler正确地查出来,而char类型却怎么都显示不出来,无论它的值是数字、字母还是汉字。。。
2.问题分析
通过一步一步调试hive源码,发现,之所以“
select * from tablename”能够正确显示,是因为并没有通过hive的FilterOperator去进行二次过滤,而是直接从数据库中取出来显示了一下。而添加了where条件则不同了,虽然从oracle中查出了实际的数据,但是在经过JdbcHandler的反序列化后,hive会在二次过滤时将where条件中的值和表中该字段的数据进行了比较(hive识别的数据行类型:bytesrefarraywritable),举个例子:select * from orchid where name=“helianthus”(这里orchid为关于oracle的hive外部表,name在oracle表中对应为char类型),hive在实际处理时,将where条件中的数值转化的字节码值和实际该值所处的字段中的值所转化的数据类型不同(该字段的类型会转为LazyStringObjectInspector,而where条件中的数据值类型会转为WritableConstantStringObjectInspector),字节码值不相同,因此,就被在二次过滤(FilterOperator)时被过滤掉了,也就是说没有符合where条件的数据。这是一层原因,还有一层原因,那就是oracle的char类型,这真是个坑啊!char类型是长度固定的
,如果存储的数据没有达到指定长度,自动补足空格。这也就从根本上解释了为什么将where条件转化为hive中的where字节码时不能够和该字段的值匹配上:
(1)where条件中的字段值是实际该数据所占的字节码
(2)select *。。。时该字段的值是包含那些自动补足的空格的
那么……查不出是必然的。
3.解决办法
在从oracle中查出char类型数据以后,在JdbcHandler的反序列化阶段将其实际数据右边的空格全部去除掉就能够和where条件匹配上了。测试通过。
ps:这虽然最后发现是个小问题,但是希望给那些也遇到类似问题的人一个小小的帮助,避开这个坑。