1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > hive中concat_ws的秘密

hive中concat_ws的秘密

时间:2019-04-01 08:10:57

相关推荐

hive中concat_ws的秘密

hive中concat_ws的秘密

1. 背景

在hive中,concat_ws有两种用法:

concat_ws("|", array('a', 'b')); -- 输出a|bconcat_ws('|', 'a', 'b');-- 输出a|b

其中,第一个参数是其它字符串的分隔符,concat_ws有个比较好用的特点,就是会自动跳过值为null的字符串(注意:空字符串不会跳过)。例如:

concat_ws('|', 'a', null, 'b');-- 输出a|b

但是在工作中,我遇到了一个奇怪的问题:

concat_ws('|', 'a', null, 'b');-- 输出a|bconcat_ws('|', array('a', null, 'b'));-- 输出a|null|b

这就奇怪了,不是说concat_ws会忽略所有null吗,为什么这里非但没忽略,还输出了“null”字符串?

2. 源码探究

2.1 concat_ws源码

实在按奈不住好奇心,于是去扒了一下concat_ws的UDF源码:

@Overridepublic Object evaluate(DeferredObject[] arguments) throws HiveException {if (arguments[0].get() == null) {return null;}// 获取分隔符String separator = PrimitiveObjectInspectorUtils.getString(arguments[0].get(), (PrimitiveObjectInspector)argumentOIs[0]);StringBuilder sb = new StringBuilder();boolean first = true;for (int i = 1; i < arguments.length; i++) {// 判断所取的值是不是nullif (arguments[i].get() != null) {// 如果是第一个字符串,则不加分隔符,否则加if (first) {first = false;} else {sb.append(separator);}// 如果第二个参数是List,也就是 concat_ws('|', array()) 这种使用类型if (argumentOIs[i].getCategory().equals(Category.LIST)) {Object strArray = arguments[i].get();ListObjectInspector strArrayOI = (ListObjectInspector) argumentOIs[i];boolean strArrayFirst = true;for (int j = 0; j < strArrayOI.getListLength(strArray); j++) {// 与外循环同样的处理逻辑,唯一的区别就是没有判断nullif (strArrayFirst) {strArrayFirst = false;} else {sb.append(separator);}sb.append(strArrayOI.getListElement(strArray, j));}} else {// 如果第二个参数不是List,则一个一个append,中间穿插sb.append(PrimitiveObjectInspectorUtils.getString(arguments[i].get(), (PrimitiveObjectInspector)argumentOIs[i]));}}}resultText.set(sb.toString());return resultText;}

在这里,可以清晰的看到concat_ws的处理流程。在取每个参数值后,会有个arguments[i].get() != null,判断是否为null。如果所取的参数类型为array,就进入for循环,取出array中的每个值。

与外层循环不同的是,array中的循环并没有做null判断处理,而是直接append。

因此,如果使用concat_ws('|', array())这种模式,array中的null值并不会被跳过。

但是至此还有一个疑问,最后输出结果中的null字符串是哪里来的呢?

2.2 stringbuilder源码

终于到了最后的阶段,打开stringbuilder的源码,如果append进来的String为null,最后会走到appendNull方法。

private AbstractStringBuilder appendNull() {int c = count;ensureCapacityInternal(c + 4);final char[] value = this.value;value[c++] = 'n';value[c++] = 'u';value[c++] = 'l';value[c++] = 'l';count = c;return this; }

至此,终于搞清楚了concat_ws中null字符串的来源。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。