1. 程式人生 > >【hive】從url中提取需要的部分字串

【hive】從url中提取需要的部分字串

本人菜鳥一隻,如果有什麼說錯的地方還請大家批評指出!!

事情是這樣的,hive的A表中,有url這樣的一個欄位,我想要提取這個欄位中的某一部分(這不就是擷取字串嘛)。但是substring肯定是滿足不了我的需求的,自己寫hive的udf也不太現實(用最簡單的方式完成任務,才會讓後來的維護變得更加方便,否則除了維護sql還要維護一堆udf,那才叫可怕)。因此我初步的想法就是正則!然後經過同事的提醒,我知道了hive有自帶函式可以處理url,所以我來總結下三種方案! 

url格式是這樣的(我想要獲取group_id=後面的數字): 

/wenzhang/v1/XXX/?fold=1&offset=0&group_id=6594293942836003076&tab_index=0&count=20&(後面還有一大堆雜七雜八的東西)

方法一:通過正則獲得字串(hive處理正則的函式regexp_extract)

先說一句hive自帶函式的官方網站:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF

正則中有個叫零寬斷言的東西,大概說的就是取某個字串的前面的字元,或者取後面的字元

題外話:

有個我覺得不錯的學習歸納正則網站:https://www.jb51.net/tools/zhengze.html

然後大家可以去這個頁面上試試正則:http://tool.chinaz.com/regex/

有一點提醒下大家,每個框架(不同開發語言,不同資料庫)支援的正則並不是完全一樣的,所以測試非常重要,不要拿了別人寫的東西就直接用,有很大機率是不成功的!

推薦一款工具:RegexBuddy(圖表是一個貓頭鷹),用來測試不同環境下的正則的~

言歸正傳:

所以我寫出的正則規則是這樣:(?<=group_id=)\d{1,}

意思就是匹配group_id=這串字串後面的1到無窮多個數字(實際測試可行)

那麼hive中,應該如何來寫這個正則呢?

其實又有點不一樣,如下圖:

select split(regexp_extract(split(url,'/')[4],'group_id=([0-9]+)',0),'=')[1] from 資料庫.表A  limit 1;

官網的解釋如下,如果對於傳入什麼引數還不太明白的話,可以百度中文部落格,或者去看hive原始碼,看這個方法到底如何通過java程式碼來處理傳入的引數!(這裡不多加贅述,因為很好百度到)

方法二:自己寫自定義函式來解析(本人最不推薦的方法)

hive官網關於如何新增自定義函式:https://cwiki.apache.org/confluence/display/Hive/HivePlugins

具體如何操作可以看官網或者百度中文的帖子或者給我留言,我就不寫明,在這裡就單純做個簡單的闡述。

1、新增臨時函式,只有當前hive的連線有效(當然對於以後一直需要使用的自定義函式,使用這個明顯不合理)

2、新增非臨時函式(做法其實是將函式打成jar包,上傳到hdfs,讓每個hive客戶端連線的時候,載入這個jar包,但是大家不覺得多維護一個jar包是一件很麻煩的事情嗎?)

實在是不推薦這種方式,不到萬不得已千萬不要想著自己新增這新增那的,可能這個東西你自己維護,你沒覺得什麼,當下一個人維護你的程式的時候,就該罵人了!

方法三:使用hive自帶的解析url的函式(parse_url)

說實話,這也是一搜一大把的函式

並且官方也寫了例子出來,挺簡單的。但是這個函式還是有要求的,他要求url必須工整。

例如:我的表中的url格式如下

/wenzhang/v1/XXX/?fold=1&offset=0&group_id=6594293942836003076&tab_index=0&count=20&(後面還有一大堆雜七雜八的東西)

也就是說他沒有http://這個頭,對不起,這個函式解析不了,因此就必須把每個url加上一個http頭!

注意:不同資料庫的字串拼接會有些許差異,有的直接用"+",有的用"||"(greenplum),hive中使用"concat"這個函式

因此sql如下:

--第二個位置上的引數可以傳入:HOST, PATH, QUERY, REF, PROTOCOL, AUTHORITY, FILE, and USERINFO來獲取url的不同部分 
select parse_url(concat('http://',url), 'QUERY','group_id') from 資料庫.表A

我覺得這篇文章寫的還可以大家也可直接參考:https://www.cnblogs.com/itdyb/p/6236953.html(作者:波比12)

 

ok,所以我最後採用的是方法三,看起來效能也還行(當然我也沒有做具體的測試,我沒有選擇方法一的原因是,我擔心正則有時候可能會有些效率問題,就是慢),如果有各位大神實際測試過這兩種方法的速度,可以給我留言,讓我也記錄學習下,謝謝~

老話說一下,本人菜鳥一隻,如果有什麼說錯的地方還請大家批評指出!!我一定虛心學習!