【大數據】Hive 內置函數和 UDF 講解
一、概述
Hive是基于Hadoop的一個數據倉庫工具,可以將結構化數據文件映射為一張數據庫表,并提供類SQL語句操作。Hive內置了很多函數,可以滿足基本的查詢需求,同時還支持自定義函數(UDF)來實現更加靈活的操作。
官方文檔:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
下面簡單介紹Hive內置函數和UDF的相關內容:
1)內置函數
Hive內置函數主要用于集合函數、數學函數、日期函數、字符串函數和條件判斷函數等方面。例如:
- 條件判斷函數:IF、WHEN、CASE、COALESCE等。
- 字符串函數:LENGTH、SUBSTR、CONCAT、TRIM、LOWER、UPPER等;
- 集合函數:SUM、MAX、MIN、AVG、COUNT等;
- 數學函數:ROUND、EXP、LOG、SIGN等;
- 日期函數:YEAR、MONTH、DAY、HOUR、MINUTE、SECOND等;
2)自定義函數(UDF)
除了Hive內置函數之外,用戶還可以自定義函數來實現更加靈活的操作。 Hive支持三種類型的自定義函數:
- 標量函數(UDF):將一行中的一個值轉換為另外一個值,比如字符串轉小寫;
- 集合函數(UDAF):作用于多個值上,并且返回一個結果,比如平均值;
- 行級別函數(UDTF):將一行中的一個或多個字段轉換為多行,比如對一行中的字符串進行單詞切分。
自定義函數用Java語言編寫,需要繼承Hive提供的UDF、UDAF或UDTF類,然后實現相應的方法。例如,下面是一個自定義的UDF函數,用于將字符串轉為小寫:
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;
public class Lowercase extends UDF {
public Text evaluate(Text str) {
if (str == null) {
return null;
} else {
return new Text(str.toString().toLowerCase());
}
}
}
以上是簡單介紹Hive內置函數和UDF的相關內容,使用Hive內置函數可以滿足常用的查詢需求,而自定義函數可以更加靈活地滿足特定的業務需求。
二、環境準備
如果已經有了環境了,可以忽略,如果想快速部署環境可以參考我這篇文章:通過 docker-compose 快速部署 Hive 詳細教程
# 登錄容器
docker exec -it hive-hiveserver2 bash
# 連接hive
beeline -u jdbc:hive2://hive-hiveserver2:10000 -n hadoop
三、Hive 內置函數
先創建一張表來測試
# 登錄容器
docker exec -it hive-hiveserver2 bash
# 登錄hive客戶端
beeline -u jdbc:hive2://hive-hiveserver2:10000 -n hadoop
# 建表
CREATE EXTERNAL TABLE external_table1 (
column1 STRING,
column2 INT,
column3 DOUBLE
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
STORED AS TEXTFILE
LOCATION '/user/hive/external_table/data';
添加數據
# 登錄容器
docker exec -it hive-hiveserver2 bash
# 模擬一些數據
cat >data<<EOF
c1,12,56.33
c2,14,58.99
c3,15,66.34
c4,16,76.78
EOF
# 登錄hive客戶端
beeline -u jdbc:hive2://hive-hiveserver2:10000 -n hadoop
# 加載數據,local 是加載本機文件數據
load data local inpath './data' into table external_table1;
1)條件判斷函數
1、If函數: if
語法:
if(boolean testCondition, T valueTrue, T valueFalseOrNull)
# 返回值: T
# 說明: 當條件testCondition為TRUE時,返回valueTrue;否則返回valueFalseOrNull
示例:
# 注意,這里查詢的記錄必須存在,要不然也返回空
hive> select if(1=2,100,200) from external_table1;
200
hive> select if(1=1,100,200) from external_table1;
100
3、條件判斷函數:CASE
語法:
CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END
#返回值: T
#說明:如果a等于b,那么返回c;如果a等于d,那么返回e;否則返回f
示例:
hive> Select case 100 when 50 then 'tom' when 100 then 'mary' else 'tim' end from external_table1;
mary
hive> Select case 200 when 50 then 'tom' when 100 then 'mary' else 'tim' end from external_table1;
tim
4、非空查找函數: COALESCE
語法:
COALESCE(T v1, T v2, …)
#返回值: T
#說明: 返回參數中的第一個非空值;如果所有值都為NULL,那么返回NULL
示例:
hive> select COALESCE(null,'100','50') from external_table1;
100
2)字符串函數
1、字符串長度函數:length
語法:
length(string A)
#返回值: int
#說明:返回字符串A的長度
示例:
hive> select length('abcedfg') from external_table1;
7
2、字符串截取函數:substr,substring
語法:
substr(string A, int start, int len)
substring(string A, int start, int len)
# int len,可省略,就是到最后一個字符
#返回值: string
#說明:返回字符串A從start位置開始,長度為len的字符串
示例:
hive> select substr('abcde',3) from external_table1;
cde
hive> select substring('abcde',3) from external_table1;
cde
hive> select substr('abcde',-1) from external_table1;
e
hive> select substr('abcde',3,2) from external_table1;
cd
hive> select substring('abcde',3,2) from external_table1;
cd
hive>select substring('abcde',-2,2) from external_table1;
de
3、字符串連接函數:concat
語法:
concat(string A, string B…)
#返回值: string
#說明:返回輸入字符串連接后的結果,支持任意個輸入字符串
示例:
hive> select concat('abc','def','gh') from external_table1;
abcdefgh
4、去空格函數:trim
語法:
trim(string A)
#返回值: string
#說明:去除字符串兩邊的空格
示例:
hive> select trim(' abc ') from external_table1;
abc
5、字符串轉小寫函數:lower,lcase
語法:
lower(string A),lcase(string A)
#返回值: string
#說明:返回字符串A的小寫格式
示例:
# 兩個函數的作用是相同的,其區別僅僅是函數名不同。
hive> select lower('abSEd') from external_table1;
absed
hive> select lcase('abSEd') from external_table1;
absed
6、字符串轉大寫函數:upper,ucase
語法:
upper(string A), ucase(string A)
#返回值: string
#說明:返回字符串A的大寫格式
示例:
hive> select upper('abSEd') from external_table1;
ABSED
hive> select ucase('abSEd') from external_table1;
ABSED
3)集合函數
1、總和統計函數: sum
語法:
sum(col), sum(DISTINCT col)
#返回值: double
#說明: sum(col)統計結果集中col的相加的結果;sum(DISTINCT col)統計結果中col不同值相加的結果
示例:
hive> select sum(column2) from external_table1;
hive> select sum(distinct column2) from external_table1;
2、最大值統計函數: max
語法:
max(col)
#返回值: double
#說明: 統計結果集中col字段的最大值
示例:
hive> select max(column2) from external_table1;
3、最小值統計函數: min
語法:
min(col)
#返回值: double
#說明: 統計結果集中col字段的最小值
示例:
hive> select min(column2) from external_table1;
4、平均值統計函數: avg
語法:
avg(col), avg(DISTINCT col)
#返回值: double
#說明: avg(col)統計結果集中col的平均值;avg(DISTINCT col)統計結果中col不同值相加的平均值
示例:
hive> select avg(column2) from external_table1;
hive> select avg (distinct column2) from external_table1;
5、個數統計函數: count
語法:
count(*), count(expr), count(DISTINCT expr[, expr_.])
#返回值: int
#說明: count(*)統計檢索出的行的個數,包括NULL值的行;count(expr)返回指定字段的非空值的個數;count(DISTINCT expr[, expr_.])返回指定字段的不同的非空值的個數
示例:
hive> select count(*) from external_table1;
hive> select count(distinct column2) from external_table1;
4)數學函數
1、取整函數: round
語法:
round(double a)
#返回值: BIGINT
#說明: 返回double類型的整數值部分 (遵循四舍五入)
#也可以指定精度
round(double a, int d)
示例:
hive> select round(3.1415926) from external_table1;
3
hive> select round(3.5) from external_table1;
4
hive> create table external_table2 as select round(9542.158) from external_table1;
hive> describe external_table2;
_c0 decimal(5,0)
# 指定精度
hive> select round(3.1415926,4) from external_table1;
3.1416
2、向下取整函數: floor
語法:
floor(double a)
#返回值: BIGINT
#說明: 返回等于或者小于該double變量的最大的整數
示例:
hive> select floor(3.1415926) from external_table1;
3
hive> select floor(25) from external_table1;
25
3、向上取整函數: ceil
語法:
ceil(double a)
#返回值: BIGINT
#說明: 返回等于或者大于該double變量的最小的整數
示例:
hive> select ceil(3.1415926) from external_table1;
4
hive> select ceil(46) from external_table1;
46
4、取隨機數函數: rand
語法:
rand(),rand(int seed)
#返回值: double
#說明: 返回一個0到1范圍內的隨機數。如果指定種子seed,則會等到一個穩定的隨機數序列
示例:
hive> select rand() from external_table1;
0.5577432776034763
hive> select rand() from external_table1;
0.6638336467363424
hive> select rand(100) from external_table1;
0.7220096548596434
hive> select rand(100) from external_table1;
0.7220096548596434
5、絕對值函數: abs
語法:
abs(double a) abs(int a)
#返回值: double int
#說明: 返回數值a的絕對值
示例:
hive> select abs(-3.9) from external_table1;
3.9
hive> select abs(10.9) from external_table1;
10.9
6、自然指數函數: exp
語法:
exp(double a)
#返回值: double
#說明: 返回自然對數e的a次方
示例:
hive> select exp(2) from external_table1;
7.38905609893065
7、對數函數: log
語法:
log(double base, double a)
#返回值: double
#說明: 返回以base為底的a的對數
示例:
hive> select log(4,256) from external_table1;
4.0
5)日期函數
1、日期轉年函數: year
語法:
year(string date)
#返回值: int
#說明: 返回日期中的年。
示例:
hive> select year('2023-05-04 22:03:01') from external_table1;
2023
hive> select year('2024-05-04') from external_table1;
2024
2、日期轉月函數: month
語法:
month (string date)
#返回值: int
#說明: 返回日期中的月份。
示例:
hive> select month('2011-12-08 10:03:01') from external_table1;
12
hive> select month('2011-08-08') from external_table1;
8
3、日期轉天函數: day
語法:
day (string date)
#返回值: int
#說明: 返回日期中的天。
示例:
hive> select day('2011-12-08 10:03:01') from external_table1;
8
hive> select day('2011-12-24') from external_table1;
24
4、日期轉小時函數: hour
語法:
hour (string date)
#返回值: int
#說明: 返回日期中的小時。
示例:
hive> select hour('2011-12-08 10:03:01') from external_table1;
10
5、日期轉分鐘函數: minute
語法:
minute (string date)
#返回值: int
#說明: 返回日期中的分鐘。
示例:
hive> select minute('2011-12-08 10:03:01') from external_table1;
3
6、日期轉秒函數: second
語法:
second (string date)
#返回值: int
#說明: 返回日期中的秒。
示例:
hive> select second('2011-12-08 10:03:01') from external_table1;
1
7、日期轉周函數: weekofyear
語法:
weekofyear (string date)
#返回值: int
#說明: 返回日期在當前的周數。
示例:
hive> select weekofyear('2011-12-08 10:03:01') from external_table1;
49
四、Hive UDF
在Hive中,UDF函數是指用戶定義的函數,其目的是為了滿足某些特殊或個性化的需求,或者是為了優化SQL查詢語句的性能。UDF函數可以分為三種類型:標量函數、集合函數和行級函數。下面分別對三種類型的UDF函數進行介紹:
1)標量函數(UDF)
標量函數(也稱為單行函數)是指一次輸入一行數據,一次輸出一行數據的函數。它們語法簡單,通常用于實現對某一列數據的單獨轉換或處理。標量函數可以接受多個參數,但只能返回一個結果。
示例:下面是一個用于計算兩數之和的簡單標量函數示例:
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;
public class ToUpper extends UDF {
public Text evaluate(Text input) {
if (input == null) {
return null;
}
return new Text(input.toString().toUpperCase());
}
}
2)集合函數(UDAF)
集合函數(也稱為聚合函數)是指將多行數據一起處理并返回單個結果的函數,例如平均值、最大值、最小值等。UDAF函數可以接收任意數量的參數,并為每個輸入行返回一個中間累加器(Mapper端計算),最后返回一個最終結果(Reducer端計算)。
示例:下面是一個用于計算平均數的簡單聚合函數示例:
import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.udf.generic.AbstractGenericUDAFResolver;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDAFEvaluator;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDAFEvaluator.AggregationBuffer;
import org.apache.hadoop.io.IntWritable;
public class UDAFAverage extends AbstractGenericUDAFResolver {
public UDAFAverage() {}
@Override
public GenericUDAFEvaluator getEvaluator(TypeInfo[] parameters) throws SemanticException {
return new UDAFAverageEvaluator();
}
public static class UDAFAverageEvaluator extends GenericUDAFEvaluator {
public UDAFAverageEvaluator() {}
// 定義中間累加器
public static class UDAFAverageAgg implements AggregationBuffer {
int sum;
int count;
}
// 初始化中間累加器
public AggregationBuffer getNewAggregationBuffer() throws HiveException {
UDAFAverageAgg result = new UDAFAverageAgg();
reset(result);
return result;
}
// 重置中間累加器
public void reset(AggregationBuffer agg) throws HiveException {
((UDAFAverageAgg) agg).count = 0;
((UDAFAverageAgg) agg).sum = 0;
}
// 處理單個輸入行數據
public void iterate(AggregationBuffer agg, Object[] parameters) throws HiveException {
if (parameters[0] != null) {
((UDAFAverageAgg) agg).sum += ((IntWritable) parameters[0]).get();
((UDAFAverageAgg) agg).count++;
}
}
// 合并各個Mapper返回的中間累加器
public void merge(AggregationBuffer agg, Object partial) throws HiveException {
if (partial != null) {
UDAFAverageAgg other = (UDAFAverageAgg) partial;
((UDAFAverageAgg) agg).sum += other.sum;
((UDAFAverageAgg) agg).count += other.count;
}
}
// 計算最終的結果
public Object terminate(AggregationBuffer agg) throws HiveException {
if (((UDAFAverageAgg) agg).count == 0) {
return null;
} else {
return new Double(((double) ((UDAFAverageAgg) agg).sum) / ((UDAFAverageAgg) agg).count);
}
}
// 結束計算
public Object terminatePartial(AggregationBuffer agg) throws HiveException {
return new IntWritable(((UDAFAverageAgg) agg).sum);
}
}
}
3)行級別函數(UDTF)
行級函數(也稱為表生成函數)是指將一行數據拆分成多行數據進行處理的函數。它們可以接受多個輸入行,并將它們轉換為多個輸出行,常用于文本處理、數據拆分等場景。
示例:下面是一個簡單的行級函數示例,用于將輸入字符串按照分隔符切分并返回多行:
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ListObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector;
import org.apache.hadoop.io.Text;
import java.util.ArrayList;
public class Split extends GenericUDTF {
private transient ListObjectInspector listOI = null;
private transient StringObjectInspector elementOI = null;
public void initialize(ObjectInspector[] argOIs) throws UDFArgumentException {
// 確保輸入是一個列表類型
if (argOIs[0].getCategory() != ObjectInspector.Category.LIST) {
throw new UDFArgumentException("split() takes an array as a parameter");
}
// 獲取列表元素類型
listOI = (ListObjectInspector) argOIs[0];
elementOI = (StringObjectInspector) listOI.getListElementObjectInspector();
// 確保輸出為兩列
ArrayList<String> fieldNames = new ArrayList<String>();
ArrayList<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>();
fieldNames.add("value");
fieldOIs.add(PrimitiveObjectInspectorFactory.writableStringObjectInspector);
fieldNames.add("pos");
fieldOIs.add(PrimitiveObjectInspectorFactory.writableIntObjectInspector);
initialize(fieldNames, fieldOIs);
}
public void process(Object[] record) throws HiveException {
// 獲取輸入字符串
Object list = record[0];
int index = 0;
// 切分字符串并向下傳遞
for (int i = 0; i < listOI.getListLength(list); i++) {
index++;
String value = elementOI.getPrimitiveJavaObject(listOI.getListElement(list, i));
forward(new Object[] { new Text(value), new IntWritable(index) });
}
}
public void close() throws HiveException {
// nothing to do
}
}
以上是Hive UDF函數的介紹,三種類型各自適用于不同的場合,可以根據業務需求選擇相應的UDF函數來實現。