已复制
全屏展示
复制代码

Hive Spark 最常用函数指南


· 10 min read

函数文档查询

-- 查看所有的函数列表
SHOW FUNCTIONS;

-- 查看指定函数文档
DESCRIBE FUNCTION <function_name>;

-- 查看指定函数详细文档
DESCRIBE FUNCTION EXTENDED <function_name>;

一. 普通函数(UDF)

substring

substring(field, i, j)   截取字符串,从某个索引 i 开始,截取长度为 j 的子字符串,注意索引从 1 开始。

  • 当 i 为负数时,取最后一个字符
  • 当 j 超过长度时,取到最大的位置
SELECT substring("abcdefg", 1, 3) -- 从1开始,取3个字符
-- abc

SELECT substring("abcdefg", 2, 20) -- 从2开始,取20个字符
-- bcdefg

SELECT substring("abcdefg", -1, 1) -- 从最后一位开始,只能取到1个字符
-- g

SELECT substring("abcdefg", -1, 5) -- 从最后一位开始,只能取到取1个字符
-- g

substr

同 substring

substring_index

按关键字截取字符串,按照出现的第几次进行截取,substring_index(field, delimiter, times)相当于特殊版本的 split

  • times为正:正向查找
  • times为负:反向查找
SELECT substring_index("ab_cd_ef_gx", '_', 1);  -- ab
SELECT substring_index("ab_cd_ef_gx", '_', 2);  -- ab_cd
SELECT substring_index("ab_cd_ef_gx", '_', 3);  -- ab_cd_ef
SELECT substring_index("ab_cd_ef_gx", '_', 4);  -- ab_cd_ef_gx 没有出现第4次,则取到最大长度


SELECT substring_index("ab_cd_ef_gx", '_', -1);  -- gx
SELECT substring_index("ab_cd_ef_gx", '_', -2);  -- ef_gx
SELECT substring_index("ab_cd_ef_gx", '_', -3);  -- cd_ef_gx
SELECT substring_index("ab_cd_ef_gx", '_', -4);  -- ab_cd_ef_gx 没有出现第4次,则取到最大长度

size

获取array类型数据的长度

SELECT size(split('a,b,c,d', ','))
-- 4

regexp_replace

正则搜索替换,匹配不成功则展示原内容

SELECT regexp_replace('school go to school', 'school$', 'class')
-- school go to class

SELECT regexp_replace('school go to school', 'beijing', 'class')
-- school go to school

regexp_extract

提取字符串中匹配的分组 regexp_extract(str, regexp[, idx])

  • str:待提取的字符串。
  • regexp:正则表达式。
  • idx:提取第几个分组,分组用括号()包含,可省略,默认为1,idx为0表示提取整个字符串。
-- 提取 URL 的参数部分
select regexp_extract('http://www.a.com/?name=zhang&age=10&wd=big', '.*\\?(.*)', 1)
-- name=zhang&age=10&wd=big


-- 分布提取 name age wd
select regexp_extract('http://www.a.com/?name=zhang&age=10&wd=big', '.*name=(.*?)&age=(.*?)&wd=(.*)', 1);
select regexp_extract('http://www.a.com/?name=zhang&age=10&wd=big', '.*name=(.*?)&age=(.*?)&wd=(.*)', 2);
select regexp_extract('http://www.a.com/?name=zhang&age=10&wd=big', '.*name=(.*?)&age=(.*?)&wd=(.*)', 3);

regexp

判断是否匹配

select 'bbbaaabbb' regexp  'abc'
-- false

coalesce

返回参数中的第一个非 NULL 值;如果所有值都为NULL,那么返回NULL

select COALESCE(NULL, NULL, '2')
-- 2

select COALESCE(NULL, NULL, NULL)
-- NULL

select COALESCE(NULL, '', 2)
-- ''

select COALESCE(NULL, 2)
-- 2

split

字符串切分

SELECT split('a,b,c,d,e', ',');
-- ["a","b","c","d","e"]

SELECT split('a,b,c,d,e', ',')[0];
-- a

SELECT split('a,b,c,d,e', ',')[1];
-- b

SELECT split('a,b,c,d,e', ',')[5];
-- NULL

get_json_object

当获取的字段不存在时,返回 NULL,这种方式一次只能取一个字段,如需一次取多个字段,可使用json_tuple

select get_json_object('{"a": {"a1":"1", "a2":"2"}, "b":2}', '$.a')
-- {"a1":"1","a2":"2"}

select get_json_object('{"a": {"a1":"1", "a2":"2"}, "b":2}', '$.a.a1')
-- 1

select get_json_object('{"a": {"a1":"1", "a2":"2"}, "b":2}', '$.a.a3')
-- NULL

json_tuple

只能取最外的一层,跨层的话返回 NULL

  • json_tuple 单独使用
SELECT JSON_TUPLE('{"a": {"a1":"1", "a2":"2"}, "b":2}', 'a'); -- {"a1":"1","a2":"2"}
SELECT JSON_TUPLE('{"a": {"a1":"1", "a2":"2"}, "b":2}', 'b'); -- 2
SELECT JSON_TUPLE('{"a": {"a1":"1", "a2":"2"}, "b":2}', 'a.a1'); -- null

SELECT JSON_TUPLE('{"a": {"a1":"1", "a2":"2"}, "b":2}', 'a', 'b'); -- 同时取多个字段,结果需要配合LATERAL VIEW使用
  • json_tuple 与 LATERAL VIEW 混用,可以同时取多个字段
SELECT value_a, value_b
FROM (
         SELECT '{"a": {"a1":"1", "a2":"2"}, "b":2}' AS info
     ) t
         LATERAL VIEW JSON_TUPLE(info, 'a', 'b') fields AS value_a, value_b
-- {"a1":"1","a2":"2"},2


SELECT value_a_1, value_a_2, value_b
FROM (
         SELECT '{"a": {"a1":"1", "a2":"2"}, "b":2}' AS info
     ) t
         LATERAL VIEW JSON_TUPLE(info, 'a', 'b') tmp1 AS value_a, value_b
         LATERAL VIEW JSON_TUPLE(value_a, 'a1', 'a2') tmp2 AS value_a_1, value_a_2
-- 1,2,2


SELECT value_a_info, value_b
FROM (
         SELECT '{"a": "a,b,c,d,e", "b":2}' AS info
     ) t
         LATERAL VIEW JSON_TUPLE(info, 'a', 'b') tmp1 AS value_a, value_b
         LATERAL VIEW EXPLODE(split(value_a, ',')) tmp2 AS value_a_info
-- result
a,2
b,2
c,2
d,2
e,2

instr

返回字符串中 子字符串 出现的位置,位置从 1 开始,没有找到 子字符串 则返回0

select instr("abcde",'b')
-- 2

select instr("abcde",'x')
-- 0

select instr("abcde",'ce')
-- 0

select instr("abcde",'cd')
-- 3

lpad

字符串左边补足多少个字符

SELECT LPAD('12', 5, 'x') -- xxx12

rpad

字符串右边补足多少个字符

SELECT RPAD('12', 5, 'x') -- 12xxx

pmod

语法: pmod(int a, int b), pmod(double a, double b)

返回值: int double

说明: 返回正的 a 除以 b 的余数

SELECT PMOD(210, 3) -- 0
SELECT PMOD(2.10, 0.03) -- 0.0
SELECT PMOD(5, 10) -- 5

sort_array

  • 只能是升序
SELECT sort_array(COLLECT_SET(score))
FROM (SELECT NULL) t
         LATERAL VIEW EXPLODE(
                 ARRAY(10, 20, 20, 30, 10)
             ) t AS score;
-- [10,20,30]


SELECT sort_array(collect_list(score))
FROM (SELECT NULL) t
         LATERAL VIEW EXPLODE(
                 ARRAY(10, 20, 20, 30, 10)
             ) t AS score;
-- [10,10,20,20,30]

sort_array_by

  • 可以倒序:倒序需要引入struct,然后指定struct的第哪个字段来排序
-- 把属性包装到struct里面,默认生成的struct名称依次为 col1 col2 ...
SELECT sort_array_by(collect_list(score), 'col1', 'DESC')
FROM (SELECT NULL) t
         LATERAL VIEW EXPLODE(
                 ARRAY(struct(10), struct(20), struct(20), struct(30), struct(10))
             ) t AS score;
-- [{"col1":30},{"col1":20},{"col1":20},{"col1":10},{"col1":10}]

printf

格式化字段

SELECT PRINTF("%s---%s", score, score)
FROM (SELECT NULL) t
         LATERAL VIEW EXPLODE(
                 ARRAY(10, 20, 20, 30, 10)
             ) t AS score;
-- 结果
 10---10 
 20---20 
 20---20 
 30---30 
 10---10 

nvl

NVL(expr1, expr2)

如果 expr1 不为 null,返回 expr1

如果 expr1 为 null,返回 expr2

二. 聚合函数(UDAF)

collect_set

将 colname 指定的列值聚合为一个无重复元素的数组。

  • 返回值说明:返回 ARRAY 类型。colname 值为 NULL 时,该行不参与计算。
SELECT COLLECT_SET(score)
FROM (SELECT NULL) t
         LATERAL VIEW EXPLODE(
                 ARRAY(10, 20, 20, 30, 10)
             ) t AS score;

-- [10,20,30]

collect_list

将指定的列聚合为一个数组。

  • 返回值说明:返回 ARRAY 类型。colname 值为 NULL 时,该行不参与计算。
SELECT collect_list(score)
FROM (SELECT NULL) t
         LATERAL VIEW EXPLODE(
                 ARRAY(10, 20, 20, 30, 10)
             ) t AS score;
-- [10,20,20,30,10]

percentile

中位数

求中位数又称中值,是按顺序排列的一组数据中居于中间位置的数,可以通过把所有观察值高低排序后找出正中间的一个作为中位数。如果观察值有偶数个,通常取最中间的两个数值(n1 n1)的平均数作为中位数=n1+(n2-n1)*p。参考:https://www.zhihu.com/question/67763556?sort=created

p位数

中位数表示中间位,此时p值为0.5,其实还有其他0~1之间的位数值分界点,叫做p位数。

命令说明

计算精确百分位数,适用于小数据量。先对指定列(int类型)升序排列,然后取精确的第p位百分数。p必须在0和1之间。percentile是从编号0开始计算,例如某列数据为100、200、300,列数据的编号顺序为0、1、2,计算该列的0.3百分位点,percentile结果是2×0.3=0.6,即值位于编号0和1之间,结果为100+(200-100)×0.6=160。

参数说明
  • colname:必填。值为BIGINT类型的列。
  • p:必填。需要精确的百分位数。取值为[0.0,1.0]。
返回值说明
  • 返回 DOUBLE 或 ARRAY 类型。
SELECT percentile(score, ARRAY(0.1, 0.5, 0.8))
FROM (SELECT NULL) t
         LATERAL VIEW EXPLODE(
                 ARRAY(10, 20, 60, 70, 80, 90, 30, 40, 50, 100)
             ) t AS score

-- 结果: [19.0,55.0,82.0]
-- 计算0.1分位举例: 10到100升序排序,然后编号0到9,0.1*9=0.9,表示要取编号为0到1之间的数即 10+(20-10)*(0.9-0)=19.0
-- 计算0.8分位举例: 10到100升序排序,然后编号0到9,0.8*9=7.2,表示要取编号为7到8之间的数即 70+(80-70)*(7.2-7)=82.0

SELECT percentile(score, 0.5)
FROM (SELECT NULL) t
         LATERAL VIEW EXPLODE(
                 ARRAY(10, 20, 60, 70, 80, 90, 30, 40, 50, 100)
             ) t AS score

-- 结果: 55.0

percentile_approx

命令说明

计算近似百分位数,适用于大数据量。先对指定列升序排列,然后取第p位百分数对应的值。percentile_approx是从编号1开始计算,例如某列数据为100、200、300,列数据的编号顺序为1、2、3,计算该列的0.6百分位点,percentile_approx结果是3×0.6=1.8,即值位于编号1和2之间,结果为100+(200-100)×0.8=180。

percentile_approx与percentile的区别

percentile_approx用于计算近似的百分位数,percentile用于计算精确的百分位数。在数据量较大时,percentile可能会因内存限制而执行失败,而percentile_approx无此问题。

命令格式
-- 返回浮点数
double percentile_approx (double <colname>, <p> [, <B>])) 

-- 以数组形式返回多个百分位近似计算结果。
array<double> percentile_approx (double <colname>, array(<p1> [, <p2>...]) [, <B>])
参数说明
  • colname:必填。值为DOUBLE类型的列。
  • p:必填。需要近似的百分位数。取值为[0.0,1.0]。
  • B:精度参数。数字越大精度越高产生的近似值误差越小。如果不设置该参数,默认值为10000。

三. 扩展函数(UDTF)

即扩展函数的输出是一个新的表。

explode

功能:将 array 或者 map 炸开,通常和 lateral view 混合使用。

注意:在 select 里面只能出现一个 EXPLODE 字段,如果要同时列出其他字段,则需要使用 lateral view。

  • array
SELECT EXPLODE(detail) as info
FROM (
         SELECT "zhang" AS username,
                SPLIT('a,b,c,d,e,', ',') AS detail
     ) t
-- 结果
a
b
c
d
e
""

-- 如下 SQL 会报错
SELECT username,
       EXPLODE(detail)
FROM (
         SELECT "zhang" AS username,
                SPLIT('a,b,c,d,e,', ',') AS detail
     ) t
     
  • map
SELECT key as mykey, value as myvalue
FROM (
         SELECT EXPLODE(STR_TO_MAP('name:zhang,age:12,address:beijing gu gong'))
     ) t
     

posexplode

功能:将array炸开,同时返回下标

注意:不能炸开map,因为map是无序的,返回下标无意义。

SELECT POSEXPLODE(detail)
FROM (
         SELECT "zhang" AS username,
                SPLIT('a,b,c,d,e,', ',') AS detail
     ) t
-- 结果
0,a
1,b
2,c
3,d
4,e
5,""

lateral view

功能:能够将一行数据拆成多行数据,通常配合split、explode、json_tuple使用

原理:LATERAL VIEW 对遇到的每一行,首先会按 UDTF 表达式进行处理,展开成若干行(可能是零行),然后将这些输出行与输入行 INNER JOIN。如果要保留输出为 NULL 的行,则需使用 LATERAL VIEW OUTER 执行 OUTER JOIN。

  • 命令格式
from <baseTable> lateral view [outer] <udtf_name>(<expression>) <table_alias> as <columnAlias> (',' <columnAlias>)
  • 使用示例
SELECT username,
       info
FROM (
         SELECT "zhang" AS username,
                SPLIT('a,b,c,d,e,', ',') AS detail
     ) t LATERAL VIEW EXPLODE(detail) tmp AS info
-- 结果
zhang,a
zhang,b
zhang,c
zhang,d
zhang,e
zhang,""


SELECT username,  -- POSEXPLODE 同时返回下标
       indexOf,
       info
FROM (
         SELECT "zhang" AS username,
                SPLIT('a,b,c,d,e,', ',') AS detail
     ) t LATERAL VIEW POSEXPLODE(detail) tmp AS indexOf, info
-- 结果
zhang,0,a
zhang,1,b
zhang,2,c
zhang,3,d
zhang,4,e
zhang,5,""

  • 参考资料 hive官方文档

https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF


文章推荐