2023-02-23
scores
Python實現UDF函數的邏輯
Hive中使用Python自定義函數的時候,其實是一個重定向輸入的過程。將表中的指定的列逐行讀取,我們在Python的腳本中就可以依次對每一行的數據進行處理。
import sys
# sys.stdin: 標準輸入流,我們使用的input()函數,其實就是stdin的一個方法。
# hive執行自定義函數的時候,會逐行讀取指定列的內容,我們就可以使用循環依次處理讀取到的每一行的數據。
for line in sys.stdin:
# 讀取到的這一行的數據,其中包含了若干個列,列于列之間以\t進行分隔
# 切割出來每一個列
columns = line.strip().split('\t')
# 對列進行處理
# 處理之后的結果,使用print直接打印即可
# 如果需要返回多個列,多個列之間需要使用\t進行分隔
print('hello world')
在使用UDF的時候,需要按照如下的步驟
# 1. 加載腳本文件
add file <腳本文件>
# 2. 執行腳本,執行Python的UDF函數的時候,只能使用transform函數
select transform(<字段>) using 'python3 <腳本文件>' as (<字段列表>) from <表>
自定義UDF函數案例
案例一:將字母轉成全部大寫
# 1. 準備數據文件
zhangsan,male,19
lisi,female,20
wangwu,male,18
zhaoliu,female,19
# 2. 創建數據表
create table if not exists example_01(
t_name string,
t_gender string,
t_age int
)
row format delimited
fields terminated by ',';
需求:將所有的列都轉成大寫
# -*- coding: utf-8 -*-
# @Author : 大數據章魚哥
# @Company : 北京千鋒互聯科技有限公司
# string_upper.py
import sys
for line in sys.stdin:
print(line.upper(), end='')
-- 應用UDF
add file string_upper.py
-- 查詢名字,將其轉成大寫
select transform(t_name) using 'python3 string_upper.py' as (t_name) from example_01;
-- 查詢名字、性別,將其轉成大寫
select transform(t_name, t_gender) using 'python3 string_upper.py' as (t_name, t_gender) from example_01;
需求:只需要將姓名轉成大寫
# -*- coding: utf-8 -*-
# @Author : 大數據章魚哥
# @Company : 北京千鋒互聯科技有限公司
# string_name_upper.py
import sys
for line in sys.stdin:
# 1. 切割出來每一列
columns = line.strip().split('\t')
# 2. 判斷切割出來的列的數量,如果數量不正確,這一行數據不處理
length = len(columns)
name = columns[0].upper() if length >= 1 else 'NULL'
gender = columns[1] if length >= 2 else 'NULL'
age = columns[2] if length >= 3 else 'NULL'
# 3. 打印處理之后的結果
print('\t'.join([name, gender, age]))
-- 查詢所有字段,將名字轉成大寫
select transform(*) using 'python3 string_name_upper.py' as (name, gender, age) from example_01;
+-----------+---------+------+
| name | gender | age |
+-----------+---------+------+
| ZHANGSAN | male | 19 |
| LISI | female | 20 |
| WANGWU | male | 18 |
| ZHAOLIU | female | 19 |
+-----------+---------+------+
案例二:身份證解析
# 1. 準備數據文件
張三三,410023198911223344
李思思,110011200210103232
汪嗚嗚,37126520000223987X
趙溜溜,561276199512019866
# 2. 準備數據表
create table if not exists example_02(
username string,
idcard string
)
row format delimited
fields terminated by ',';
需求:通過表中的數據,查詢出 姓名、身份證號、出生年月日、年齡、性別
# -*- coding: utf-8 -*-
# @Author : 大數據章魚哥
# @Company : 北京千鋒互聯科技有限公司
# 身份證驗證
# 如果身份證不是一個合法的身份證,輸出空
# 如果身份證是合法的,解析出年齡、生日、性別
import sys
import re
import datetime
def calculate_age(year, month, day):
now = datetime.datetime.now()
age = now.year - year
if now.month < month:
age -= 1
elif now.month == month and now.day < day:
age -= 1
return age
for line in sys.stdin:
# 1. 切割出來每一個組成部分
fields = line.strip().split('\t')
# 2. 如果長度不到兩位,說明數據有問題,不做任何處理
if len(fields) != 2:
continue
# 3. 提取姓名和身份證
name = fields[0]
id_card = fields[1]
# 4. 身份證正則匹配
m = re.fullmatch(r'(\d{6})(?P<year>(19|20)\d{2})(?P<month>0[1-9]|1[0-2])(?P<day>[012][0-9]|10|20|30|31)\d{2}(?P<gender>\d)[0-9xX]', id_card)
if m is None:
print('\t'.join([name, id_card, 'NULL', 'NULL', 'NULL']))
else:
# 出生年月日
year = m.group('year')
month = m.group('month')
day = m.group('day')
age = calculate_age(int(year), int(month), int(day))
# 計算性別
gender = '男' if int(m.group('gender')) % 2 != 0 else '女'
# 拼接生日
birthday = f'{year}-{month}-{day}'
print('\t'.join([name, id_card, birthday, str(age), gender]))
-- 添加文件
add file idcard_parser.py
-- 執行查詢
select transform(*) using 'python3 idcard_parser.py' as (name, idcard, birthday, age, gender) from example_02
+-------+---------------------+-------------+------+---------+
| name | idcard | birthday | age | gender |
+-------+---------------------+-------------+------+---------+
| 張三三 | 410023198911223344 | 1989-11-22 | 33 | 女 |
| 李思思 | 110011200210103232 | 2002-10-10 | 20 | 男 |
| 汪嗚嗚 | 37126520000223987X | 2000-02-23 | 22 | 男 |
| 趙溜溜 | 561276199512019866 | 1995-12-01 | 27 | 女 |
+-------+---------------------+-------------+------+---------+
案例三:自定義聚合函數
# 準備數據
zhangsan,89
lisi,67
wangwu,55
zhaoliu,78
tianqi,92
# 建立數據表
create table if not exists example_03(
name string,
score int
)
row format delimited
fields terminated by ',';
需求:通過表中的數據,統計出學生的人數、總成績、最高成績、最低成績、平均成績、及格率
# -*- coding: utf-8 -*-
# @Author : 大數據章魚哥
# @Company : 北京千鋒互聯科技有限公司
import sys
scores = []
for line in sys.stdin:
scores.append(int(line.strip()))
# 計算人數
count = len(scores)
# 計算總成績
sum_score = sum(scores)
# 計算最高成績
max_score = max(scores)
# 計算最低成績
min_score = min(scores)
# 計算平均成績
avg_score = sum_score / count
# 計算及格率
rate = len(list(filter(lambda x: x >= 60, scores))) / count
# 輸出最后的結果
print('\t'.join(map(lambda x: str(x), [count, sum_score, max_score, min_score, avg_score, rate])))
案例四:自定義展開函數
# 1. 準備數據
zhangsan 78,89,92,96
lisi 67,75,83,94
王五 23,12
# 2. 建立數據表
create table if not exists example_04(
name string,
scores array
)
row format delimited
fields terminated by ' '
collection items terminated by ','
;
需求:根據表中的數據,將每一個成績展開,綁定給每一個名字
# -*- coding: utf-8 -*-
# @Author : 大數據章魚哥
# @Company : 北京千鋒互聯科技有限公司
import sys
for line in sys.stdin:
fields = line.strip().split('\t')
if len(fields) != 2:
continue
# 提取名字
name = fields[0]
# 提取所有成績
scores = fields[1].strip('[').rstrip(']').split(',')
for s in scores:
print("\t".join([name, s]))
開班時間:2021-04-12(深圳)
開班盛況開班時間:2021-05-17(北京)
開班盛況開班時間:2021-03-22(杭州)
開班盛況開班時間:2021-04-26(北京)
開班盛況開班時間:2021-05-10(北京)
開班盛況開班時間:2021-02-22(北京)
開班盛況開班時間:2021-07-12(北京)
預約報名開班時間:2020-09-21(上海)
開班盛況開班時間:2021-07-12(北京)
預約報名開班時間:2019-07-22(北京)
開班盛況Copyright 2011-2023 北京千鋒互聯科技有限公司 .All Right 京ICP備12003911號-5 京公網安備 11010802035720號