2017-07-14 91 views
1

我們有一個Hive表,其中一個字符串列包含XML。爲了簡化,假設表是:使用Xpath將XML節點提取到Hive表中

DataTable 
key: string 
xml: string 

並且該XML的格式爲:

<xml> 
    <entity> 
     <property type="alpha">123</property> 
     <property type="beta">abc</property> 
     <property type="delta">...</property> 
    </entity> 
    <entity> 
     <property type="alpha">321</property> 
     <property type="beta">cba</property> 
     <property type="delta">---</property> 
    </entity> 
</xml> 

與0..N實體節點。

我想這個數據轉換爲具有以下格式的新蜂巢表:

TransformedTable 
key: string 
alpha: string 
beta: string 
delta: string 

,但我發現很難。我對Hive相當陌生,但我認爲像這樣的東西應該是正確的了。

下面的問題涉及:

,但沒有答案。而這個問題有一個相關的答案:

,但我不認爲我可以使用XML SERDE在這種情況下。通過這一研究,我已經試過這樣的事情:

select key, 
     xpath(xml, 'xml/entity/property[@type="alpha"]/text()')) as alpha, 
     xpath(xml, 'xml/entity/property[@type="beta"]/text()')) as beta, 
     xpath(xml, 'xml/entity/property[@type="delta"]/text()')) as delta 
    from DataTable 

,但導致這個:

key1 ["123", "321"] ["abc", "cba"] ["...", "---"] 
key2 ["123", "321"] ["abc", "cba"] ["...", "---"] 

什麼,而不是我真的想:

key1 123 abc ... 
key1 321 cba --- 
key2 123 abc ... 
key2 321 cba --- 

感謝花時間閱讀本文,我會很感激你可以給我的任何想法!

回答

0

基於數組的數據可以使用LATERAL VIEW結合表生成函數(如explode)「連接」成關係。在這種情況下的另一複雜情況是我們需要對應於alphabetadelta陣列的LATERAL VIEW的3個單獨事件,這在結果集中產生了完整的笛卡爾乘積的風險;每個alpha/beta/delta排列都會生成一個單獨的行。

爲了避免笛卡爾乘積,我們可以使用一個名爲posexplode的函數變體,它可以從原始數組中生成一個數字索引和數據值。然後,我們可以使用過濾條件來確保我們只查看與原始數組的位置匹配的行。

查詢

WITH DataTable AS (
    SELECT 'key1' AS key, '<xml><entity><property type="alpha">123</property><property type="beta">abc</property><property type="delta">...</property></entity><entity><property type="alpha">321</property><property type="beta">cba</property><property type="delta">---</property></entity></xml>' AS xml UNION ALL 
    SELECT 'key2' AS key, '<xml><entity><property type="alpha">123</property><property type="beta">abc</property><property type="delta">...</property></entity><entity><property type="alpha">321</property><property type="beta">cba</property><property type="delta">---</property></entity></xml>' AS xml 
) 
SELECT 
    key, 
    alpha, 
    beta, 
    delta 
FROM DataTable 
LATERAL VIEW posexplode(xpath(xml, 'xml/entity/property[@type="alpha"]/text()')) xml_alpha AS pos_alpha, alpha 
LATERAL VIEW posexplode(xpath(xml, 'xml/entity/property[@type="beta"]/text()')) xml_beta AS pos_beta, beta 
LATERAL VIEW posexplode(xpath(xml, 'xml/entity/property[@type="delta"]/text()')) xml_delta AS pos_delta, delta 
WHERE pos_alpha = pos_beta 
AND pos_beta = pos_delta 
; 

結果集

key alpha beta delta 
0 key1 123 abc ... 
1 key1 321 cba --- 
2 key2 123 abc ... 
3 key2 321 cba --- 

如果需要進一步的定製,那麼你可能會考慮寫自己的自定義UDTF恰好生成行,你需要他們。

+0

謝謝克里斯。你的答案既正確又有教育意義。非常有幫助!現在我努力嘗試以某種方式將OUTER視圖放在一起,因爲並非每個實體都具有(例如)「測試」屬性,並且在這種情況下,我希望在測試列中使用NULL。我會再玩一次,如果我不能弄明白,就發表一個不同的問題。再次感謝。 – Ckratide

+0

@Ckratide,很高興聽到這幫助!這聽起來像你可能正在一條需要更多定製邏輯的路上。我編輯了答案,說你可能想考慮編寫你自己的自定義UDTF。 https://cwiki.apache.org/confluence/display/Hive/DeveloperGuide+UDTF –