引言:
通过split分割当前字段获取数组,并得到最后一个索引的元素,通过hive怎么实现,下面通过不同方法一一验证可行性。
字段样式 shopList : productA,productB,productC
表名 shopTable : shopListTable
一.split + size 获取 – 失败
hive -e "
select split(shopList,',')[size(split(shopList,','))-1]
from shopTable;
"
FAILED: SemanticException 2:25 Non-constant expressions for array indexes not supported. Error encountered near token '1'
遇到这个问题第一反应就是split转化为数组,再通过数组size-1获取最后一位,但是 array 的索引位置不允许非常数的表达式,所以失败。
二.split + size + cast 获取 – 失败
hive -e "
select array[index] as product
from
( select split(shopList,',') array, cast((size(split(shopList,',')) - 1) as int) index from shopTable) tmp
";
FAILED: SemanticException 2:12 Non-constant expressions for array indexes not supported. Error encountered near token 'index'
和上面的问题类似,有点坑,继续尝试。
三. regexp_extract – 能跑但效果不对
hive -e "
select regexp_extract(shopList,'(\,[^\,]+)',1)
from shopTable
";
split 和 regexp_extract 作用类似,但是这里正则表达式使用起来有问题,还是暂不考虑。
四. reverse + split + reverse – 成功
hive -e "
select reverse(split(reverse(shopList), ',')[1])
from shopTable";
看网上大神这么操作的,实测没有问题,但是性能和资源消耗都比较严重。
五.自定义UDF – 成功 (推荐)
截止目前上面四种方法只有 reverse 一种可以实现但是效率还是个问题,所以出大招直接自己写函数好了。
java :
package com.hive.udf;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;
import java.util.List;
/**
* @title: SplitString
* @Date: 2021-01-21 14:21
* @Version 1.0
*/
public final class SplitString extends UDF {
public Text evaluate(final Text s) {
if (s == null) { return null; }
String[] arr = s.toString().split(",");
if ( arr.length == 0) { return null; }
return new Text(arr[arr.length - 1]);
}
}
sh :
hive -e "
add jar ~/your-class-1.0-SNAPSHOT.jar;
create temporary function my_split as 'com.hive.udf.SplitString';
select my_split(shopList) from shopTable group by my_split(shopList);
"
将java代码打包,并上传至sh脚本对应位置即可,通过自定义的方法实现 split + index 功能,这里不局限于倒数第一位,倒数第几位都可以,实测性能优于 reverse, 值得拥有!
除了UDF(一进一出)之外,还有 UDAF (多进一出)和 UDTF(一进多出)等形式,有兴趣也可以自己实现~