Hive中给了很多系统函数,官网 给了很多函数可以参考。但是复杂的业务中,官方函数并不一定能满足特定化的需求,这时可以自定义函数来满足需求。

参考:官网中的关于UDF部分的链接

1. 在IDEA中创建一个项目,配置pom.xml 添加依赖如下:

1
2
3
4
5
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>2.1.1</version>
</dependency>

2. 创建一个类,例如创建一个把字符串全部转换为小写的UDF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package tech.mapan.hive;
import org.apache.hadoop.hive.ql.exec.UDF;

/**
* @program: UDF
* @description: UDF函数
* @author: MaPan
* @create: 2020-03-22 09:13
**/
public class Lower extends UDF {
public String evaluate (String s) {

if (s == null) {
return null;
}
return s.toLowerCase();
}
}

3. 打jar包,把jar包放在 /opt/local/hive/lib

这一步就不在赘述,默认大家都会

4. 配置环境变量

CDH官网写的在hive-site.xml中配置hive.aux.jars.path,但是我配置完后并没有生效,不过官网写

The directory location is set in the environment as HIVE_AUX_JARS_PATH and will generally override the hive.aux.jars.path property set in XML files, even if hive.aux.jars.path is set in an advanced configuration snippet.

意思就是环境变量的优先级要高于XML,所以建议直接配置环境变量。

在root用户下:

1
2
3
4
vim /etc/profile.d/hive.sh 
# 添加如下内容并保存
export HIVE_AUX_JARS_PATH=/opt/local/hive/lib
export PATH=$PATH:$HIVE_AUX_JARS_PATH

执行source /etc/profile刷新环境变量。

5. 进入hive-cli中,创建函数

1
2
3
4
5
6
7
8
9
hive (default)> create function mylower as "tech.mapan.hive.Lower";
OK
Time taken: 0.285 seconds

hive (default)> select mylower("HELLO WORLD");
OK
_c0
hello world
Time taken: 0.18 seconds, Fetched: 1 row(s)

这样就向系统添加了一个函数 mylower(), 退出hive-cli再次进入依然生效。


随手写了几个常用的UDF函数:

  • 输入两个数,输出按位与的结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package tech.mapan.hive;

import org.apache.hadoop.hive.ql.exec.UDF;

/**
* @program: UDF
* @description: 按位与
* @author: MaPan
* @create: 2020-03-22 12:29
**/
public class BitAnd extends UDF {
public String evaluate(String a, String b) {
String result;
if(a==null ||b==null){
result = null;
}else {
int i = Integer.parseInt(a);
int j = Integer.parseInt(b);
result = Integer.toString(i & j);
}
return result;
}
}
  • 输入几个数,找出这些数中最大的数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package tech.mapan.hive;

import org.apache.hadoop.hive.ql.exec.UDF;

/**
* @program: UDF
* @description: 求一组数中的最大值
* @author: MaPan
* @create: 2020-03-22 12:49
**/
public class Greatest extends UDF {
public String evaluate(String... strings) {
int[] arr = new int[strings.length];
int i = 0;
for (String s : strings) {
if (s == null) {
return null;
} else {
arr[i++] = Integer.parseInt(s);
}
}
int max = arr[0];
for (int j = 1; j < arr.length; j++) {
if (arr[j] > max) {
max = arr[j];
}
}
return Integer.toString(max);
}
}
  • 地址脱敏
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package tech.mapan.hive;

import org.apache.hadoop.hive.ql.exec.UDF;

/**
* @program: UDF
* @description: 地址脱敏, 对长度超过15个字符串, 只保留前15个字符, 不超过15个则不截取, 全部返回。
* @author: MaPan
* @create: 2020-03-22 11:19
**/
public class MaskAddress extends UDF {
public String evaluate(String s) {
String result = "";
if (s == null) {
return null;
} else if (s.length() > 15) {
result = s.substring(0, 14);
} else {
result = s;
}
return result;
}
}
  • 邮箱脱敏
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package tech.mapan.hive;

import org.apache.hadoop.hive.ql.exec.UDF;

/**
* @program: UDF
* @description: 邮箱脱敏,@后面全部换成*
* @author: MaPan
* @create: 2020-03-22 13:19
**/
public class MaskMail extends UDF {
public String evaluate(String s) {
String res = "";
if (s == null) {
res = null;
} else {
String[] split = s.split("@");
res = split[0] + "@*****";
}
return res;
}
}
  • 单号脱敏
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package tech.mapan.hive;

import org.apache.hadoop.hive.ql.exec.UDF;

/**
* @program: UDF
* @description: 单号脱敏,保留头部尾部各两位,其他全部换成*
* @author: MaPan
* @create: 2020-03-22 13:25
**/
public class MaskNo extends UDF {
public String evaluate(String s) {
String res = "";
if (s == null) {
res = null;
} else {
res = s.substring(0, 2) + "****" + s.substring(s.length() - 2);
}
return res;
}
}
  • 手机号脱敏
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package tech.mapan.hive;

import org.apache.hadoop.hive.ql.exec.UDF;

/**
* @program: UDF
* @description: 手机号码脱敏,手机号码后6位换成*
* @author: MaPan
* @create: 2020-03-22 13:08
**/
public class MaskPhone extends UDF {
public String evaluate(String s) {
String res = "";
if (s == null) {
res = null;
} else {
res = s.substring(0, 5) + "******";
}
return res;
}
}
  • 性别归一化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package tech.mapan.hive;

import org.apache.hadoop.hive.ql.exec.UDF;

/**
* @program: UDF
* @description: 性别归一化,不同的系统中的性别不同有的是男和女,有的是F和M有的是1和0,针对不同的性别表示方式进行归一化
* @author: MaPan
* @create: 2020-03-22 13:47
**/
public class GenderETL extends UDF {
public String evaluate(String s) {
String res = "";
if (s == null) {
res = null;
} else {
if (s.equals("男") || s.equals("M") || s.equals("1")) {
res = "男";
} else if (s.equals("女") || s.equals("F") || s.equals("0")) {
res = "女";
} else {
res = "未知";
}
}
return res;
}
}

附:jar包下载