Hive中使用Python文件實(shí)現(xiàn)UDF

背景:表中有一個降水強(qiáng)度字段,但是并不是真實(shí)的降雨量,后來數(shù)據(jù)模型的同事給了一個python腳本,按照腳本可以大體轉(zhuǎn)換成降雨量。
思路:
1.想過用 python 現(xiàn)將表中的數(shù)查出來放到文件中,然后在用給的python邏輯對降水強(qiáng)度字段進(jìn)行處理,最后在加載進(jìn)表中。 但是這樣太麻煩了。
2.也想過用給的python腳本查出一些數(shù)值,然后建立一個數(shù)學(xué)模型,找出一個計算關(guān)系。最后因?yàn)樽约悍菙?shù)學(xué)專業(yè),也不是專業(yè)分析人員,放棄了該想法。
3.最后,突然想到,是不是能像 udf 函數(shù)一樣,將這段python 代碼,也當(dāng)做一個 udf 函數(shù)嵌到 sql 中呢。
看來解決問題,思路還是最重要,什么樣的思路決定了解決方法,決定了最后的難易程度。

這是我原本的 sql,現(xiàn)在 intensity 字段需要用給定的python邏輯進(jìn)行一個加工。

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
    # 當(dāng)val>70,return 70*val 。 當(dāng)val <= 70,返回val * val 因?yàn)門rue 和 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)該要把所有的字段都列出來,因?yàn)槟阕x了一行的數(shù)據(jù),其實(shí)包含了所有的字段。split('\t')應(yīng)該要源表的分隔符一致。
        cityid,city_name,di_cityid,server_time1,intensity,temperature,wind_speed = line.split("\t")
        # 相關(guān)字段進(jì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)鍵字,將原本的字段全都放進(jìn)去,然后 using 添加后的 python文件,最后返回新的字段。
這里,傳遞進(jìn)去的字段的數(shù)量,和最后生成的字段數(shù)量不一定相同??赡芤粋€字段在python腳本中分解成多個字段,也可能多個字段最后加工成了一個字段。
但是如果想:
select cityid,city_name,transform(intensity) using 'python intensity.py' as intensity,.....
這樣我試過,是不行的。

另外,在實(shí)際操作中發(fā)現(xiàn)了兩個問題:
1.最后python文件返回必須是 str 類型,所有我在代碼中,都強(qiáng)轉(zhuǎn)了 str 類型。
2.承接上一條,使用了python文件后,你的字段類型也就變成了 str 類型。這時候在求最大值這種需要注意,你還要在轉(zhuǎn)回數(shù)值類型,否則求出來的最大值就不準(zhǔn)確。貌似hive 沒法自動識別出來你這個字符串類型的字段中,實(shí)際上都是數(shù)值類型的值。

第一次使用 python 文件嵌入到hive 中使用,如果不是碰到這個問題,還不知道有這種操作。欠缺的地方還很多,歡迎各位指正,期待大神指教一二。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容