背景:表中有一個降水強度字段滨砍,但是并不是真實的降雨量,后來數(shù)據(jù)模型的同事給了一個python腳本妖异,按照腳本可以大體轉(zhuǎn)換成降雨量惋戏。
思路:
1.想過用 python 現(xiàn)將表中的數(shù)查出來放到文件中,然后在用給的python邏輯對降水強度字段進行處理他膳,最后在加載進表中响逢。 但是這樣太麻煩了。
2.也想過用給的python腳本查出一些數(shù)值棕孙,然后建立一個數(shù)學(xué)模型舔亭,找出一個計算關(guān)系。最后因為自己非數(shù)學(xué)專業(yè)散罕,也不是專業(yè)分析人員分歇,放棄了該想法。
3.最后欧漱,突然想到职抡,是不是能像 udf 函數(shù)一樣,將這段python 代碼误甚,也當做一個 udf 函數(shù)嵌到 sql 中呢缚甩。
看來解決問題,思路還是最重要窑邦,什么樣的思路決定了解決方法擅威,決定了最后的難易程度。
這是我原本的 sql冈钦,現(xiàn)在 intensity 字段需要用給定的python邏輯進行一個加工郊丛。
select
cityid,
city_name,
di_cityid,
substr(server_time1,1,14) as server_time1,
intensity as intensity,
temperature as temperature,
round((wind_speed / 36),2) as wind_speed
from tablename
where concat(year,month,day) = '${DT}'
and di_cityid in (9,11,17,47,95)
and intensity < 1
這是拿到的轉(zhuǎn)換代碼。我在里面加了些注釋瞧筛。
def intense2dbz(intn):
val = (intn + 0.15) * 16.0 * 5
# 當val>70厉熟,return 70*val 。 當val <= 70较幌,返回val * val 因為True 和 False 在python 計算中就代表 1 和 0
return 70 * (val > 70) + val * (val <= 70)
def radar2precip_metric(radar):
dbz = intense2dbz(radar)
# power(a,b) --> a的b次方
val = np.power(np.power(10.0, dbz / 10.0) / 200, 5.0 / 8.0)
val = val - 0.2051
return val * (val > 0)
ok揍瑟,下面是根據(jù)給的轉(zhuǎn)換方法寫的 udf 函數(shù)代碼:
# -*- coding:utf-8 -*-
import numpy as np
import sys
def intense2dbz(intn):
val = (intn + 0.15) * 16.0 * 5
return 70 * (val > 70) + val * (val <= 70)
def radar2precip_metric(radar):
dbz = intense2dbz(radar)
val = np.power(np.power(10.0, dbz / 10.0) / 200, 5.0 / 8.0)
val = val - 0.2051
return val * (val > 0)
if __name__ == "__main__":
#循環(huán)讀取每一行數(shù)據(jù)。
for line in sys.stdin:
# 去掉每一行后面的 \n
line = line.strip()
# 這里應(yīng)該要把所有的字段都列出來乍炉,因為你讀了一行的數(shù)據(jù)绢片,其實包含了所有的字段滤馍。split('\t')應(yīng)該要源表的分隔符一致。
cityid,city_name,di_cityid,server_time1,intensity,temperature,wind_speed = line.split("\t")
# 相關(guān)字段進行相關(guān)操作底循。
new_server_time1 = server_time1[0:14]
new_wind_speed = round((float(wind_speed) / 36),2)
new_intensity = abs(radar2precip_metric(float(intensity)))
#最后輸出新的所有的字段巢株。
print("\t".join([cityid,city_name,didi_cityid,new_server_time1,str(new_intensity),temperature,str(new_wind_speed)]))
下面是在 hive 里使用上述文件:
-- 首先是添加文件,java需要一個jar包此叠。python就是一個py文件纯续。 我這是hdfs 上面的相對路徑。絕對路徑也可以灭袁。
add file ./intensity.py;
select
transform(cityid,city_name,di_cityid,server_time1,intensity,temperature,wind_speed)
using 'python intensity.py'
as (cityid,city_name,di_cityid,server_time1,intensity,temperature,wind_speed)
from tablename
where concat(year,month,day) = '${DT}'
and di_cityid in (9,11,17,47,95)
and intensity < 1
transform 是關(guān)鍵字猬错,將原本的字段全都放進去,然后 using 添加后的 python文件茸歧,最后返回新的字段倦炒。
這里,傳遞進去的字段的數(shù)量软瞎,和最后生成的字段數(shù)量不一定相同逢唤。可能一個字段在python腳本中分解成多個字段涤浇,也可能多個字段最后加工成了一個字段鳖藕。
但是如果想:
select cityid,city_name,transform(intensity) using 'python intensity.py' as intensity,.....
這樣我試過,是不行的只锭。
另外著恩,在實際操作中發(fā)現(xiàn)了兩個問題:
1.最后python文件返回必須是 str 類型,所有我在代碼中蜻展,都強轉(zhuǎn)了 str 類型喉誊。
2.承接上一條,使用了python文件后纵顾,你的字段類型也就變成了 str 類型伍茄。這時候在求最大值這種需要注意,你還要在轉(zhuǎn)回數(shù)值類型施逾,否則求出來的最大值就不準確敷矫。貌似hive 沒法自動識別出來你這個字符串類型的字段中,實際上都是數(shù)值類型的值汉额。
第一次使用 python 文件嵌入到hive 中使用沪饺,如果不是碰到這個問題,還不知道有這種操作闷愤。欠缺的地方還很多,歡迎各位指正件余,期待大神指教一二讥脐。