最近收到一份需求:
有两张表 one 和 two . 两张表都有一个字段name,现在要求从one 导入到two 中。
要求是
name字段有可能为空 ,在HIVE中默认是用"\N"来表示空,也就是ONE表在HDFS上文件包含"\N"。ONE表类似的HDFS文件系统如下
ID NAME
2, licl\r
导入后TWO表的HDFS文件系统应该如下
1, NULL
2, licl\n
原始语句:insert overwrite table TWO select id,name from ONE;
我们的思路很简单,首先处理NULL的情况,你可以使用serialization.null.format 属性来修改TWO的表结构属性。但是当时我受到环境制约不允许这样做。接下来用coalesce函数处理NAME,coalesce(A,B,C)代表返回第一个不是NULL的值
于是函数变为了insert overwrite table TWO select id,coalesce(name,'NULL') from ONE;
接下来是难点,由于HIVE是采用JAVA编写的 "\"在JAVA中有着特殊的意义,同时还涉及到了正则表达式,更加复杂了。
最初我的语句是这样的。
insert overwrite table TWO select id,regexp_replace(coalesce(name,'NULL'),‘\r’,'\n') from ONE;
发现根本不起作用。
通过查询源码,发现我的 '\r' 在经过regexp_replace函数的时候变成了对象 TEXT("\\r"),这是由于JAVA引起的。
我的正则(‘\r’)也不起作用,因为正则遇到\的时候需要使用两个\\代表一个\,同时由于这个操作是在JAVA中进行的。反斜杠的数量应该再乘以2.
所以语句改成了:
insert overwrite table TWO select id,regexp_replace(coalesce(name,'NULL'),‘\\\\r’,'\\n') from ONE;
发现TWO变成了
ID NAME
1, NULL
2, licln
n的前面少了一个反斜杠,于是语句变成了: insert overwrite table TWO select id,regexp_replace(coalesce(name,'NULL'),‘\\\\r’,'\\\\n') from ONE;
这个程序在客户端运行的十分好。
TWO表变成了
ID NAME
1, NULL
2, licl\n
但是!当我采用JDBC的模式的时候,发现第二条记录完全没有变化,也就是说正则匹配又失败了。
我推测是jdbc传输语句的问题,反斜杠的数量再次发生了变化,于是索性。
insert overwrite table TWO select id,regexp_replace(coalesce(name,'NULL'),‘\\\\\\\\r’,'\\\\\\\\n') from ONE;
这次JDBC发送的语句也执行的很好。
至此,我们的语句写完了。