該文件轉自 http://blog.csdn.net/hguisu/article/details/7256833
9 Operators and UDFs
9.1 內置運算符
9.1.1 關系運算符
操作符 | 運算對象的類型 | 描述 |
---|---|---|
A <=> B | ALL | 都是NULL時,返回TRUE,有一為NULL時,返回FALSE,都不為NULL時,與‘=’運算符一樣。 |
A <> B | ALL | A或B為NULL時,返回NULL,否則A不等於B是返回TRUE,反之FALSE。 |
A RLIKE B | strings | A或B為NULL時,返回NULL,A的子串與正則表達式B匹配時,返回TRUE,反之FALSE。 |
A REGEXP B | strings | 同A RLIKE B |
其他不在此列舉。
9.1.2 算數運算符
只要有一個操作數為NULL,結果為NULL。
9.1.3 邏輯運算符
9.1.4 復雜類型
構造函數 | 操作數 | 描述 |
---|---|---|
map | (key1, value1, key2, value2, …) | 創建map |
struct | (val1, val2, val3, …) | 創建struct,屬性名為col1, col2等 |
named_struct | (name1, val1, name2, val2, …) | 創建struct |
array | (val1, val2, …) | 創建array |
create_union | (tag, val1, val2, …) | 創建tag指向的union |
9.1.5 復雜類型的運算符
運算符 | 操作數類型 | 描述 |
---|---|---|
A[n] | A是Array,n是int | 返回數組A的第n個值 |
M[key] | M是Map<K, V>,key是K | 返回key對應的value |
S.x | S是struct | 返回屬性x的值 |
9.2 內置函數
9.2.1 數學函數
返回類型 | 函數名 | 描述 |
---|---|---|
DOUBLE | round(DOUBLE a) | 返回對a四舍五入的BIGINT值 |
DOUBLE | round(DOUBLE a, INT d) | 小數部分d位之后數字四舍五入 |
DOUBLE | bround(DOUBLE a) | 銀行家舍入法(1~4:舍,6~9:進,5->前位數是偶:舍,5->前位數是奇:進) |
DOUBLE | bround(DOUBLE a, INT d) | 銀行家舍入法,保留d位小數 |
BIGINT | floor(DOUBLE a) | 對給定數據進行向下舍入最接近的整數 |
BIGINT | ceil(DOUBLE a) ceiling(DOUBLE a) | 將參數向上舍入為最接近的整數 |
DOUBLE | rand() rand(INT seed) | 返回大於或等於0且小於1的平均分布隨機數 |
DOUBLE | exp(DOUBLE a) exp(DECIMAL a) | 返回e的n次方 |
DOUBLE | ln(DOUBLE a) ln(DECIMAL a) | 返回給定數值的自然對數 |
DOUBLE | log10(DOUBLE a) log10(DECIMAL a) | 返回給定數值的以10為底自然對數 |
DOUBLE | log2(DOUBLE a) log2(DECIMAL a) | 返回給定數值的以2為底自然對數 |
DOUBLE | log(DOUBLE base, DOUBLE a) log(DECIMAL base, DECIMAL a) | 返回給定底數及指數返回自然對數 |
DOUBLE | pow(DOUBLE a, DOUBLE p) power(DOUBLE a, DOUBLE p) | 返回某數的乘冪 |
DOUBLE | sqrt(DOUBLE a) sqrt(DECIMAL a) | 返回數值的平方根 |
STRING | bin(BIGINT a) | 返回二進制格式 |
string | hex(BIGINT a) hex(STRING a) hex(BINARY a) | 將整數、字符或二進制轉換為十六進制格式 |
binary | unhex(STRING a) | 十六進制字符轉換由數字表示的字符。 |
string | conv(BIGINT num, INT from_base, INT to_base) conv(STRING num, INT from_base, INT to_base) | 將指定數值,由原來的度量體系轉換為指定的體系。例如CONV(‘a’,16,2),返回。參考:’1010′ |
double | abs(DOUBLE a) | 取絕對值 |
int or double | pmod(INT a, INT b) pmod(DOUBLE a, DOUBLE b) | 返回a除b的余數的絕對值 |
double | sin(DOUBLE a) sin(DECIMAL a) | 返回給定角度的正弦值 |
double | asin(DOUBLE a) asin(DECIMAL a) | 返回x的反正弦,即是X。如果X是在-1到1的正弦值,返回NULL。 |
double | cos(DOUBLE a) cos(DECIMAL a) | 返回余弦 |
double | acos(DOUBLE a) acos(DECIMAL a) | 返回X的反余弦,即余弦是X,,如果-1<= A <= 1,否則返回null. |
double | tan(DOUBLE a) tan(DECIMAL a) | 求正切值 |
double | atan(DOUBLE a) atan(DECIMAL a) | 求反正切值 |
double | degrees(DOUBLE a) degrees(DECIMAL a) | 將弧度值轉換角度值 |
double | radians(DOUBLE a) radians(DOUBLE a) | 將角度值轉換成弧度值 |
int or double | positive(INT a) positive(DOUBLE a) | 返回A的值,例如positive(2),返回2。 |
int or double | negative(INT a) negative(DOUBLE a) | 返回A的相反數,例如negative(2),返回-2。 |
double or int | sign(DOUBLE a) sign(DECIMAL a) | 如果a是正數則返回1.0,是負數則返回-1.0,否則返回0.0 |
double | e() | 數學常數e |
double | pi() | 數學常數pi |
BIGINT | factorial(INT a) | 求a的階乘 |
double | cbrt(DOUBLE a) | 求a的立方根 |
int bigint | shiftleft(TINYINT | SMALLINT | INT a, INT b) shiftleft(BIGINT a, INT b) | 按位左移 |
int bigint | shiftright(TINYINT | SMALLINT | INT a, INT b) shiftright(BIGINT a, INT b) | 按位右移 |
int bigint | shiftrightunsigned(TINYINT | SMALLINT | INT a, INT b) shiftrightunsigned(BIGINT a, INT b) | 無符號按位右移(<<<) |
T | greatest(T v1, T v2, …) | 求最大值 |
T | least(T v1, T v2, …) | 求最小值 |
9.2.2 集合函數
返回類型 | 函數名 | 描述 |
---|---|---|
int | size(Map<K.V>) | 返回Map的大小 |
int | size(Array<T>) | 返回Array的大小 |
array<K> | map_keys(Map<K.V>) | 返回Map的key集合 |
array<V> | map_values(Map<K.V>) | 返回Map的value集合 |
boolean | array_contains(Array<T>, value) | 返回Array是否包含value |
array<T> | sort_array(Array<T>) | 返回Array按自然順序升序排列后的數組 |
9.2.3 類型轉換函數
返回類型 | 函數名 | 描述 |
---|---|---|
binary | binary(string | binary) | 轉換參數為binary |
Expected “=” to follow “type” | cast(expr as <type>) | 轉換表達式expr為type類型,例如cast(‘1’ as BIGINT)。如果轉換不成功,則返回null;非空字符串轉換為boolean,返回true。 |
9.2.4 日期函數
返回類型 | 函數名 | 描述 |
---|---|---|
string | from_unixtime(bigint unixtime[, string format]) | 轉化UNIX時間戳(從1970-01-01 00:00:00 UTC到指定時間的秒數)到當前時區的時間格式 |
bigint | unix_timestamp() | 獲得當前時區的UNIX時間戳 |
bigint | unix_timestamp(string date) | 轉換格式為“yyyy-MM-dd HH:mm:ss“的日期到UNIX時間戳。如果轉化失敗,則返回0 |
bigint | unix_timestamp(string date, string pattern) | 轉換pattern格式的日期到UNIX時間戳。如果轉化失敗,則返回0。 |
pre 2.1.0: string 2.1.0 on: date | to_date(string timestamp) | 返回日期時間字段中的日期部分。 |
int | year(string date) | 返回日期中的年。 |
int | quarter(date/timestamp/string) | 返回第幾季(1.3.0開始) |
int | month(string date) | 返回日期中的月份 |
int | day(string date) dayofmonth(date) | 返回日期中的天 |
int | hour(string date) | 返回日期中的小時 |
int | minute(string date) | 返回日期中的分鍾 |
int | second(string date) | 返回日期中的秒 |
int | weekofyear(string date) | 返回日期在當前的周數 |
int | datediff(string enddate, string startdate) | 返回結束日期減去開始日期的天數 |
pre 2.1.0: string 2.1.0 on: date | date_add(string startdate, int days) | 返回開始日期startdate增加days天后的日期 |
pre 2.1.0: string 2.1.0 on: date | date_sub(string startdate, int days) | 返回開始日期startdate減少days天后的日期 |
timestamp | from_utc_timestamp(timestamp, string timezone) | 轉換UTC時間為指定時區的時間 |
timestamp | to_utc_timestamp(timestamp, string timezone) | 轉換指定時區的時間為UTC時間 |
date | current_date | 返回查詢時的日期 |
timestamp | current_timestamp | 返回查詢時的時間 |
string | add_months(string start_date, int num_months) | 返回當前時間下再增加num_months個月的日期,如果當前日期是最后一天,則計算后的日期也為最后一天 |
string | last_day(string date) | 返回這個月的最后一天的日期,忽略時分秒部分(HH:mm:ss) |
string | next_day(string start_date, string day_of_week) | 返回當前時間的下一個星期X所對應的日期。day_of_week是星期的2個、3個或整個單詞 (e.g. Mo, tue, FRIDAY). |
string | trunc(string date, string format) | 返回時間的最開始年份或月份 如trunc(“2016-06-26”,“MM”)=2016-06-01 trunc(“2016-06-26”,“YY”)=2016-01-01 注意所支持的格式為MONTH/MON/MM, YEAR/YYYY/YY |
double | months_between(date1, date2) | 返回date1與date2之間相差的月份,如date1>date2,則返回正,如果date1 |
string | date_format(date/timestamp/string ts, string fmt) | 按指定格式返回時間date 如:date_format(“2016-06-22”,”MM-dd”)=06-22 |
9.2.5 條件函數
返回類型 | 函數名 | 描述 |
---|---|---|
T | if(boolean testCondition, T valueTrue, T valueFalseOrNull) | testCondition為true,返回valueTrue,否則返回valueFalseOrNull |
boolean | isnull(a) | a為null時,返回true;否則返回false |
boolean | isnotnull (a) | a不為null時,返回true;否則返回false |
T | nvl(T value, T default_value) | value為null時,返回default_value,否則返回value |
T | COALESCE(T v1, T v2, …) | 返回第一個不為null的值,都為null時,返回null |
T | CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END | 類似switch |
T | CASE WHEN a THEN b [WHEN c THEN d]* [ELSE e] END | 類似if else語句 |
T | nullif(a, b) | a = b時,返回null,否則返回a |
9.2.6 字符串函數
返回類型 | 函數名 | 描述 |
---|---|---|
int | ascii(string str) | 返回str中首個ASCII字符串的整數值 |
string | base64(binary bin) | 將二進制bin轉換成base64的字符串 |
string | chr(bigint | double A) | 返回ASCII字符,大於256,則A%256 |
string | concat(string | binary A, string | binary B…) | 對二進制字節碼或字符串按次序進行拼接 |
array<struct<string,double>> | context_ngrams(array<array<string>>, array<string>, int K, int pf) | 與ngram類似,但context_ngram()允許你預算指定上下文(數組)來去查找子序列 |
string | concat_ws(string SEP, string A, string B…) | 與concat()類似,但使用指定的分隔符進行分隔 |
string | concat_ws(string SEP, array<string>) | 拼接Array中的元素並用指定分隔符進行分隔 |
string | decode(binary bin, string charset) | 使用指定的字符集charset將二進制值bin解碼成字符串,支持的字符集有:’US-ASCII’, ‘ISO-8859-1’, ‘UTF-8’, ‘UTF-16BE’, ‘UTF-16LE’, ‘UTF-16’,如果任意輸入參數為NULL都將返回NULL |
binary | encode(string src, string charset) | 使用指定的字符集charset將字符串編碼成二進制值,支持的字符集有:’US-ASCII’, ‘ISO-8859-1’, ‘UTF-8’, ‘UTF-16BE’, ‘UTF-16LE’, ‘UTF-16’,如果任一輸入參數為NULL都將返回NULL |
int | find_in_set(string str, string strList) | 返回以逗號分隔的字符串中str出現的位置,如果參數str為逗號或查找失敗將返回0,如果任一參數為NULL將返回NULL回 |
string | format_number(number x, int d) | 將數值X轉換成”#,###,###.##”格式字符串,並保留d位小數,如果d為0,將進行四舍五入且不保留小數 |
string | get_json_object(string json_string, string path) | 從指定路徑上的JSON字符串抽取出JSON對象,並返回這個對象的JSON格式,如果輸入的JSON是非法的將返回NULL,注意此路徑上JSON字符串只能由數字 字母 下划線組成且不能有大寫字母和特殊字符,且key不能由數字開頭,這是由於Hive對列名的限制 |
boolean | in_file(string str, string filename) | 如果文件名為filename的文件中有一行數據與字符串str匹配成功就返回true |
int | instr(string str, string substr) | 查找字符串str中子字符串substr出現的位置,如果查找失敗將返回0,如果任一參數為Null將返回null,注意位置為從1開始的 |
int | length(string A) | 返回字符串的長度 |
int | locate(string substr, string str[, int pos]) | 查找字符串str中的pos位置后字符串substr第一次出現的位置 |
string | lower(string A) lcase(string A) | 將字符串A的所有字母轉換成小寫字母 |
string | lpad(string str, int len, string pad) | 返回指定長度的字符串,給定字符串長度小於指定長度時,由指定字符從左側填補。 |
string | ltrim(string A) | 刪除字符串左邊的空格,其他的空格保留 |
array<struct<string,double>> | ngrams(array<array<string>>, int N, int K, int pf) | 返回出現次數TOP K的的子序列,n表示子序列的長度 |
string | parse_url(string urlString, string partToExtract [, string keyToExtract]) | 返回從URL中抽取指定部分的內容,參數url是URL字符串,而參數partToExtract是要抽取的部分,這個參數包含(HOST, PATH, QUERY, REF, PROTOCOL, AUTHORITY, FILE, and USERINFO,例如:parse_url(‘http://facebook.com/path1/p.php?k1=v1&k2=v2#Ref1‘, ‘HOST’) =’facebook.com’,如果參數partToExtract值為QUERY則必須指定第三個參數key 如:parse_url(‘http://facebook.com/path1/p.php?k1=v1&k2=v2#Ref1‘, ‘QUERY’, ‘k1’) =‘v1’ |
string | printf(String format, Obj… args) | 按照printf風格格式輸出字符串 |
string | regexp_extract(string subject, string pattern, int index) | 抽取字符串subject中符合正則表達式pattern的第index個部分的子字符串,注意些預定義字符的使用,如第二個參數如果使用’\s’將被匹配到s,’\\s’才是匹配空格 |
string | regexp_replace(string INITIAL_STRING, string PATTERN, string REPLACEMENT) | 按照Java正則表達式PATTERN將字符串INTIAL_STRING中符合條件的部分成REPLACEMENT所指定的字符串,如里REPLACEMENT這空的話,抽符合正則的部分將被去掉 如:regexp_replace(“foobar”, “oo|ar”, “”) = ‘fb.’ 注意些預定義字符的使用,如第二個參數如果使用’\s’將被匹配到s,’\\s’才是匹配空格 |
string | repeat(string str, int n) | 重復輸出n次字符串str |
string | replace(string A, string OLD, string NEW) | 置換字符串 |
string | reverse(string A) | 反轉字符串 |
string | rpad(string str, int len, string pad) | 從右邊開始對字符串str使用字符串pad填充,最終len長度為止,如果字符串str本身長度比len大的話,將去掉多余的部分 |
string | rtrim(string A) | 去掉字符串后面出現的空格 |
array<array<string>> | sentences(string str, string lang, string locale) | 字符串str將被轉換成單詞數組,如:sentences(‘Hello there! How are you?’) =( (“Hello”, “there”), (“How”, “are”, “you”) ) |
string | space(int n) | 返回n個空格 |
array | split(string str, string pat) | 按照正則表達式pat來分割字符串str,並將分割后的數組字符串的形式返回 |
map<string,string> | str_to_map(text[, delimiter1, delimiter2]) | 將字符串str按照指定分隔符轉換成Map,第一個參數是需要轉換字符串,第二個參數是鍵值對之間的分隔符,默認為逗號;第三個參數是鍵值之間的分隔符,默認為”=” |
string | substr(string | binary A, int start) substring(string | binary A, int start) | 對於字符串A,從start位置開始截取字符串並返回 |
string | substr(string | binary A, int start, int len) substring(string | binary A, int start, int len) | 對於二進制/字符串A,從start位置開始截取長度為length的字符串並返回 |
string | substring_index(string A, string delim, int count) | 截取第count分隔符之前的字符串,如count為正則從左邊開始截取,如果為負則從右邊開始截取 |
string | translate(string | char | varchar input, string | char | varchar from, string | char | varchar to) | 將input出現在from中的字符串替換成to中的字符串 如:translate(“MOBIN”,”BIN”,”M”)=”MOM” |
string | trim(string A) | 將字符串A前后出現的空格去掉 |
binary | unbase64(string str) | 將64位的字符串轉換二進制值 |
string | upper(string A) ucase(string A) | 將字符串A中的字母轉換成大寫字母 |
string | initcap(string A) | 將字符串A轉換第一個字母大寫其余字母的字符串 |
int | levenshtein(string A, string B) | 計算兩個字符串之間的差異大小 如:levenshtein(‘kitten’, ‘sitting’) = 3 |
string | soundex(string A) | 將普通字符串轉換成soundex字符串 |
9.2.7 數據脫敏函數(2.1.0新增)
返回類型 | 函數名 | 描述 |
---|---|---|
string | mask(string str[, string upper[, string lower[, string number]]]) | 默認大寫字母轉化為’X’,小寫字母轉換為’x’,數字轉換為“n”。通過參數可以修改掩碼,例如:mask(“abcd-EFGH-8765-4321”, “U”, “l”, “#”) 返回”llll-UUUU-####-####”. |
string | mask_first_n(string str[, int n]) | 轉換方式同上默認處理,只處理前n個字符。mask_first_n(“1234-5678-8765-4321”, 4)返回”nnnn-5678-8765-4321” |
string | mask_last_n(string str[, int n]) | 同上,但只處理最后n個字符 |
string | mask_show_first_n(string str[, int n]) | 只顯示前n個字符,其他同上 |
string | mask_show_last_n(string str[, int n]) | 只顯示最后n個字符,其他同上 |
string | mask_hash(string | char | varchar str) | 返回str的哈希值,可以用於表連接 |
9.2.8 其他函數
9.2.8.1 函數列表
返回類型 | 函數名 | 描述 |
---|---|---|
varies | java_method(class, method[, arg1[, arg2..]]) | 同反射 |
varies | reflect(class, method[, arg1[, arg2..]]) | 同反射 |
int | hash(a1[, a2…]) | 返回參數的哈希值 |
string | current_user() | 返回當前用戶 |
string | current_database() | 返回當前數據庫 |
string | md5(string/binary) | 返回MD5(128位校驗碼) |
string | sha1(string/binary) sha(string/binary) | 返回SHA-1摘要 |
bigint | crc32(string/binary) | 返回CRC |
string | sha2(string/binary, int) | 返回SHA-2,參數2: 224, 256, 384, 512, 或 0(=256)中的一個,表示SHA-224, SHA-256, SHA-384, SHA-512。base64(aes_encrypt(‘ABC’, ‘1234567890123456’)) = ‘y6Ss+zCYObpCbgfWfyNWTw==’. |
binary | aes_encrypt(input string/binary, key string/binary) | AES加密,key的長度必須是128、192或256位。aes_decrypt(unbase64(‘y6Ss+zCYObpCbgfWfyNWTw==’), ‘1234567890123456’) = ‘ABC’. |
binary | aes_decrypt(input binary, key string/binary) | AES解密 |
string | version() | 返回Hive版本(2.1.0) |
9.2.8.2 xpath
用於解析XML,javax.xml.xpath的封裝。基於XPath 1.0。
9.2.8.3 get_json_object
字符 | 含義 |
---|---|
& | 根 |
. | 子 |
[] | 數組下標 |
* | []的通配符 |
9.3 內置聚合函數(UDAF)
返回類型 | 函數名 | 描述 |
---|---|---|
BIGINT | count(*) | 統計總行數,包括含有NULL值的行 |
BIGINT | count(expr) | 統計提供非NULL的expr表達式值的行數 |
BIGINT | count(DISTINCT expr[, expr…]) | 統計提供非NULL且去重后的expr表達式值的行數 |
DOUBLE | sum(col) sum(DISTINCT col) | 求指定列的和 |
DOUBLE | avg(col) avg(DISTINCT col) | 求指定列的平均值 |
DOUBLE | min(col) | 求指定列的最小值 |
DOUBLE | max(col) | 求指定列的最大值 |
DOUBLE | variance(col) var_pop(col) | 求指定列數值的方差 |
DOUBLE | var_samp(col) | 求指定列數值的樣本方差 |
DOUBLE | stddev_pop(col) | 求指定列數值的標准偏差 |
DOUBLE | stddev_samp(col) | 求指定列數值的樣本標准偏差 |
DOUBLE | covar_pop(col1, col2) | 求指定列數值的協方差 |
DOUBLE | covar_samp(col1, col2) | 求指定列數值的樣本協方差 |
DOUBLE | corr(col1, col2) | 返回兩列數值的相關系數 |
DOUBLE | percentile(BIGINT col, p) | 返回數值區域的百分比數值點。0<=P<=1,否則返回NULL,不支持浮點型數值。 |
array<double> | percentile(BIGINT col, array(p1 [, p2]…)) | 返回數值區域的一組百分比值分別對應的數值點。0<=P<=1,否則返回NULL,不支持浮點型數值 |
DOUBLE | percentile_approx(DOUBLE col, p [, B]) | 求近似的第pth個百分位數,p必須介於0和1之間,返回類型為double,但是col字段支持浮點類型。參數B控制內存消耗的近似精度,B越大,結果的准確度越高。默認為10,000。當col字段中的distinct值的個數小於B時,結果為准確的百分位數 |
array<double> | percentile_approx(DOUBLE col, array(p1 [, p2]…) [, B]) | 功能和上述類似,之后后面可以輸入多個百分位數,返回類型也為array<double>,其中為對應的百分位數。 |
array<struct {‘x’,’y’}> | histogram_numeric(col, b) | 以b為基准計算col的直方圖信息。 |
array | collect_set(col) | 返回無重復記錄 |
array | collect_list(col) | 返回記錄list |
INTEGER | ntile(INTEGER x) | 用於將分組數據按照順序切分成n片,返回當前切片值 |
9.4 內置Table-Generating函數(UDTF)
9.4.1 函數列表
返回類型 | 函數名 | 描述 |
---|---|---|
N rows | explode(ARRAY) | 每行對應數組中的一個元素 |
N rows | explode(MAP) | 每行對應每個map鍵-值,其中一個字段是map的鍵,另一個字段是map的值 |
無 | inline(ARRAY<STRUCT[,STRUCT]>) | 將結構體數組提取出來並插入到表中 |
array | explode(array\ a) | 對於a中的每個元素,將生成一行且包含該元素 |
tuple | json_tuple(jsonStr, k1, k2, …) | 從一個JSON字符串中獲取多個鍵並作為一個元組返回,與get_json_object不同的是此函數能一次獲取多個鍵值 |
tuple | parse_url_tuple(url, p1, p2, …) | 返回從URL中抽取指定N部分的內容,參數url是URL字符串,而參數p1,p2,….是要抽取的部分,這個參數包含HOST, PATH, QUERY, REF, PROTOCOL, AUTHORITY, FILE, USERINFO, QUERY:\ |
N rows | posexplode(ARRAY) | 與explode類似,不同的是還返回各元素在數組中的位置 |
N rows | stack(INT n, v_1, v_2, …, v_k) | 把v_1, v_2, …, v_k轉換成N行,每行有M/N個字段,其中n必須是個常數 |
限制: 1. SELECT里面不能有其它字段; 2. 不能嵌套; 3. 不支持GROUP BY / CLUSTER BY / DISTRIBUTE BY / SORT BY。
9.5 GROUPing與SORTing
函數的別名不能用於group by或sort by,例如下面例子
select f(col) as fc, count(*) from table_name group by fc;
- 1
- 1
有兩種變通方法: 1. 使用子查詢; 2. 在group by或sort by中使用函數。
9.6 自定義函數
9.6.1 步驟
- 繼承UDF、UDAF或UDTF,實現特定方法;
- 將寫好的類打包為jar。例如hive-demo.jar;
- 進入Hive外殼環境中,利用add jar /home/zkpk/doc/hive/hive-demo.jar注冊該jar文件;
- 為該類起別名,create temporary function mylength as ‘com.whut.StringLength’; 注意,只是會話臨時定義。
- 使用mylength。
9.6.2 UDF
操作單個數據行,產生單個數據行;
package com.zw.hive.w4; import org.apache.hadoop.hive.ql.exec.UDF; /** * * 計算src中包含word的個數 * * <p> * UDF是作用於單個數據行,產生一個數據行; * 用戶必須要繼承UDF,且必須至少實現一個evalute方法,該方法並不在UDF中 * 但是Hive會檢查用戶的UDF是否擁有一個evalute方法 * </p> * * Created by zhangws on 16/8/27. */ public class CountSpecifyWordUDF extends UDF { /** * 計算src中包含word的個數 * @param src src * @param word word * @return counter */ public int evaluate(String src, String word) { try { int counter=0; if (!src.contains(word)) { return 0; } int pos; while((pos = src.indexOf(word)) != -1){ counter++; src = src.substring(pos + word.length()); } return counter; } catch (Exception e) { return 0; } } }
- 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
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 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
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
9.6.3 UDAF
操作多個數據行,產生一個數據行。
編寫通用型UDAF需要兩個類:解析器和計算器。
9.6.3.1 解析器
負責UDAF的參數檢查,操作符的重載以及對於給定的一組參數類型來查找正確的計算器。繼承AbstractGenericUDAFResolver。
package com.zw.hive.w4.udaf; import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException; import org.apache.hadoop.hive.ql.parse.SemanticException; import org.apache.hadoop.hive.ql.udf.generic.AbstractGenericUDAFResolver; import org.apache.hadoop.hive.ql.udf.generic.GenericUDAFEvaluator; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo; /** * 計算分組中的最大值(獲取計算器) * <pre> * <code> * add jar /home/zkpk/doc/hive-demo.jar; * CREATE TEMPORARY FUNCTION collectList AS 'com.zw.hive.w4.udaf.CollectListUDAFResolver'; * * * 數據准備(udaf_demo_data_1) * 1,a * 1,a * 1,b * 2,c * 2,d * 2,d * 創建表 create external table hive_udaf_data_1 ( id int, value string ) comment 'UDAF演示表' row format delimited fields terminated by ',' stored as textfile location '/hw/hive/udaf/1'; * * 加載數據 * load data local inpath '/home/zkpk/doc/hive/udaf_demo_data_1' overwrite into table hive_udaf_data_1; * * 執行SQL * SELECT id, collectList(value) FROM hive_udaf_data_1 GROUP BY id; * </code> * </pre> * <p> * Created by zhangws on 16/9/18. */ public class CollectListUDAFResolver extends AbstractGenericUDAFResolver { /** * 返回計算器 * * @param parameters * * @return * * @throws SemanticException */ @Override public GenericUDAFEvaluator getEvaluator(TypeInfo[] parameters) throws SemanticException { if (parameters.length != 1) { throw new UDFArgumentTypeException(parameters.length - 1, "Exactly one argument is expected."); } if (parameters[0].getCategory() != ObjectInspector.Category.PRIMITIVE) { throw new UDFArgumentTypeException(0, "Only primitive type arguments are accepted."); } return new CollectListUDAFEvaluator(); } }
- 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
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 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
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
9.6.3.2 計算器
計算器實現具體的計算邏輯,需要繼承GenericUDAFEvaluator抽象類。 計算器有4種模式,由枚舉類GenericUDAFEvaluator.Mode定義:
public static enum Mode { PARTIAL1, //從原始數據到部分聚合數據的過程(map階段),將調用iterate()和terminatePartial()方法。 PARTIAL2, //從部分聚合數據到部分聚合數據的過程(map端的combiner階段),將調用merge() 和terminatePartial()方法。 FINAL, //從部分聚合數據到全部聚合的過程(reduce階段),將調用merge()和 terminate()方法。 COMPLETE //從原始數據直接到全部聚合的過程(表示只有map,沒有reduce,map端直接出結果),將調用merge() 和 terminate()方法。 };
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
計算器必須實現的方法: 1、getNewAggregationBuffer():返回存儲臨時聚合結果的AggregationBuffer對象。 2、reset(AggregationBuffer agg):重置聚合結果對象,以支持mapper和reducer的重用。 3、iterate(AggregationBuffer agg,Object[] parameters):迭代處理原始數據parameters並保存到agg中。 4、terminatePartial(AggregationBuffer agg):以持久化的方式返回agg表示的部分聚合結果,這里的持久化意味着返回值只能Java基礎類型、數組、基礎類型包裝器、Hadoop的Writables、Lists和Maps。 5、merge(AggregationBuffer agg,Object partial):合並由partial表示的部分聚合結果到agg中。 6、terminate(AggregationBuffer agg):返回最終結果。
通常還需要覆蓋初始化方法ObjectInspector init(Mode m,ObjectInspector[] parameters)。
示例
package com.zw.hive.w4.udaf; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.apache.hadoop.hive.ql.metadata.HiveException; import org.apache.hadoop.hive.ql.udf.generic.GenericUDAFEvaluator; import org.apache.hadoop.hive.serde2.objectinspector.*; import org.apache.hadoop.io.Text; import java.util.Collections; import java.util.List; import java.util.Map; /** * 實現按分組中元素的出現次數降序排序,並將每個元素的在分組中的出現次數也一起返回,格式為:[data1, num1, data2, num2, ...] * <p> * Created by zhangws on 16/9/19. */ public class CollectListUDAFEvaluator extends GenericUDAFEvaluator { protected PrimitiveObjectInspector inputKeyOI; protected StandardListObjectInspector loi; protected StandardListObjectInspector internalMergeOI; /** * <pre> * <code> * m: * PARTIAL1 和 COMPLETE 時, parameters為原始數據; * PARTIAL2 和 FINAL 時, parameters僅為部分聚合數據(只有一個元素) * * PARTIAL1 和 PARTIAL2 時, terminatePartial方法的返回值; * FINAL 和 COMPLETE 時, terminate方法的返回值. * </code> * </pre> * * @param m 模式 * @param parameters 數據參數 * * @return * * @throws HiveException */ @Override public ObjectInspector init(Mode m, ObjectInspector[] parameters) throws HiveException { super.init(m, parameters); if (m == Mode.PARTIAL1) { // 從原始數據到部分聚合數據的過程(map階段),將調用iterate()和terminatePartial()方法。 inputKeyOI = (PrimitiveObjectInspector) parameters[0]; return ObjectInspectorFactory.getStandardListObjectInspector( ObjectInspectorUtils.getStandardObjectInspector(inputKeyOI)); } else { if (parameters[0] instanceof StandardListObjectInspector) { internalMergeOI = (StandardListObjectInspector) parameters[0]; inputKeyOI = (PrimitiveObjectInspector) internalMergeOI.getListElementObjectInspector(); loi = (StandardListObjectInspector) ObjectInspectorUtils.getStandardObjectInspector(internalMergeOI); return loi; } else { inputKeyOI = (PrimitiveObjectInspector) parameters[0]; return ObjectInspectorFactory.getStandardListObjectInspector( ObjectInspectorUtils.getStandardObjectInspector(inputKeyOI)); } } } static class MkListAggregationBuffer extends AbstractAggregationBuffer { List<Object> container = Lists.newArrayList(); } /** * 返回存儲臨時聚合結果的AggregationBuffer對象。 */ @Override public AggregationBuffer getNewAggregationBuffer() throws HiveException { return new MkListAggregationBuffer(); } /** * 重置聚合結果對象,以支持mapper和reducer的重用。 * * @param agg */ @Override public void reset(AggregationBuffer agg) throws HiveException { ((MkListAggregationBuffer) agg).container.clear(); } /** * 迭代處理原始數據parameters並保存到agg中。 * * @param agg * @param parameters 原始數據 */ @Override public void iterate(AggregationBuffer agg, Object[] parameters) throws HiveException { if (parameters == null || parameters.length != 1) { return; } Object key = parameters[0]; if (key != null) { MkListAggregationBuffer myagg = (MkListAggregationBuffer) agg; putIntoList(key, myagg.container); } } private void putIntoList(Object key, List<Object> container) { Object pCopy = ObjectInspectorUtils.copyToStandardObject(key, this.inputKeyOI); container.add(pCopy); } /** * 以持久化的方式返回agg表示的部分聚合結果,這里的持久化意味着返回值只能Java基礎類型、數組、 * 基礎類型包裝器、Hadoop的Writables、Lists和Maps。 * * @param agg * * @return partial aggregation result. */ @Override public Object terminatePartial(AggregationBuffer agg) throws HiveException { MkListAggregationBuffer myagg = (MkListAggregationBuffer) agg; return Lists.newArrayList(myagg.container); } /** * 合並由partial表示的部分聚合結果到agg中。 * * @param agg * @param partial */ @Override public void merge(AggregationBuffer agg, Object partial) throws HiveException { if (partial == null) { return; } MkListAggregationBuffer myagg = (MkListAggregationBuffer) agg; List<Object> partialResult = (List<Object>) internalMergeOI.getList(partial); for (Object ob : partialResult) { putIntoList(ob, myagg.container); } } /** * 返回最終結果。 * * @param agg * * @return final aggregation result. */ @Override public Object terminate(AggregationBuffer agg) throws HiveException { MkListAggregationBuffer myagg = (MkListAggregationBuffer) agg; Map<Text, Integer> map = Maps.newHashMap(); // 統計相同值得個數 for (int i = 0; i < myagg.container.size(); i++) { Text key = (Text) myagg.container.get(i); if (map.containsKey(key)) { map.put(key, map.get(key) + 1); } else { map.put(key, 1); } } // 排序 List<Map.Entry<Text, Integer>> listData = Lists.newArrayList(map.entrySet()); Collections.sort(listData, (o1, o2) -> { if (o1.getValue() < o2.getValue()) return 1; else if (o1.getValue().equals(o2.getValue())) return 0; else return -1; }); // 合並輸出 List<Object> ret = Lists.newArrayList(); for (Map.Entry<Text, Integer> entry : listData) { ret.add(entry.getKey()); ret.add(new Text(entry.getValue().toString())); } return ret; } }
- 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
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 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
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
結果
1 ["a","2","b","1"] 2 ["d","2","c","1"]
- 1
- 2
- 1
- 2
9.6.4 UDTF
操作一個數據行,產生多個數據行一個表作為輸出。
- 繼承org.apache.hadoop.hive.ql.udf.generic.GenericUDTF,實現initialize, process, close三個方法。
- UDTF首先會調用initialize方法,此方法返回UDTF的返回行的信息(返回個數,類型)。
- 初始化完成后,會調用process方法,真正的處理過程在process函數中,在process中,每一次forward()調用產生一行;如果產生多列可以將多個列的值放在一個數組中,然后將該數組傳入到forward()函數。
- 最后close()方法調用,對需要清理的方法進行清理。
示例: 將字符串(key1:20;key2:30;key3:40)按照分好拆分行按照冒號拆分列進行展示。
package com.zw.hive.w4.udtf; import org.apache.hadoop.hive.ql.exec.UDFArgumentException; import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException; import org.apache.hadoop.hive.ql.metadata.HiveException; import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory; import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory; import java.util.ArrayList; /** * * <p> * 1. 繼承org.apache.hadoop.hive.ql.udf.generic.GenericUDTF,實現initialize, process, close三個方法。 * 2. UDTF首先會調用initialize方法,此方法返回UDTF的返回行的信息(返回個數,類型)。 * 3. 初始化完成后,會調用process方法,真正的處理過程在process函數中,在process中,每一次forward()調用產生一行; * 如果產生多列可以將多個列的值放在一個數組中,然后將該數組傳入到forward()函數。 * 4. 最后close()方法調用,對需要清理的方法進行清理。 * 5. 代碼實例,實現的功能比較簡單,將字符串(key1:20;key2:30;key3:40)按照分好拆分行按照冒號拆分列進行展示。 * </p> * * <pre> * <code> * hive-demo.jar放到${HIVE_HOME}/auxli目錄下 * CREATE TEMPORARY FUNCTION explode_map AS 'com.zw.hive.w4.udtf.ExplodeMapUDTF'; * * 准備數據(hive_udtf_demo_data_1) * key1:20;key2:30;key3:40 * create external table udtf_demo_data_1 ( value string ); * 加載數據 * load data local inpath '/home/zkpk/doc/hive/udtf_demo_data_1' overwrite into table udtf_demo_data_1; * * SELECT explode_map(value) AS (col1,col2) from udtf_demo_data_1; * </code> * </pre> * * Created by zhangws on 16/9/18. */ public class ExplodeMapUDTF extends GenericUDTF { /** * 返回UDTF的返回行的信息(返回個數,類型) * @param args * @return * @throws UDFArgumentException */ @Override public StructObjectInspector initialize(ObjectInspector[] args) throws UDFArgumentException { if (args.length != 1) { throw new UDFArgumentLengthException("ExplodeMap takes only one argument"); } if (args[0].getCategory() != ObjectInspector.Category.PRIMITIVE) { throw new UDFArgumentException("ExplodeMap takes string as a parameter"); } ArrayList<String> fieldNames = new ArrayList<String>(); ArrayList<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>(); fieldNames.add("col1"); fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector); fieldNames.add("col2"); fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector); return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs); } /** * 每一次forward()調用產生一行;如果產生多列可以將多個列的值放在一個數組中,然后將該數組傳入到forward()函數。 * @param args * @throws HiveException */ @Override public void process(Object[] args) throws HiveException { String input = args[0].toString(); String[] test = input.split(";"); for (String aTest : test) { try { String[] result = aTest.split(":"); forward(result); } catch (Exception e) { // nothing } } } /** * 對需要清理的方法進行清理。 * @throws HiveException */ @Override public void close() throws HiveException { } }
- 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
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 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
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
結果
hive> CREATE TEMPORARY FUNCTION explode_map AS 'com.zw.hive.w4.udtf.ExplodeMapUDTF'; OK Time taken: 0.02 seconds hive> SELECT explode_map(value) AS (col1,col2) from udtf_demo_data_1; OK key1 20 key2 30 key3 40
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
9.6.5 添加自定義函數的jar文件
-
使用add path/test.jar 缺點是每次啟動Hive的時候都要新加入。
-
配置hive-site.xml加入
<property> <name>hive.aux.jars.path</name> <value>file:///jarpath/all_new1.jar,file:///jarpath/all_new2.jar</value> </property>
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
-
在${HIVE_HOME}中創建文件夾auxlib,然后將自定義jar文件放入該文件夾中。
9.6.6 調試
-
以debug模式啟動Cli,${HIVE_HOME}/bin/hive –debug。進程會監聽在8000端口等待調試連接。如果想更改監聽端口,可以修改配置文件:
${HIVE_HOME}bin/ext/debug.sh 。
- 1
- 1
-
在Eclipse中, 選擇Debug configurations->Remote Java Application,填好Host和Port,並選中包含UDF的工程,確定。
-
在idea中,選擇Remote,修改host與port,確定。
9.6.7 參考
Hive中添加自定義udf udaf udtf等函數的jar文件的三種方法
9.7 參考
10 Locks
11 Authorization
12 Hive HPL/SQL
13 Hive Configuration Properties
14 參考